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')
Example #2
0
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.')
Example #4
0
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
Example #7
0
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)
Example #8
0
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)
Example #10
0
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
Example #11
0
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.')
Example #12
0
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')
Example #13
0
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'
Example #14
0
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))
Example #15
0
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!')
Example #16
0
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?')
Example #17
0
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)