Beispiel #1
0
 def _assert_success(self, response):
     if response.status_code != 200:
         logger.error(
             "Kubernetes API call failed with response: %s => %s",
             response.status_code,
             response.text,
         )
         raise CannotWriteConfigException("Kubernetes API call failed: %s" % response.text)
Beispiel #2
0
def _ensure_parent_dir(filepath):
    """ Ensures that the parent directory of the given file path exists. """
    try:
        parentpath = os.path.abspath(os.path.join(filepath, os.pardir))
        if not os.path.isdir(parentpath):
            os.makedirs(parentpath)
    except IOError as ioe:
        raise CannotWriteConfigException(str(ioe))
Beispiel #3
0
    def save_volume_file(self, flask_file, relative_file_path):
        filepath = os.path.join(self.config_volume, relative_file_path)
        _ensure_parent_dir(filepath)

        # Write the file.
        try:
            flask_file.save(filepath)
        except IOError as ioe:
            raise CannotWriteConfigException(str(ioe))

        return filepath
Beispiel #4
0
    def save_volume_file(self, flask_file, relative_file_path):
        # Write the file to a temp location.
        buf = StringIO()
        try:
            try:
                flask_file.save(buf)
            except IOError as ioe:
                raise CannotWriteConfigException(str(ioe))

            self._update_secret_file(relative_file_path, buf.getvalue())
        finally:
            buf.close()
Beispiel #5
0
 def remove_volume_file(self, relative_file_path):
     try:
         self._update_secret_file(relative_file_path, None)
     except IOError as ioe:
         raise CannotWriteConfigException(str(ioe))
Beispiel #6
0
    def _update_secret_file(self, relative_file_path, value=None):
        if '/' in relative_file_path:
            raise Exception(
                'Expected path from get_volume_path, but found slashes')

        # Check first that the namespace for Red Hat Quay exists. If it does not, report that
        # as an error, as it seems to be a common issue.
        namespace_url = 'namespaces/%s' % (QE_NAMESPACE)
        response = self._execute_k8s_api('GET', namespace_url)
        if response.status_code // 100 != 2:
            msg = 'A Kubernetes namespace with name `%s` must be created to save config' % QE_NAMESPACE
            raise CannotWriteConfigException(msg)

        # Check if the secret exists. If not, then we create an empty secret and then update the file
        # inside.
        secret_url = 'namespaces/%s/secrets/%s' % (QE_NAMESPACE,
                                                   QE_CONFIG_SECRET)
        secret = self._lookup_secret()
        if secret is None:
            self._assert_success(
                self._execute_k8s_api(
                    'POST', secret_url, {
                        "kind": "Secret",
                        "apiVersion": "v1",
                        "metadata": {
                            "name": QE_CONFIG_SECRET
                        },
                        "data": {}
                    }))

        # Update the secret to reflect the file change.
        secret['data'] = secret.get('data', {})

        if value is not None:
            secret['data'][relative_file_path] = base64.b64encode(value)
        else:
            secret['data'].pop(relative_file_path)

        self._assert_success(self._execute_k8s_api('PUT', secret_url, secret))

        # Wait until the local mounted copy of the secret has been updated, as
        # this is an eventual consistency operation, but the caller expects immediate
        # consistency.
        while True:
            matching_files = set()
            for secret_filename, encoded_value in secret['data'].iteritems():
                expected_value = base64.b64decode(encoded_value)
                try:
                    with self.get_volume_file(secret_filename) as f:
                        contents = f.read()

                    if contents == expected_value:
                        matching_files.add(secret_filename)
                except IOError:
                    continue

            if matching_files == set(secret['data'].keys()):
                break

            # Sleep for a second and then try again.
            time.sleep(1)