[feature] adding-pre-post-actions-to-yaml (#44)

* fix multiple release items
* remove old configs in kubernetes
* add skip flags
This commit is contained in:
Alexis Rivera DeLa Torre 2017-04-17 14:24:30 -05:00 committed by Alan Meadows
parent 6355fee383
commit e4f49e9f8a
7 changed files with 171 additions and 26 deletions

1
.gitignore vendored
View File

@ -87,3 +87,4 @@ ENV/
# Rope project settings # Rope project settings
.ropeproject .ropeproject

View File

@ -49,6 +49,8 @@ class Armada(object):
chart = dotify(entry['chart']) chart = dotify(entry['chart'])
values = entry['chart']['values'] values = entry['chart']['values']
pre_actions = {}
post_actions = {}
if chart.release_name is None: if chart.release_name is None:
continue continue
@ -61,16 +63,23 @@ class Armada(object):
protoc_chart = chartbuilder.get_helm_chart() protoc_chart = chartbuilder.get_helm_chart()
# determine install or upgrade by examining known releases # determine install or upgrade by examining known releases
LOG.debug("RELEASE: %s", chart.release_name)
if chart.release_name in [x[0] for x in known_releases]: if chart.release_name in [x[0] for x in known_releases]:
# indicate to the end user what path we are taking # indicate to the end user what path we are taking
LOG.info("Upgrading release %s", chart.release_name) LOG.info("Upgrading release %s", chart.release_name)
# extract the installed chart and installed values from the # extract the installed chart and installed values from the
# latest release so we can compare to the intended state # latest release so we can compare to the intended state
installed_chart, installed_values = self.find_release_chart( installed_chart, installed_values = self.find_release_chart(
known_releases, chart.release_name) known_releases, chart.release_name)
if not self.args.disable_update_pre:
pre_actions = getattr(chart.upgrade, 'pre', {})
if not self.args.disable_update_post:
post_actions = getattr(chart.upgrade, 'post', {})
# show delta for both the chart templates and the chart values # show delta for both the chart templates and the chart values
# TODO(alanmeadows) account for .files differences # TODO(alanmeadows) account for .files differences
# once we support those # once we support those
@ -85,7 +94,8 @@ class Armada(object):
# do actual update # do actual update
self.tiller.update_release(protoc_chart, self.args.dry_run, self.tiller.update_release(protoc_chart, self.args.dry_run,
chart.release_name, chart.release_name, chart.namespace,
pre_actions, post_actions,
disable_hooks=chart. disable_hooks=chart.
upgrade.no_hooks, upgrade.no_hooks,
values=yaml.safe_dump(values)) values=yaml.safe_dump(values))
@ -99,6 +109,15 @@ class Armada(object):
chart.namespace, chart.namespace,
prefix, prefix,
values=yaml.safe_dump(values)) values=yaml.safe_dump(values))
try:
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))
except Exception:
LOG.error("Install failed, continuing.")
LOG.debug("Cleaning up chart source in %s", LOG.debug("Cleaning up chart source in %s",
chartbuilder.source_directory) chartbuilder.source_directory)

View File

@ -135,7 +135,11 @@ class ChartBuilder(object):
for root, _, files in os.walk(os.path.join(self.source_directory, for root, _, files in os.walk(os.path.join(self.source_directory,
'templates'), topdown=True): 'templates'), topdown=True):
for tpl_file in files: for tpl_file in files:
templates.append(Template(name=tpl_file, tname = os.path.relpath(os.path.join(root, tpl_file),
os.path.join(self.source_directory,
'templates'))
templates.append(Template(name=tname,
data=open(os.path.join(root, data=open(os.path.join(root,
tpl_file), tpl_file),
'r').read())) 'r').read()))

View File

@ -1,4 +1,6 @@
from kubernetes import client, config from kubernetes import client, config
from kubernetes.client.rest import ApiException
from logutil import LOG
class K8s(object): class K8s(object):
''' '''
@ -10,3 +12,33 @@ class K8s(object):
''' '''
config.load_kube_config() config.load_kube_config()
self.client = client.CoreV1Api() self.client = client.CoreV1Api()
self.api_client = client.BatchV1Api()
def delete_job_action(self, name, namespace="default"):
'''
:params name - name of the job
:params namespace - name of pod that job
'''
try:
body = client.V1DeleteOptions()
self.api_client.delete_namespaced_job(name=name,
namespace=namespace,
body=body)
except ApiException as e:
LOG.error("Exception when deleting a job: %s", e)
def create_job_action(self, name, namespace="default"):
'''
:params name - name of the job
:params namespace - name of pod that job
'''
LOG.debug(" %s in namespace: %s", name, namespace)
def get_namespace_pod(self, namespace="default"):
'''
:params - namespace - pod namespace
This will return a list of objects req namespace
'''
res = self.client.list_namespaced_pod(namespace)
return res

View File

@ -3,12 +3,13 @@ from hapi.services.tiller_pb2 import ReleaseServiceStub, ListReleasesRequest, \
from hapi.chart.config_pb2 import Config from hapi.chart.config_pb2 import Config
import grpc import grpc
from logutil import LOG
from k8s import K8s from k8s import K8s
from logutil import LOG
TILLER_PORT = 44134 TILLER_PORT = 44134
TILLER_VERSION = b'2.1.3' TILLER_VERSION = b'2.1.3'
TILLER_TIMEOUT = 300 TILLER_TIMEOUT = 300
RELEASE_LIMIT = 64
class Tiller(object): class Tiller(object):
''' '''
@ -48,8 +49,7 @@ class Tiller(object):
''' '''
Search all namespaces for a pod beginning with tiller-deploy* Search all namespaces for a pod beginning with tiller-deploy*
''' '''
ret = self.k8s.client.list_pod_for_all_namespaces() for i in self.k8s.get_namespace_pod('kube-system').items:
for i in ret.items:
# TODO(alanmeadows): this is a bit loose # TODO(alanmeadows): this is a bit loose
if i.metadata.name.startswith('tiller-deploy'): if i.metadata.name.startswith('tiller-deploy'):
return i return i
@ -69,9 +69,14 @@ class Tiller(object):
''' '''
List Helm Releases List Helm Releases
''' '''
releases = []
stub = ReleaseServiceStub(self.channel) stub = ReleaseServiceStub(self.channel)
req = ListReleasesRequest() req = ListReleasesRequest(limit=RELEASE_LIMIT)
return stub.ListReleases(req, self.timeout, metadata=self.metadata) release_list = stub.ListReleases(req, self.timeout,
metadata=self.metadata)
for y in release_list:
releases.extend(y.releases)
return releases
def list_charts(self): def list_charts(self):
''' '''
@ -80,9 +85,8 @@ class Tiller(object):
Returns list of (name, version, chart, values) Returns list of (name, version, chart, values)
''' '''
charts = [] charts = []
for x in self.list_releases(): for latest_release in self.list_releases():
try: try:
latest_release = x.releases[-1]
charts.append((latest_release.name, latest_release.version, charts.append((latest_release.name, latest_release.version,
latest_release.chart, latest_release.chart,
latest_release.config.raw)) latest_release.config.raw))
@ -90,8 +94,49 @@ class Tiller(object):
continue continue
return charts return charts
def update_release(self, chart, dry_run, name, disable_hooks=False, def _pre_update_actions(self, actions, namespace):
values=None): '''
: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 update_release(self, chart, dry_run, name, namespace,
pre_actions=None, post_actions=None,
disable_hooks=False, values=None):
''' '''
Update a Helm Release Update a Helm Release
''' '''
@ -101,6 +146,8 @@ class Tiller(object):
else: else:
values = Config(raw=values) values = Config(raw=values)
self._pre_update_actions(pre_actions, namespace)
# build release install request # build release install request
stub = ReleaseServiceStub(self.channel) stub = ReleaseServiceStub(self.channel)
release_request = UpdateReleaseRequest( release_request = UpdateReleaseRequest(
@ -109,8 +156,11 @@ class Tiller(object):
disable_hooks=disable_hooks, disable_hooks=disable_hooks,
values=values, values=values,
name=name) name=name)
return stub.UpdateRelease(release_request, self.timeout,
metadata=self.metadata) stub.UpdateRelease(release_request, self.timeout,
metadata=self.metadata)
self._post_update_actions(post_actions, namespace)
def install_release(self, chart, dry_run, name, namespace, prefix, def install_release(self, chart, dry_run, name, namespace, prefix,
values=None): values=None):

View File

@ -11,9 +11,9 @@ armada:
charts: charts:
# silent dependency # silent dependency
- chart: &common - chart: &helm-toolkit
name: common name: helm-toolkit
release_name: null release_name: null
namespace: null namespace: null
values: {} values: {}
@ -23,19 +23,53 @@ armada:
subpath: helm-toolkit subpath: helm-toolkit
reference: master reference: master
dependencies: [] dependencies: []
- chart: &keystone - chart: &mariadb
name: keystone name: mariadb
release_name: keystone release_name: mariadb
namespace: openstack namespace: openstack
install: install:
no_hooks: false no_hooks: false
upgrade: upgrade:
no_hooks: false no_hooks: false
pre: pre:
delete: delete: []
- Job/keystone-db-sync create: []
- Job/keystone-db-init post:
delete: []
create: []
values:
endpoints: *endpoints
source:
type: git
location: git://github.com/att-comdev/openstack-helm
subpath: mariadb
reference: master
dependencies:
- *helm-toolkit
- chart: &keystone
name: keystone
release_name: keystone
namespace: openstack
install:
no_hooks: false
upgrade:
no_hooks: false
pre:
delete:
- name: keystone-db-sync
type: job
- name: keystone-db-init
type: job
create:
- name: keystone-db-sync
type: job
- name: keystone-db-init
type: job
post:
delete: []
create: []
values: values:
endpoints: *endpoints endpoints: *endpoints
source: source:
@ -44,4 +78,4 @@ armada:
subpath: keystone subpath: keystone
reference: master reference: master
dependencies: dependencies:
- *common - *helm-toolkit

View File

@ -19,6 +19,11 @@ def parse_args():
ap.add_argument('-d', '--dry-run', action='store_true', default=False, ap.add_argument('-d', '--dry-run', action='store_true', default=False,
required=False, help='Enable dry-run flag on all Tiller' required=False, help='Enable dry-run flag on all Tiller'
'Calls') 'Calls')
ap.add_argument('--disable-update-pre', action='store_true', default=False,
required=False, help='Disable pre update actions')
ap.add_argument('--disable-update-post', action='store_true',
default=False, required=False,
help='Disable post update actions')
return ap.parse_args() return ap.parse_args()