def get_state(ctx, **kwargs):

    ctx.logger.info("initializing {0} cloud driver"
                    .format(Provider.CLOUDSTACK))
    cloud_driver = get_cloud_driver(ctx)

    instance_id = ctx.instance.runtime_properties[CLOUDSTACK_ID_PROPERTY]
    networking_type = ctx.instance.runtime_properties[
        NETWORKINGTYPE_CLOUDSTACK_TYPE]

    node = get_vm_by_id(ctx, cloud_driver, instance_id)
    if node is None:
        return False

    if networking_type == 'network':

        if ctx.node.properties['management_network_name']:

            ctx.logger.info('Management network defined: {0}'
                            .format(ctx.node.properties[
                                    'management_network_name']))

            mgt_net = get_network(cloud_driver, ctx.node.properties[
                'management_network_name'])

            nic = get_nic_by_node_and_network_id(ctx, cloud_driver, node,
                                                 mgt_net.id)

            ctx.logger.info('CFY will use {0} for management,'
                            ' overwriting previously set value'
                            .format(nic))

            ctx.instance.runtime_properties[IP_PROPERTY] = nic.ip_address

            return True

        else:

            ctx.instance.runtime_properties[IP_PROPERTY] = node.private_ips[0]

            ctx.logger.info('VM {1} started successfully with IP {0}'
                            .format(ctx.instance.runtime_properties[
                                    IP_PROPERTY],
                                    ctx.instance.runtime_properties[
                                        CLOUDSTACK_NAME_PROPERTY]))
            return True

    elif networking_type == 'security_group':
        ctx.runtime.properties[IP_PROPERTY] = node.public_ips[0]
        ctx.logger.info('instance started successfully with IP {0}'
                        .format(ctx.instance.runtime_properties[IP_PROPERTY]))
        return True

    else:
        ctx.instance.runtime_properties[IP_PROPERTY] = node.private_ips[0]
        ctx.logger.info('Cannot determine networking type,'
                        ' using private_ip as {0} ip'
                        .format(ctx.instance.runtime_properties[IP_PROPERTY]))
        return True
def get_state(ctx, **kwargs):

    ctx.logger.info("initializing {0} cloud driver"
                    .format(Provider.CLOUDSTACK))
    cloud_driver = get_cloud_driver(ctx)

    instance_id = ctx.instance.runtime_properties[CLOUDSTACK_ID_PROPERTY]
    networking_type = ctx.instance.runtime_properties[
        NETWORKINGTYPE_CLOUDSTACK_TYPE]

    node = get_vm_by_id(ctx, cloud_driver, instance_id)
    if node is None:
        return False

    if networking_type == 'network':

        if ctx.node.properties['management_network_name']:

            ctx.logger.info('Management network defined: {0}'
                            .format(ctx.node.properties[
                            'management_network_name']))

            mgt_net = get_network(cloud_driver, ctx.node.properties[
                'management_network_name'])

            nic = get_nic_by_node_and_network_id(ctx, cloud_driver, node,
                                                 mgt_net.id)

            ctx.logger.info('CFY will use {0} for management,'
                            ' overwriting previously set value'
                            .format(nic))

            ctx.instance.runtime_properties[IP_PROPERTY] = nic.ip_address

            return True

        else:

            ctx.instance.runtime_properties[IP_PROPERTY] = node.private_ips[0]

            ctx.logger.info('VM {1} started successfully with IP {0}'
                            .format(ctx.instance.runtime_properties[IP_PROPERTY],
                                    ctx.instance.runtime_properties[
                                        CLOUDSTACK_NAME_PROPERTY]))
            return True

    elif networking_type == 'security_group':
        ctx.runtime.properties[IP_PROPERTY] = node.public_ips[0]
        ctx.logger.info('instance started successfully with IP {0}'
                        .format(ctx.instance.runtime_properties[IP_PROPERTY]))
        return True

    else:
        ctx.instance.runtime_properties[IP_PROPERTY] = node.private_ips[0]
        ctx.logger.info('Cannot determine networking type,'
                        ' using private_ip as {0} ip'
                        .format(ctx.instance.runtime_properties[IP_PROPERTY]))
        return True
def _create_in_network(ctx,
                       cloud_driver,
                       name,
                       image,
                       size,
                       keypair_name,
                       network_ids,
                       default_network,
                       ip_address=None,
                       location=None):

    network_list = cloud_driver.ex_list_networks()

    # Set default network as first network in the list
    nets = [get_network(cloud_driver, default_network)]
    nets.extend([net for net in network_list if net.id in network_ids])

    # Remove duplicates this results in non-default networks e.g. without
    # default gateway
    seen_nets = set()
    dedup_nets = []
    for obj in nets:

        if obj.id not in seen_nets:
            dedup_nets.append(obj)
            seen_nets.add(obj.id)

    for i in range(len(dedup_nets)):
        if i == 0:
            ctx.logger.info('Adding VM with default_network: {0}'.format(
                dedup_nets[i].name))
        else:
            ctx.logger.info('Adding VM to additional network: {0}'.format(
                dedup_nets[i].name))

    try:
        node = cloud_driver.create_node(name=name,
                                        image=image,
                                        size=size,
                                        ex_keyname=keypair_name,
                                        ex_displayname=name,
                                        networks=dedup_nets,
                                        ex_ip_address=ip_address,
                                        ex_start_vm=False,
                                        location=location)
    except Exception as e:
        raise NonRecoverableError('VM creation failed: {0}'.format(str(e)))

    ctx.logger.info('VM: {0} was created successfully'.format(node.name))

    ctx.instance.runtime_properties[CLOUDSTACK_ID_PROPERTY] = node.id
    ctx.instance.runtime_properties[CLOUDSTACK_TYPE_PROPERTY] = \
        SERVER_CLOUDSTACK_TYPE
    ctx.instance.runtime_properties[NETWORKINGTYPE_CLOUDSTACK_TYPE] = 'network'
    ctx.instance.runtime_properties[CLOUDSTACK_NAME_PROPERTY] = node.name
def _create_in_network(ctx, cloud_driver, name, image, size, keypair_name,
                       network_ids, default_network, ip_address=None,
                       location=None):

    network_list = cloud_driver.ex_list_networks()

    # Set default network as first network in the list
    nets = [get_network(cloud_driver, default_network)]
    nets.extend([net for net in network_list if net.id in network_ids])

    # Remove duplicates this results in non-default networks e.g. without
    # default gateway
    seen_nets = set()
    dedup_nets = []
    for obj in nets:

        if obj.id not in seen_nets:
            dedup_nets.append(obj)
            seen_nets.add(obj.id)

    for i in range(len(dedup_nets)):
        if i == 0:
            ctx.logger.info('Adding VM with default_network: {0}'
                            .format(dedup_nets[i].name))
        else:
            ctx.logger.info('Adding VM to additional network: {0}'
                            .format(dedup_nets[i].name))

    try:
        node = cloud_driver.create_node(name=name,
                                        image=image,
                                        size=size,
                                        ex_keyname=keypair_name,
                                        ex_displayname=name,
                                        networks=dedup_nets,
                                        ex_ip_address=ip_address,
                                        ex_start_vm=False,
                                        location=location)
    except Exception as e:
        raise NonRecoverableError('VM creation failed: {0}'.format(str(e)))

    ctx.logger.info(
        'VM: {0} was created successfully'.format(
            node.name))

    ctx.instance.runtime_properties[CLOUDSTACK_ID_PROPERTY] = node.id
    ctx.instance.runtime_properties[CLOUDSTACK_TYPE_PROPERTY] = \
        SERVER_CLOUDSTACK_TYPE
    ctx.instance.runtime_properties[NETWORKINGTYPE_CLOUDSTACK_TYPE] = 'network'
    ctx.instance.runtime_properties[CLOUDSTACK_NAME_PROPERTY] = node.name
def connect_floating_ip(ctx, **kwargs):

    cloud_driver = get_cloud_driver(ctx)
    # network_ids = get_cloudstack_ids_of_connected_nodes_by_cloudstack_type(
    #     ctx, NETWORK_CLOUDSTACK_TYPE)

    network_config = ctx.source.node.properties['network']
    default_network_config = network_config['default_network']

    default_net = get_network(cloud_driver, default_network_config)

    ctx.logger.debug('reading portmap configuration.')
    portmaps = ctx.source.node.properties['portmaps']

    if not portmaps:
        raise NonRecoverableError('Relation defined but no portmaps set'
                                  ' either remove relation or'
                                  ' define the portmaps')

    server_id = ctx.source.instance.runtime_properties[CLOUDSTACK_ID_PROPERTY]
    floating_ip_id = ctx.target.instance.runtime_properties[
        CLOUDSTACK_ID_PROPERTY]

    # TODO Needs more elegant solution, problem only seen on VPC with CS4.3
    # TODO Should be fixed in Cloudstack
    ctx.logger.info('Sleeping for 15 secs so router can stabilize, '
                    'so we wont have to wait for ARP timeouts '
                    'when reusing public IPs')
    sleep(15)

    for portmap in portmaps:

        protocol = portmap.get(['protocol'][0], None)
        pub_port = portmap.get(['public_port'][0], None)
        pub_end_port = portmap.get(['public_end_port'][0], None)
        priv_port = portmap.get(['private_port'][0], None)
        priv_end_port = portmap.get(['private_end_port'][0], None)

        #If not specified assume closed
        open_fw = portmap.get(['open_firewall'][0], False)

        if pub_port is None:
            raise NonRecoverableError('Please specify the public_port')
        elif pub_end_port is None:
            pub_end_port = pub_port

        if priv_port is None:
            raise NonRecoverableError('Please specify the private_port')
        elif priv_end_port is None:
            priv_end_port = priv_port

        if protocol is None:
            raise NonRecoverableError('Please specify the protocol TCP or UDP')

        node = get_vm_by_id(ctx, cloud_driver, server_id)
        public_ip = get_public_ip_by_id(ctx, cloud_driver, floating_ip_id)

        try:
            ctx.logger.info('Creating portmap for node: {0}:{1}-{2} on'
                            ' {3}:{4}-{5}'.
                            format(node.name, priv_port, priv_end_port,
                                   public_ip.address, pub_port, pub_end_port))

            cloud_driver.ex_create_port_forwarding_rule(node=node,
                                                        address=public_ip,
                                                        protocol=protocol,
                                                        public_port=pub_port,
                                                        public_end_port=
                                                        pub_end_port,
                                                        private_port=priv_port,
                                                        private_end_port=
                                                        priv_end_port,
                                                        openfirewall=open_fw,
                                                        network_id=
                                                        default_net.id)
        except Exception as e:
            ctx.logger.warn('Port forward creation failed: '
                            '{0}'.format(str(e)))
            return False

    return True
def connect_floating_ip(ctx, **kwargs):

    cloud_driver = get_cloud_driver(ctx)

    network_config = ctx.source.node.properties['network']
    default_network_config = network_config['default_network']

    default_net = get_network(cloud_driver, default_network_config)

    ctx.logger.debug('reading portmap configuration.')
    portmaps = ctx.source.node.properties['portmaps']

    if not portmaps:
        raise NonRecoverableError('Relation defined but no portmaps set'
                                  ' either remove relation or'
                                  ' define the portmaps')

    server_id = ctx.source.instance.runtime_properties[CLOUDSTACK_ID_PROPERTY]
    floating_ip_id = ctx.target.instance.runtime_properties[
        CLOUDSTACK_ID_PROPERTY]

    # TODO Needs more elegant solution, problem only seen on VPC with CS4.3
    # TODO Should be fixed in Cloudstack
    ctx.logger.info('Sleeping for 15 secs so router can stabilize, '
                    'so we wont have to wait for ARP timeouts '
                    'when reusing public IPs')
    sleep(15)

    for portmap in portmaps:

        protocol = portmap.get(['protocol'][0], None)
        pub_port = portmap.get(['public_port'][0], None)
        pub_end_port = portmap.get(['public_end_port'][0], None)
        priv_port = portmap.get(['private_port'][0], None)
        priv_end_port = portmap.get(['private_end_port'][0], None)

        # If not specified assume closed
        open_fw = portmap.get(['open_firewall'][0], False)

        if pub_port is None:
            raise NonRecoverableError('Please specify the public_port')
        elif pub_end_port is None:
            pub_end_port = pub_port

        if priv_port is None:
            raise NonRecoverableError('Please specify the private_port')
        elif priv_end_port is None:
            priv_end_port = priv_port

        if protocol is None:
            raise NonRecoverableError('Please specify the protocol TCP or UDP')

        node = get_vm_by_id(ctx, cloud_driver, server_id)
        public_ip = get_public_ip_by_id(ctx, cloud_driver, floating_ip_id)

        try:
            ctx.logger.info('Creating portmap for node: {0}:{1}-{2} on'
                            ' {3}:{4}-{5}'.
                            format(node.name, priv_port, priv_end_port,
                                   public_ip.address, pub_port, pub_end_port))

            cloud_driver.ex_create_port_forwarding_rule(
                node=node,
                address=public_ip,
                protocol=protocol,
                public_port=pub_port,
                public_end_port=pub_end_port,
                private_port=priv_port,
                private_end_port=priv_end_port,
                openfirewall=open_fw,
                network_id=default_net.id)
        except Exception as e:
            ctx.logger.warn('Port forward creation failed: '
                            '{0}'.format(str(e)))
            return False

    return True