def get_vars(self, obj): if not obj: return merged_vars = copy.deepcopy(obj.vars) for var_secret in obj.var_secrets: secret_name = var_secret.get('name', None) secret_namespace = var_secret.get('namespace', None) if secret_name: try: secret_data = self.get_secret_data(secret_name, secret_namespace) var_name = var_secret.get('var', None) if var_name: deep_update(merged_vars, {var_name: secret_data}) else: deep_update(merged_vars, secret_data) except kubernetes.client.rest.ApiException as e: if e.status != 404: raise operator_logger.warning( 'varSecrets references missing secret, %s', secret_name) else: operator_logger.warning('varSecrets has entry with no name') return merged_vars
def patch(self, patch, runtime): ''' Patch AnarchySubject resource and status. ''' resource_patch = {} result = None if 'metadata' in patch or 'spec' in patch: if 'metadata' in patch: resource_patch['metadata'] = patch['metadata'] if 'spec' in patch: resource_patch['spec'] = patch['spec'] deep_update(self.spec, patch['spec']) if patch.get('skip_update_processing', False): # Set spec-sha256 annotation to indicate skip processing if 'metadata' not in resource_patch: resource_patch['metadata'] = {} if 'annotations' not in resource_patch['metadata']: resource_patch['metadata']['annotations'] = {} resource_patch['metadata']['annotations'][ runtime.operator_domain + '/spec-sha256'] = self.spec_sha256 result = runtime.custom_objects_api.patch_namespaced_custom_object( runtime.operator_domain, runtime.api_version, runtime.operator_namespace, 'anarchysubjects', self.name, resource_patch) if 'status' in patch: result = runtime.custom_objects_api.patch_namespaced_custom_object_status( runtime.operator_domain, runtime.api_version, runtime.operator_namespace, 'anarchysubjects', self.name, {'status': patch['status']}) return result
def manage_runner_pods(self, runtime): ''' Manage Pods for AnarchyRunner ''' #deployment_name = 'anarchy-runner-' + self.name #deployment_namespace = self.pod_namespace or runtime.operator_namespace pod_template = copy.deepcopy(self.pod_template) if 'metadata' not in pod_template: pod_template['metadata'] = {} if 'labels' not in pod_template['metadata']: pod_template['metadata']['labels'] = {} if 'spec' not in pod_template: pod_template['spec'] = {} if 'serviceAccountName' not in pod_template['spec']: pod_template['spec'][ 'serviceAccountName'] = self.service_account_name(runtime) if not 'containers' in pod_template['spec']: pod_template['spec']['containers'] = [{}] pod_template['metadata']['generateName'] = '{}-runner-{}-'.format( runtime.anarchy_service_name, self.name) pod_template['metadata']['labels'][runtime.runner_label] = self.name pod_template['metadata']['ownerReferences'] = [{ 'apiVersion': runtime.api_group_version, 'controller': True, 'kind': 'AnarchyRunner', 'name': self.name, 'uid': self.uid, }] runner_container = pod_template['spec']['containers'][0] if 'name' not in runner_container: runner_container['name'] = 'runner' if not runner_container.get('image'): image = os.environ.get('RUNNER_IMAGE', '') if image != '': runner_container['image'] = image else: runner_container['image'] = runtime.pod.spec.containers[ 0].image if not 'env' in runner_container: runner_container['env'] = [] runner_container['env'].extend([{ 'name': 'ANARCHY_COMPONENT', 'value': 'runner' }, { 'name': 'ANARCHY_URL', 'value': 'http://{}.{}.svc:5000'.format(runtime.anarchy_service_name, runtime.operator_namespace) }, { 'name': 'ANARCHY_DOMAIN', 'value': runtime.operator_domain }, { 'name': 'POD_NAME', 'valueFrom': { 'fieldRef': { 'apiVersion': 'v1', 'fieldPath': 'metadata.name' } } }, { 'name': 'RUNNER_NAME', 'value': self.name }, { 'name': 'RUNNER_TOKEN', 'value': self.runner_token }]) pod_count = 0 for name, pod in self.pods.items(): pod_dict = runtime.api_client.sanitize_for_serialization(pod) if pod.metadata.labels.get( runtime.runner_terminating_label) == 'true': # Ignore pod marked for termination pass elif pod_dict == deep_update(copy.deepcopy(pod_dict), pod_template): pod_count += 1 else: # Pod does not match template, need to terminate pod runtime.core_v1_api.patch_namespaced_pod( pod.metadata.name, pod.metadata.namespace, { 'metadata': { 'labels': { runtime.runner_terminating_label: 'true' } } }) operator_logger.info( 'Labeled AnarchyRunner %s runner pod %s for termination', self.name, pod.metadata.name) for i in range(self.min_replicas - pod_count): pod = None while pod == None: try: pod = runtime.core_v1_api.create_namespaced_pod( runtime.operator_namespace, pod_template) break except kubernetes.client.rest.ApiException as e: if 'retry after the token is automatically created' in json.loads( e.body).get('message', ''): time.sleep(1) else: raise operator_logger.info("Started runner pod %s for AnarchyRunner %s", pod.metadata.name, self.name)
def manage_runner_deployment(self, runtime): """Manage Deployment for AnarchyRunner pods""" self.manage_runner_service_account(runtime) deployment_name = 'anarchy-runner-' + self.name deployment_namespace = self.pod_namespace or runtime.operator_namespace deployment_definition = { 'apiVersion': 'apps/v1', 'kind': 'Deployment', 'metadata': { 'name': deployment_name, 'namespace': deployment_namespace, 'labels': { runtime.runner_label: self.name } }, 'spec': { 'selector': { 'matchLabels': { runtime.runner_label: self.name } }, 'template': { 'metadata': { 'labels': { runtime.runner_label: self.name } }, 'spec': { 'serviceAccountName': self.service_account_name, 'containers': [{ 'name': 'runner', 'env': [{ 'name': 'ANARCHY_URL', 'value': 'http://{}.{}.svc:5000'.format( runtime.anarchy_service, runtime.operator_namespace) }, { 'name': 'OPERATOR_DOMAIN', 'value': runtime.operator_domain }, { 'name': 'POD_NAME', 'valueFrom': { 'fieldRef': { 'apiVersion': 'v1', 'fieldPath': 'metadata.name' } } }, { 'name': 'RUNNER_NAME', 'value': self.name }, { 'name': 'RUNNER_TOKEN', 'value': self.runner_token }], 'image': self.image, 'imagePullPolicy': self.image_pull_policy, 'resources': self.resources }] } } } } deployment = None try: deployment = runtime.custom_objects_api.get_namespaced_custom_object( 'apps', 'v1', deployment_namespace, 'deployments', deployment_name) except kubernetes.client.rest.ApiException as e: if e.status != 404: raise if deployment: updated_deployment = copy.deepcopy(deployment) deep_update(updated_deployment, deployment_definition) if updated_deployment['spec']['replicas'] < self.min_replicas: updated_deployment['spec']['replicas'] = self.min_replicas if updated_deployment['spec']['replicas'] > self.max_replicas: updated_deployment['spec']['replicas'] = self.max_replicas # FIXME - Scale based on queue size if deployment != updated_deployment: runtime.custom_objects_api.replace_namespaced_custom_object( 'apps', 'v1', deployment_namespace, 'deployments', deployment_name, updated_deployment) else: deployment_definition['spec']['replicas'] = self.min_replicas runtime.custom_objects_api.create_namespaced_custom_object( 'apps', 'v1', deployment_namespace, 'deployments', deployment_definition)