community/front-end/ofe/website/ghpcfe/views/view_utils.py (70 lines of code) (raw):
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Common helpers used in multiple views"""
from pathlib import Path
from django.http import HttpResponseNotFound, FileResponse
from django.views import generic
from ..cluster_manager import cloud_info
import logging
logger = logging.getLogger(__name__)
class LocalFile:
"""Local file access helper"""
def __init__(self, filename):
self.filename = Path(filename)
def get_file(self):
return self.filename
def open(self):
return self.get_file().open("rb")
def exists(self):
return self.get_file().exists()
def get_filename(self):
return self.get_file().name
class TerraformLogFile(LocalFile):
"""Terraform log file helper"""
def __init__(self, prefix):
self.prefix = Path(prefix)
super().__init__("terraform.log")
def set_prefix(self, prefix):
self.prefix = Path(prefix)
def get_file(self):
for phase in ["destroy", "apply", "plan", "init"]:
tf_log = self.prefix / f"terraform_{phase}_log.stderr"
if (not tf_log.exists()) or tf_log.stat().st_size == 0:
tf_log = self.prefix / f"terraform_{phase}_log.stdout"
if tf_log.exists():
break
if tf_log.exists():
logger.info("Found terraform log file %s", tf_log.as_posix())
else:
logger.warning("Found no terraform log files")
return tf_log
def get_filename(self):
return "terraform.log"
class GCSFile:
"""GCS file access helper"""
def __init__(self, bucket, basepath, prefix):
self.bucket = bucket
self.basepath = basepath
self.prefix = prefix
def get_path(self):
return "/".join([self.prefix, self.basepath])
def exists(self):
return cloud_info.gcs_get_blob(self.bucket, self.get_path()).exists()
def open(self):
logger.debug(
"Attempting to open gs://%s%s", self.bucket, self.get_path()
)
return cloud_info.gcs_get_blob(self.bucket, self.get_path()).open(
mode="rb", chunk_size=4096
)
def get_filename(self):
return self.basepath.split("/")[-1]
class StreamingFileView(generic.base.View):
"""View for a file that is being updated"""
def get(self, request, *args, **kwargs):
try:
file_info = self.get_file_info()
if file_info.exists():
return FileResponse(
file_info.open(),
filename=file_info.get_filename(),
as_attachment=False,
content_type="text/plain",
)
return HttpResponseNotFound("Log file does not exist")
# Not a lot we can do, regardless of error type, so just report back
except Exception as err: # pylint: disable=broad-except
logger.warning("Exception trying to stream file", exc_info=err)
return HttpResponseNotFound("Log file not found")