def source_clone(self): ''' Clone the charts source We only support a git source type right now, which can also handle git:// local paths as well ''' if self.chart.source.type == 'git': tmpdir = tempfile.mkdtemp(prefix='armada', dir='/tmp') self._source_tmp_dir = tmpdir if self.parent: LOG.info("Cloning %s/%s as dependency for %s", self.chart.source.location, self.chart.source.subpath, self.parent) else: LOG.info("Cloning %s/%s for release %s", self.chart.source.location, self.chart.source.subpath, self.chart.release_name) pygit2.clone_repository(self.chart.source.location, tmpdir) return os.path.join(tmpdir, self.chart.source.subpath) else: LOG.exception("Unknown source type %s for chart %s", self.chart.name, self.chart.source.type)
def show_diff(self, chart, installed_chart, installed_values, target_chart, target_values): ''' Produce a unified diff of the installed chart vs our intention TODO(alanmeadows): This needs to be rewritten to produce better unified diff output and avoid the use of print ''' chart_diff = list( difflib.unified_diff( installed_chart.SerializeToString().split('\n'), target_chart.split('\n'))) if len(chart_diff) > 0: LOG.info("Chart Unified Diff (%s)", chart.release_name) for line in chart_diff: LOG.debug(line) values_diff = list( difflib.unified_diff(installed_values.split('\n'), yaml.safe_dump(target_values).split('\n'))) if len(values_diff) > 0: LOG.info("Values Unified Diff (%s)", chart.release_name) for line in values_diff: LOG.debug(line) return (len(chart_diff) > 0) or (len(values_diff) > 0)
def get_helm_chart(self): ''' Return a helm chart object ''' if self._helm_chart: return self._helm_chart # dependencies # [process_chart(x, is_dependency=True) for x in chart.dependencies] dependencies = [] for chart in self.chart.dependencies: LOG.info("Building dependency chart %s for release %s", chart.name, self.chart.release_name) dependencies.append(ChartBuilder(chart).get_helm_chart()) helm_chart = Chart( metadata=self.get_metadata(), templates=self.get_templates(), dependencies=dependencies, values=self.get_values(), files=self.get_files(), ) self._helm_chart = helm_chart return helm_chart
def source_clone(self): ''' Clone the charts source We only support a git source type right now, which can also handle git:// local paths as well ''' if self.chart.source.type == 'git': if self.parent: LOG.info("Cloning %s/%s as dependency for %s", self.chart.source.location, self.chart.source.subpath, self.parent) else: LOG.info("Cloning %s/%s for release %s", self.chart.source.location, self.chart.source.subpath, self.chart.release_name) self._source_tmp_dir = git_clone(self.chart.source.location, self.chart.source.reference) return os.path.join(self._source_tmp_dir, self.chart.source.subpath) else: LOG.exception("Unknown source type %s for chart %s", self.chart.name, self.chart.source.type)
def _pre_update_actions(self, actions, namespace): ''' :params actions - array of items actions :params namespace - name of pod for actions ''' try: for action in actions.get('delete', []): name = action.get("name") action_type = action.get("type") if "job" in action_type: LOG.info("Deleting %s in namespace: %s", name, namespace) self.k8s.delete_job_action(name, namespace) continue LOG.error("Unable to execute name: %s type: %s ", name, type) except Exception: LOG.debug("PRE: Could not delete anything, please check yaml") try: for action in actions.get('create', []): name = action.get("name") action_type = action.get("type") if "job" in action_type: LOG.info("Creating %s in namespace: %s", name, namespace) self.k8s.create_job_action(name, action_type) continue except Exception: LOG.debug("PRE: Could not create anything, please check yaml")
def _post_update_actions(self, actions, namespace): try: for action in actions.get('create', []): name = action.get("name") action_type = action.get("type") if "job" in action_type: LOG.info("Creating %s in namespace: %s", name, namespace) self.k8s.create_job_action(name, action_type) continue except Exception: LOG.debug("POST: Could not create anything, please check yaml")
def sync(self): ''' Syncronize Helm with the Armada Config(s) ''' def release_prefix(prefix, chart): ''' how to attach prefix to chart ''' return "{}-{}".format(prefix, chart) # extract known charts on tiller right now known_releases = self.tiller.list_charts() prefix = self.config.get('armada').get('release_prefix') for release in known_releases: LOG.debug("Release %s, Version %s found on tiller", release[0], release[1]) for entry in self.config['armada']['charts']: chart = dotify(entry['chart']) values = entry['chart']['values'] pre_actions = {} post_actions = {} if chart.release_name is None: continue # initialize helm chart and request a # protoc helm chart object which will # pull the sources down and walk the # dependencies chartbuilder = ChartBuilder(chart) protoc_chart = chartbuilder.get_helm_chart() # determine install or upgrade by examining known releases LOG.debug("RELEASE: %s", chart.release_name) if release_prefix(prefix, chart.release_name) in [ x[0] for x in known_releases ]: # indicate to the end user what path we are taking LOG.info("Upgrading release %s", chart.release_name) # extract the installed chart and installed values from the # latest release so we can compare to the intended state installed_chart, installed_values = self.find_release_chart( known_releases, release_prefix(prefix, chart.release_name)) if not self.disable_update_pre: pre_actions = getattr(chart.upgrade, 'pre', {}) if not self.disable_update_post: post_actions = getattr(chart.upgrade, 'post', {}) # show delta for both the chart templates and the chart values # TODO(alanmeadows) account for .files differences # once we support those upgrade_diff = self.show_diff(chart, installed_chart, installed_values, chartbuilder.dump(), values) if not upgrade_diff: LOG.info("There are no updates found in this chart") continue # do actual update self.tiller.update_release( protoc_chart, self.dry_run, chart.release_name, chart.namespace, prefix, pre_actions, post_actions, disable_hooks=chart.upgrade.no_hooks, values=yaml.safe_dump(values)) # process install else: LOG.info("Installing release %s", chart.release_name) self.tiller.install_release(protoc_chart, self.dry_run, chart.release_name, chart.namespace, prefix, values=yaml.safe_dump(values)) LOG.debug("Cleaning up chart source in %s", chartbuilder.source_directory) chartbuilder.source_cleanup() if self.enable_chart_cleanup: self.tiller.chart_cleanup(prefix, self.config['armada']['charts'])
def sync(self): ''' Syncronize Helm with the Armada Config(s) ''' # extract known charts on tiller right now known_releases = self.tiller.list_charts() for release in known_releases: LOG.debug("Release %s, Version %s found on tiller", release[0], release[1]) for entry in self.config['armada']['charts']: chart = dotify(entry['chart']) values = entry['chart']['values'] if chart.release_name is None: continue # initialize helm chart and request a # protoc helm chart object which will # pull the sources down and walk the # dependencies chartbuilder = ChartBuilder(chart) protoc_chart = chartbuilder.get_helm_chart() # determine install or upgrade by examining known releases if chart.release_name in [x[0] for x in known_releases]: # indicate to the end user what path we are taking LOG.info("Upgrading release %s", chart.release_name) # extract the installed chart and installed values from the # latest release so we can compare to the intended state installed_chart, installed_values = self.find_release_chart( known_releases, chart.release_name) # show delta for both the chart templates and the chart values # TODO(alanmeadows) account for .files differences # once we support those self.show_diff(chart, installed_chart, installed_values, chartbuilder.dump(), values) # do actual update self.tiller.update_release( protoc_chart, self.args.dry_run, chart.release_name, disable_hooks=chart.upgrade.no_hooks, values=yaml.safe_dump(values)) # process install else: LOG.info("Installing release %s", chart.release_name) self.tiller.install_release(protoc_chart, self.args.dry_run, chart.release_name, chart.namespace, values=yaml.safe_dump(values)) LOG.debug("Cleaning up chart source in %s", chartbuilder.source_directory) chartbuilder.source_cleanup()