def start(**_): try: connection.MistConnectionClient().machine.start() except Exception as exc: ctx.logger.error("Failed to start machine. Already running?") if ctx.node.properties.get("monitoring"): connection.MistConnectionClient().machine.enable_monitoring() ctx.logger.info('Monitoring enabled')
def create(**kwargs): """Creates a keypair.""" conn = connection.MistConnectionClient() if _create_external_keypair(): return key_pair_name = get_resource_id() ctx.instance.runtime_properties["key"] = key_pair_name ctx.instance.runtime_properties["mist_type"] = "keypair" kp = conn.client.keys(search=key_pair_name) if len(kp): kp = kp[0] return # if key already in mist.io, skip else: key_pair_name = ctx.node.properties[ "key_name"] # commented out in plugin? private = conn.client.generate_key() conn.client.add_key(key_name=key_pair_name, private=private) conn.client.update_keys() kp = conn.client.keys(search=key_pair_name)[0] _save_key_pair(kp)
def delete(**_): if not ctx.node.properties['use_external_resource']: try: connection.MistConnectionClient().machine.destroy() except Exception as exc: raise Exception(exc) else: ctx.logger.info('use_external_resource flag is true, cannot delete.')
def delete(**_): try: network_id = ctx.instance.runtime_properties["info"]["id"] conn = connection.MistConnectionClient() cloud = conn.get_cloud(ctx.node.properties["parameters"]["cloud_id"]) cloud.delete_network(network_id) except Exception as exc: raise Exception(exc)
def stop(**_): try: conn = connection.MistConnectionClient() machine = conn.get_machine( cloud_id=ctx.instance.runtime_properties['cloud_id'], machine_id=ctx.instance.runtime_properties['machine_id']) machine.stop() except Exception as exc: ctx.logger.error('Failed to stop machine. %s', exc)
def create(**kwargs): stack_name = utils.get_stack_name() node_type = kwargs.get('node_type', 'instance') mist_client = connection.MistConnectionClient() try: client = mist_client.client except: raise NonRecoverableError('User authentication failed') params = ctx.node.properties['parameters'] cloud_id = params.get('cloud_id') cloud = client.clouds(id=cloud_id)[0] if ctx.node.properties['use_external_resource']: machine = mist_client.machine ctx.instance.runtime_properties['mist_type'] = 'machine' ctx.instance.runtime_properties['info'] = machine.info public_ips = machine.info.get('public_ips', []) if public_ips: ctx.instance.runtime_properties['ip'] = public_ips[0] ctx.instance.runtime_properties['networks'] = public_ips return try: params.pop('cloud_id') name = params.pop('name', '') or utils.generate_name(stack_name, node_type) key = params.pop('key') image_id = params.pop('image_id') location_id = params.pop('location_id') size_id = params.pop('size_id') job = cloud.create_machine(name, key, image_id, location_id, size_id, async=True, fire_and_forget=False, **params) for log in job['logs']: if log['action'] == 'machine_creation_finished' and log[ 'machine_name'] == name: ctx.instance.runtime_properties[ 'machine_id'] = log['machine_id'] break except Exception as exc: raise NonRecoverableError(exc) machine_id = ctx.instance.runtime_properties[ 'machine_id'] or ctx.node.properties['resource_id'] cloud.update_machines() machine = cloud.machines(id=machine_id)[0] ctx.instance.runtime_properties['cloud_id'] = cloud_id ctx.instance.runtime_properties['mist_type'] = 'machine' ctx.instance.runtime_properties['info'] = machine.info public_ips = machine.info.get('public_ips', []) # Filter out IPv6 addresses public_ips = filter(lambda ip: ':' not in ip, public_ips) if public_ips: ctx.instance.runtime_properties['ip'] = public_ips[0] ctx.instance.runtime_properties['networks'] = public_ips
def create(**_): params = ctx.node.properties['parameters'] conn = connection.MistConnectionClient() cloud = conn.get_cloud(params.pop('cloud_id')) try: network = cloud.create_network(**params) ctx.instance.runtime_properties["info"] = network except Exception as exc: raise Exception(exc)
def create(**_): params = ctx.node.properties['parameters'] cloud = connection.MistConnectionClient().cloud del params["cloud_id"] try: network = cloud.create_network(**params) ctx.instance.runtime_properties["info"] = network except Exception as exc: raise Exception(exc)
def run_script(**kwargs): client = connection.MistConnectionClient().client machine = connection.MistConnectionClient().machine kwargs['cloud_id'] = machine.cloud.id kwargs['machine_id'] = str(machine.id) script_params = kwargs.pop("params", "") kwargs.pop('ctx', None) if kwargs.get("script_id", ''): try: job_id = client.run_script(**kwargs) except Exception as exc: raise NonRecoverableError(exc) else: try: response = client.add_and_run_script(machine.cloud.id, script_params=script_params, fire_and_forget=False, **kwargs) except Exception as exc: raise NonRecoverableError(exc)
def _get_key_pair_by_id(key_pair_id): """Returns the key pair object for a given key pair id. :param key_pair_id: The ID of a keypair. :returns The mist keypair object. :raises NonRecoverableError: If Mist finds no matching key pairs. """ conn = connection.MistConnectionClient() key_pairs = conn.client.keys(search=key_pair_id) return key_pairs[0] if key_pairs else None
def delete(**_): if not ctx.instance.runtime_properties.get('use_external_resource'): try: conn = connection.MistConnectionClient() machine = conn.get_machine( cloud_id=ctx.instance.runtime_properties['cloud_id'], machine_id=ctx.instance.runtime_properties['machine_id']) machine.destroy() except Exception as exc: ctx.logger.error('Failed to destroy machine. %s', exc) else: ctx.logger.info('use_external_resource flag is true, cannot delete.')
def delete(**kwargs): """Deletes a keypair.""" conn = connection.MistConnectionClient() key_pair_name = get_external_resource_id_or_raise('delete key pair') if _delete_external_keypair(): return if key_pair_name: try: conn.client.keys(search=key_pair_name)[0].delete() except Exception as exc: raise NonRecoverableError('{0}'.format(str(exc))) unassign_runtime_property_from_resource('mist_resource_id') _delete_key_file() ctx.logger.info('Deleted key pair: {0}'.format(key_pair_name)) else: ctx.logger.info('Not deleting key pair from account')
def create_machine(properties, skip_post_deploy_validation=False, **kwargs): """Create a machine with the given parameters by invoking the MistClient The `properties` must include all parameters required for the machine's creation. These parameters are supposed to be populated mainly by the blueprint's inputs. In the simplest scenario, `properties` should be equal to `ctx.node.properties`. But, they can also be modified before passed into this method. Similarly, `kwargs` correspond to a specific operation's inputs and they should be used likewise, even if this method is not invoked directly by the blueprint's lifecycle operation, but rather from another method, such as user-defined workflow. """ stack_name = utils.get_stack_name() node_type = kwargs.get('node_type', 'instance') conn = connection.MistConnectionClient() # The job_id associated with the current workflow. job_id = conn.job_id params = properties['parameters'] if utils.is_resource_external(properties): cloud_id = get_cloud_id(properties) machine_id = get_machine_id(properties) cloud = conn.get_cloud(cloud_id) ctx.instance.runtime_properties['machine_id'] = str(machine_id) ctx.instance.runtime_properties['use_external_resource'] = True else: # Get the cloud on which to provision the new machines. cloud_id = params.pop('cloud_id') cloud = conn.get_cloud(cloud_id) # Ensure no machine_id is provided upon machine creation. params.pop('machine_id', None) # Provision new machine. try: name = ( params.pop('name', '') or # Get or auto-generate. utils.generate_name(stack_name, node_type)) key = params.pop('key_id') or '' # Avoid None. size_id = params.pop('size_id') image_id = params.pop('image_id') location_id = params.pop('location_id') job = cloud.create_machine(name, key, image_id, location_id, size_id, async=True, **params) except Exception as exc: raise NonRecoverableError(exc) # Wait for machine creation to finish. event = utils.wait_for_event(job_id=job['job_id'], job_kwargs={ 'action': 'machine_creation_finished', 'machine_name': name }, timeout=600) ctx.instance.runtime_properties['machine_id'] = event['machine_id'] ctx.instance.runtime_properties['use_external_resource'] = False # Wait for machine's post-deploy configuration to finish. if key and not skip_post_deploy_validation: event = utils.wait_for_event(job_id=job['job_id'], job_kwargs={ 'action': 'post_deploy_finished', 'machine_id': event['machine_id'], }) # Update the node instance's runtime properties. machine_id = ctx.instance.runtime_properties['machine_id'] machine = conn.get_machine(cloud_id, machine_id) ctx.instance.runtime_properties['job_id'] = job_id ctx.instance.runtime_properties['machine_name'] = machine.name ctx.instance.runtime_properties['info'] = machine.info ctx.instance.runtime_properties['cloud_id'] = cloud_id ctx.instance.runtime_properties['mist_type'] = 'machine'
def creation_validation(**_): """ This checks that all user supplied info is valid """ ctx.logger.info('Checking validity of info') mist_client = connection.MistConnectionClient() try: client = mist_client.client except: raise NonRecoverableError('Credentials failed') for property_key in constants.INSTANCE_REQUIRED_PROPERTIES: if property_key not in ctx.node.properties: raise NonRecoverableError( '{0} is a required input. Unable to create.'.format( property_key)) cloud = client.clouds(id=ctx.node.properties['cloud_id']) if not len(cloud): raise NonRecoverableError('{0} cloud was not found.'.format( ctx.node.properties['cloud_id'])) image = "" for im in cloud[0].images: if im[id] == ctx.node.properties['image_id']: image = im break if not image: raise NonRecoverableError('image_id {0} not found.'.format( ctx.node.properties['image_id'])) size = "" for si in cloud[0].sizes: if si[id] == ctx.node.properties['size_id']: size = si break if not size: raise NonRecoverableError('size_id {0} not found.'.format( ctx.node.properties['size_id'])) location = "" for lo in cloud[0].locations: if lo[id] == ctx.node.properties['location_id']: location = lo break if not location: raise NonRecoverableError('location_id {0} not found.'.format( ctx.node.properties['location_id'])) # FIXME this should not always raise a NonRecoverableError machine_name = ctx.node.properties.get('name', '') if machine_name: machines = cloud[0].machines(search=machine_name) if ctx.node.properties['use_external_resource'] and not len(machines): raise NonRecoverableError( 'Machine {0} not found.'.format(machine_name)) if not ctx.node.properties['use_external_resource'] and len(machines): raise NonRecoverableError( 'Machine {0} exists.'.format(machine_name)) if ctx.node.properties['use_external_resource'] and len(machines): if machines[0].info["state"] == "running": pass elif machines[0].info["state"] == "stopped": try: machines[0].start() except: pass delay = 0 while True: time.sleep(10) cloud[0].update_machines() if cloud[0].machines( search=machine_name)[0].info["state"] == "running": break elif delay == 5: raise NonRecoverableError( 'Machine {0} in stopped state.'.format( machine_name)) delay += 1 else: raise NonRecoverableError( 'Machine {0} error state.'.format(machine_name))
def scale_cluster_down(quantity): master = workctx.get_node('kube_master') # Get node directly from local-storage in order to have access to all of # its runtime_properties master_node = LocalStorage.get('kube_master') # Public IP of the Kubernetes Master used to remove nodes from the cluster master_ip = master_node.runtime_properties['server_ip'] username = master_node.runtime_properties['auth_user'] password = master_node.runtime_properties['auth_pass'] # TODO deprecate this! / mist_client = connection.MistConnectionClient(properties=master.properties) cloud = mist_client.cloud # / deprecate worker_name = inputs.get('worker_name') if not worker_name: raise NonRecoverableError('Kubernetes Worker\'s name is missing') machines = cloud.machines(search=worker_name) if not machines: workctx.logger.warn( 'Cannot find node \'%s\'. Already removed? ' 'Exiting...', worker_name) return workctx.logger.info('Terminating %d Kubernetes Worker(s)...', len(machines)) counter = 0 # Get all nodes via the kubernetes API. This will give us access to all # nodes' metadata. If the master node does not expose a publicly accessible # IP address, then the connection will fail. In that case, we won't be # able to retrieve and verify the list of nodes in order to remove them # from the cluster. try: url = 'https://%s:%s@%s' % (username, password, master_ip) nodes = requests.get('%s/api/v1/nodes' % url, verify=False) except Exception as exc: if netaddr.IPAddress(master_ip).is_private(): raise NonRecoverableError( 'Cannot connect to the kubernetes master to automatically ' 'remove nodes from the cluster. It seems like the kubernetes ' 'master listens at a private IP address. You can manually ' 'remove nodes by destroying them or by simply disassociating ' 'them from the kubernetes cluster. For instance, the current ' 'node can be removed from the cluster by issuing an HTTP ' 'DELETE request at https://%s:%s@%s/api/v1/nodes/%s from the ' 'same network' % (username, password, master_ip, worker_name)) raise NonRecoverableError('Connection to master failed: %s', exc) if not nodes.ok: raise NonRecoverableError('Got %s: %s', nodes.status_code, nodes.text) nodes = nodes.json() # If any of the machines specified, match a kubernetes node, then # we attempt to remove the node from the cluster and destroy it. for m in machines: for node in nodes['items']: labels = node['metadata']['labels'] if labels['kubernetes.io/hostname'] == m.name: if 'node-role.kubernetes.io/master' in labels.iterkeys(): raise NonRecoverableError('Cannot remove master') break else: workctx.logger.error('%s does not match a kubernetes node', m) continue workctx.logger.info('Removing %s from cluster', m) api = node['metadata']['selfLink'] resp = requests.delete('%s%s' % (url, api), verify=False) if not resp.ok: workctx.logger.error('Bad response from kubernetes: %s', resp.text) workctx.logger.info('Destroying machine') m.destroy() # FIXME Why? counter += 1 if counter == quantity: break workctx.logger.info('Downscaling the kubernetes cluster completed!')
def stop(**_): try: connection.MistConnectionClient().machine.stop() ctx.logger.info('Machine stopped') except Exception as exc: ctx.logger.error('Failed to stop machine. Is \'stop\' supported?')
def delete(**_): try: network_id = ctx.instance.runtime_properties["info"]["id"] connection.MistConnectionClient().cloud.delete_network(network_id) except Exception as exc: raise Exception(exc)