Skip to content

Commit

Permalink
Merge pull request #197 from Mirantis/jenkinsdelete
Browse files Browse the repository at this point in the history
Jenkins deprovision
  • Loading branch information
tomkukral authored Jan 12, 2018
2 parents 429b3df + 6f8df26 commit 52f962a
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 35 deletions.
11 changes: 9 additions & 2 deletions kqueen/config/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ class Config(BaseConfig):

# Jenkins engine settings
JENKINS_API_URL = 'https://ci.mcp.mirantis.net'
JENKINS_PROVISION_JOB_NAME = 'deploy-aws-k8s_ha_calico_sm'
JENKINS_PROVISION_JOB_NAME = 'deploy_aws_k8s_kqueen_job'
JENKINS_PROVISION_JOB_CTX = {}
JENKINS_ANCHOR_PARAMETER = 'STACK_NAME'
JENKINS_DEPROVISION_JOB_NAME = 'deploy-stack-cleanup'
JENKINS_DEPROVISION_JOB_CTX = {
'STACK_TYPE': 'aws'
}
JENKINS_PARAMETER_MAP = {
'cluster_name': 'STACK_NAME',
'cluster_uuid': 'KQUEEN_BUILD_ID'
}
JENKINS_USERNAME = None
JENKINS_PASSWORD = None
11 changes: 9 additions & 2 deletions kqueen/config/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@ class Config(BaseConfig):

# Jenkins engine settings
JENKINS_API_URL = 'https://ci.mcp.mirantis.net'
JENKINS_PROVISION_JOB_NAME = 'deploy-aws-k8s_ha_calico_sm'
JENKINS_PROVISION_JOB_NAME = 'deploy_aws_k8s_kqueen_job'
JENKINS_PROVISION_JOB_CTX = {}
JENKINS_ANCHOR_PARAMETER = 'STACK_NAME'
JENKINS_DEPROVISION_JOB_NAME = 'deploy-stack-cleanup'
JENKINS_DEPROVISION_JOB_CTX = {
'STACK_TYPE': 'aws'
}
JENKINS_PARAMETER_MAP = {
'cluster_name': 'STACK_NAME',
'cluster_uuid': 'KQUEEN_BUILD_ID'
}
JENKINS_USERNAME = None
JENKINS_PASSWORD = None
79 changes: 48 additions & 31 deletions kqueen/engines/jenkins.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class JenkinsEngine(BaseEngine):
username = config.get('JENKINS_USERNAME')
password = config.get('JENKINS_PASSWORD')
provision_job_name = config.get('JENKINS_PROVISION_JOB_NAME')
anchor_parameter = config.get('JENKINS_ANCHOR_PARAMETER')
deprovision_job_name = config.get('JENKINS_DEPROVISION_JOB_NAME')
job_parameter_map = config.get('JENKINS_PARAMETER_MAP')
parameter_schema = {
'provisioner': {
'username': {
Expand Down Expand Up @@ -107,15 +108,17 @@ def provision(self, **kwargs):
"""
Implementation of :func:`~kqueen.engines.base.BaseEngine.provision`
"""
cluster_id = self.cluster.id
ctx = config.get('JENKINS_PROVISION_JOB_CTX')
# PATCH THE CTX TO CONTAIN ANCHOR WITH OBJ UUID
ctx['STACK_NAME'] = 'KQUEEN__{}'.format(cluster_id)
cluster_name = self.job_parameter_map['cluster_name']
cluster_uuid = self.job_parameter_map['cluster_uuid']
# PATCH THE CTX TO CONTAIN CLUSTER NAME AND UUID
ctx[cluster_name] = self.cluster.name
ctx[cluster_uuid] = self.cluster.id
try:
self.client.build_job(self.provision_job_name, ctx)
return True, None
except Exception as e:
msg = 'Creating cluster {} failed with following reason: {}'.format(cluster_id, repr(e))
msg = 'Creating cluster {} failed with following reason: {}'.format(self.cluster.id, repr(e))
logger.error(msg)
return False, msg
return None, None
Expand All @@ -126,20 +129,29 @@ def deprovision(self, **kwargs):
Implementation of :func:`~kqueen.engines.base.BaseEngine.deprovision`
"""

return True, None
ctx = config.get('JENKINS_DEPROVISION_JOB_CTX')
cluster_name = self.job_parameter_map['cluster_name']
ctx[cluster_name] = self.cluster.name
try:
self.client.build_job(self.deprovision_job_name, ctx)
return True, None
except Exception as e:
msg = 'Creating cluster {} failed with following reason: {}'.format(self.cluster.id, repr(e))
logger.error(msg)
return False, msg
return None, None

def get_kubeconfig(self):
"""
Implementation of :func:`~kqueen.engines.base.BaseEngine.get_kubeconfig`
"""
cluster_external_id = self._get_external_id()
if not cluster_external_id:
cluster_build_number = self._get_build_number()
if not cluster_build_number:
return {}
kubeconfig_url = '{jenkins_url}/job/{job_name}/{build_id}/artifact/kubeconfig'.format(
jenkins_url=self.jenkins_url,
job_name=self.provision_job_name,
build_id=str(cluster_external_id),
build_id=str(cluster_build_number),
)
kubeconfig = {}
try:
Expand All @@ -148,62 +160,62 @@ def get_kubeconfig(self):
logger.error(repr(e))
return kubeconfig

def _get_external_id(self):
def _get_build_number(self):
"""
Get external ID of cluster, in this case Jenkins job ID.
First we try to get external_id from related object metadata, if there is no external_id
First we try to get build_number from related object metadata, if there is no build_number
yet, we need to look it up in build history of our configured provisioning Jenkins job
Returns:
int: Jenkins job ID
"""
metadata = self.cluster.metadata or {}
external_id = metadata.get('external_id', None)
if external_id:
return external_id
build_number = metadata.get('build_number', None)
if build_number:
return build_number
try:
cluster = self._get_by_id()
external_id = cluster['metadata']['external_id']
build_number = cluster['metadata']['build_number']
# Get fresh data just in case to avoid conflict
metadata = self.cluster.metadata or {}
metadata['external_id'] = external_id
metadata['build_number'] = build_number
self.cluster.metadata = metadata
self.cluster.save()
return external_id
return build_number
except Exception:
pass
return external_id
return build_number

def _get_by_id(self):
cluster_id = self.cluster.id
_list = self.cluster_list()
cluster = [c for c in _list if c['id'] == cluster_id]
return cluster[0] if cluster else {}

def _get_by_external_id(self):
cluster_external_id = self._get_external_id()
# Cannot get by external_id if there is no external_id on self.cluster
if not cluster_external_id:
def _get_by_build_number(self):
cluster_build_number = self._get_build_number()
# Cannot get by build_number if there is no build_number on self.cluster
if not cluster_build_number:
return {}
# Try to get the data from cache
cluster_cache_key = 'cluster-{}-{}'.format(self.name, cluster_external_id)
cluster_cache_key = 'cluster-{}-{}'.format(self.name, cluster_build_number)
cluster = cache.get(cluster_cache_key)
if cluster:
return cluster
# Get build info for the given job ID (external_id)
build = self.client.get_build_info(self.provision_job_name, int(cluster_external_id))
# Get build info for the given job ID (build_number)
build = self.client.get_build_info(self.provision_job_name, int(cluster_build_number))
cluster = self._get_cluster_from_build(build)
return cluster or {}

def cluster_get(self):
"""
Implementation of :func:`~kqueen.engines.base.BaseEngine.cluster_get`
First we try to get cluster by external_id, because its much more efficient in this
First we try to get cluster by build_number, because its much more efficient in this
implementation. If its not possible yet, we return from the slower method
"""
cluster = self._get_by_external_id()
cluster = self._get_by_build_number()
if cluster:
return cluster
return self._get_by_id()
Expand All @@ -225,9 +237,10 @@ def _get_cluster_from_build(self, build):
stack_name = build['description'].split(' ')[0]

# Try to determine cluster_id
cluster_uuid_parameter = self.job_parameter_map['cluster_uuid']
_cluster_id = [p.get('value', '') for p in parameters
if p.get('name', '') == 'STACK_NAME' and p.get('value', '').startswith('KQUEEN')]
cluster_id = _cluster_id[0].split('__')[1] if _cluster_id else None
if p.get('name', '') == cluster_uuid_parameter]
cluster_id = _cluster_id[0] if _cluster_id else None

# Try to determine cluster state
if build['result']:
Expand All @@ -245,7 +258,7 @@ def _get_cluster_from_build(self, build):
'id': cluster_id,
'state': state,
'metadata': {
'external_id': build['number'],
'build_number': build['number'],
'build_timestamp': build['timestamp'],
'build_estimated_duration': build['estimatedDuration']
}
Expand Down Expand Up @@ -288,10 +301,14 @@ def get_progress(self):
start = cluster['metadata']['build_timestamp']
estimate = cluster['metadata']['build_estimated_duration']
progress = int(((now - start) / estimate) * 100)
if estimate == -1:
raise ArithmeticError
if progress > 99:
progress = 99
else:
progress = 100
except ArithmeticError:
raise NotImplementedError
except Exception:
response = 500
return {'response': response, 'progress': progress, 'result': result}

0 comments on commit 52f962a

Please sign in to comment.