Esempio n. 1
0
    def setUp(self):
        super(CreateVmTests, self).setUp()

        flavor_name = "m1.tiny"
        network_name = "private"

        self.nova_client = client.nova_client()
        self.neutron_client = client.neutron_client()

        self.new_vm_name = str(uuid.uuid4())
        self.new_vm_id = None

        image_list = self.nova_client.images.list()
        for image in image_list:
            if (image.name.startswith("cirros")) and (
                    image.name.endswith("kernel")):
                break
        self.valid_image = image

        self.valid_flavor = self.nova_client.flavors.find(name=flavor_name)

        network_list = self.neutron_client.list_networks(name=network_name)
        self.valid_network = network_list['networks'][0]

        self.flow = linear_flow.Flow("create vm flow")
        self.flow.add(
            create_vm.CreateVm(os_client=self.nova_client,
                               requires=('name', 'image', 'flavor', 'nics'),
                               provides='new_vm',
                               rebind={'name': 'vm_name'}))
Esempio n. 2
0
    def setUp(self):
        super(GetVmTests, self).setUp()

        flavor_name = "m1.tiny"

        self.nova_client = client.nova_client()

        self.valid_vm_name = str(uuid.uuid4())

        image_list = self.nova_client.images.list()
        for image in image_list:
            if (image.name.startswith("cirros")) and (
                    image.name.endswith("kernel")):
                break
        valid_image = image

        valid_flavor = self.nova_client.flavors.find(name=flavor_name)
        new_vm = self.nova_client.servers.create(name=self.valid_vm_name,
                                                 image=valid_image,
                                                 flavor=valid_flavor)
        self.valid_vm_id = new_vm.id

        self.flow = linear_flow.Flow("create vm flow")
        self.flow.add(
            get_vm.GetVm(os_client=self.nova_client,
                         requires=('server', ),
                         provides=('vm_info')))
Esempio n. 3
0
    def setUp(self):
        super(GetVmStatusTests, self).setUp()

        image_name = "cirros-0.3.2-x86_64-uec-kernel"
        flavor_name = "m1.tiny"

        # retrieve nova client API class
        self.nova_client = client.nova_client()

        self.image = self.nova_client.images.find(name=image_name)
        self.flavor = self.nova_client.flavors.find(name=flavor_name)
Esempio n. 4
0
def delete_cluster(cluster_id, node_ids, group_id):
    """Delete Cluster flow factory function

    This factory function uses :func:`cue.taskflow.flow.delete_cluster_node` to
    delete a multi node cluster.

    :param cluster_id: A unique ID assigned to the cluster being deleted
    :type cluster_id: string
    :param node_ids: The Cue Node id's associated with each node in the cluster
    :type node_ids: list of uuid's
    :param group_id: The group id associated with the cluster
    :type group_id: uuid
    :return: A flow instance that represents the workflow for deleting a
             cluster
    """
    cluster_name = "cue[%s]" % cluster_id
    flow = linear_flow.Flow("deleting cluster %s" % cluster_id)
    sub_flow = unordered_flow.Flow("delete VMs")
    start_flow_status = {
        'cluster_id': cluster_id,
        'cluster_values': {
            'status': models.Status.DELETING
        }
    }
    end_flow_status = {
        'cluster_id': cluster_id,
        'cluster_values': {
            'status': models.Status.DELETED,
            'deleted': True
        }
    }

    #todo(dagnello): verify node_ids is a list and not a string
    for i, node_id in enumerate(node_ids):
        sub_flow.add(
            delete_cluster_node.delete_cluster_node(cluster_id, i, node_id))

    flow.add(
        cue_tasks.UpdateClusterRecord(name="update cluster status start "
                                      "%s" % cluster_name,
                                      inject=start_flow_status))
    if group_id is not None:
        flow.add(
            nova.DeleteVmGroup(name="delete nova user group %s %s" %
                               (group_id, cluster_name),
                               os_client=client.nova_client(),
                               inject={'group': group_id}))
    flow.add(sub_flow)
    flow.add(
        cue_tasks.UpdateClusterRecord(name="update cluster status end "
                                      "%s" % cluster_name,
                                      inject=end_flow_status))

    return flow
Esempio n. 5
0
    def setUp(self):
        super(CreateVmGroupTests, self).setUp()

        self.nova_client = client.nova_client()

        self.new_vm_group_name = str(uuid.uuid4())
        self.new_vm_group_id = None

        self.flow = linear_flow.Flow("create vm group flow")
        self.flow.add(
            create_vm_group.CreateVmGroup(os_client=self.nova_client,
                                          requires=('name', 'policies'),
                                          provides='new_vm_group',
                                          rebind={'name': 'vm_group_name'}))
Esempio n. 6
0
    def setUp(self):
        super(DeleteVmTests, self).setUp()
        # retrieve nova client API class
        self.nova_client = client.nova_client()

        # create flow with "DeleteVm" task
        self.flow = linear_flow.Flow('create port').add(
            delete_vm.DeleteVm(os_client=self.nova_client))

        image_list = self.nova_client.images.list()
        for image in image_list:
            if (image.name.startswith("cirros")) and (
                    image.name.endswith("kernel")):
                break
        self.valid_image = image

        self.flavor = self.nova_client.flavors.find(name="m1.tiny")
Esempio n. 7
0
    def _validate_flavor(self, image_id, cluster_flavor):
        """Checks if flavor satisfies minimum requirement of image metadata.

        :param image_id: image id of the broker.
        :param cluster_flavor: flavor id of the cluster.
        :raises: exception.ConfigurationError
        :raises: exception.InternalServerError
        :raises: exception.Invalid
        """
        nova_client = client.nova_client()

        # get image metadata
        try:
            image_metadata = nova_client.images.get(image_id)
            image_minRam = image_metadata.minRam
            image_minDisk = image_metadata.minDisk
        except nova_exc.ClientException as ex:
            if ex.http_status == 404:
                raise exception.ConfigurationError(
                    _('Invalid image %s '
                      'configured') % image_id)
            else:
                raise exception.InternalServerError

        # get flavor metadata
        try:
            flavor_metadata = nova_client.flavors.get(cluster_flavor)
            flavor_ram = flavor_metadata.ram
            flavor_disk = flavor_metadata.disk
        except nova_exc.ClientException as ex:
            if ex.http_status == 404:
                raise exception.Invalid(
                    _('Invalid flavor %s provided') % cluster_flavor)
            else:
                raise exception.InternalServerError

        # validate flavor with broker image metadata
        if (flavor_disk < image_minDisk):
            raise exception.Invalid(
                _("Flavor disk is smaller than the "
                  "minimum %s required for broker") % image_minDisk)
        elif (flavor_ram < image_minRam):
            raise exception.Invalid(
                _("Flavor ram is smaller than the "
                  "minimum %s required for broker") % image_minRam)
Esempio n. 8
0
    def setUp(self):

        super(DeleteClusterTests, self).setUp()

        flavor_name = "m1.tiny"
        network_name = "private"
        management_network_name = "cue_management_net"

        self.nova_client = client.nova_client()
        self.neutron_client = client.neutron_client()
        self.port = '5672'

        self.new_vm_name = str(uuid.uuid4())
        self.new_vm_list = []

        image_list = self.nova_client.images.list()
        for image in image_list:
            if (image.name.startswith("cirros")) and (
                    image.name.endswith("kernel")):
                break
        self.valid_image = image

        self.valid_flavor = self.nova_client.flavors.find(name=flavor_name)

        network_list = self.neutron_client.list_networks(name=network_name)
        self.valid_network = network_list['networks'][0]

        network_list = self.neutron_client.list_networks(
            name=management_network_name)
        self.management_network = network_list['networks'][0]

        # Todo(Dan) If testing becomes asynchronous, then there is no guarantee
        # that these urllib return results will come in the proper order.  Will
        # have to update the urllib2 fixture to respond appropriately for the
        # url passed in.
        urllib2_fixture.Urllib2ResultDetails.set_urllib2_result(
            ['{"status": "ok"}',
             '[{"name": "/"}]',
             '{"status": "ok"}',
             '[{"name": "/"}]',
             '{"status": "ok"}',
             '[{"name": "/"}]']
        )
Esempio n. 9
0
    def test_get_vm_status_flow(self):
        """Verifies GetVmStatusTask in a successful retry flow

        This test simulates creating a new VM, then directly running a flow
        with the 'CheckFor' task which will fail until vm_status acquired from
        GetVmStatus task returns 'ACTIVE'.  The new VM will return 'BUILDING'
        for the first three times the VM is acquired, then will return
        'ACTIVE'
        """
        # configure custom vm_status list
        nova.VmStatusDetails.set_vm_status(
            ['ACTIVE', 'BUILD', 'BUILD', 'BUILD'])

        # create flow with "GetVmStatus" task
        self.flow = linear_flow.Flow(
            'wait for vm to become active', retry=retry.Times(10)).add(
                get_vm_status.GetVmStatus(os_client=client.nova_client(),
                                          provides='vm_status'),
                common_task.CheckFor(rebind={'check_var': 'vm_status'},
                                     check_value='ACTIVE',
                                     retry_delay_seconds=1),
            )

        # create a vm
        new_instance = self.nova_client.servers.create(name="vm1",
                                                       image=self.image,
                                                       flavor=self.flavor)

        # set vm_id variable in TaskFlow's data store required for task
        GetVmStatusTests.task_store['nova_vm_id'] = new_instance.id

        # start engine to run task
        result = engines.run(self.flow, store=GetVmStatusTests.task_store)

        # verify vm_status key is in BUILD state
        self.assertEqual('ACTIVE', result['vm_status'],
                         "Invalid status received")

        # cleanup
        self.nova_client.servers.delete(new_instance)
Esempio n. 10
0
    def test_get_vm_status_flow_timeout(self):
        """Verifies GetVmStatusTask in an unsuccessful retry flow

        This test simulates creating a new VM which does not build
        successively and results in an 'ERROR' state.  The flow will reach
        the maximum retry times and raise an 'AssertionError' for the expected
        failure.
        """
        # configure custom vm_status list
        nova.VmStatusDetails.set_vm_status(
            ['BUILD', 'BUILD', 'BUILD', 'BUILD', 'BUILD', 'ERROR', 'ERROR'])

        # create flow with "GetVmStatus" task
        self.flow = linear_flow.Flow(
            'wait for vm to become active', retry=retry.Times(5)).add(
                get_vm_status.GetVmStatus(os_client=client.nova_client(),
                                          provides='vm_status'),
                common_task.CheckFor(rebind={'check_var': 'vm_status'},
                                     check_value='ACTIVE',
                                     retry_delay_seconds=1),
            )

        # create a vm
        new_instance = self.nova_client.servers.create(name="vm1",
                                                       image=self.image,
                                                       flavor=self.flavor)

        # set vm_id variable in TaskFlow's data store required for task
        GetVmStatusTests.task_store['nova_vm_id'] = new_instance.id

        # start engine to run task and verify AssertRaises exception
        self.assertRaises(AssertionError,
                          engines.run,
                          self.flow,
                          store=GetVmStatusTests.task_store)

        # cleanup
        self.nova_client.servers.delete(new_instance)
Esempio n. 11
0
    def setUp(self):
        super(GetVmInterfacesTests, self).setUp()

        flavor_name = "m1.tiny"

        self.nova_client = client.nova_client()
        self.neutron_client = client.neutron_client()

        self.valid_vm_name = str(uuid.uuid4())

        image_list = self.nova_client.images.list()
        for image in image_list:
            if (image.name.startswith("cirros")) and (
                    image.name.endswith("kernel")):
                break
        valid_image = image

        valid_flavor = self.nova_client.flavors.find(name=flavor_name)

        network_name = "private"
        networks = self.neutron_client.list_networks(name=network_name)
        network = networks['networks'][0]
        self.valid_net_id = network['id']
        nics = [{'net-id': self.valid_net_id}]

        new_vm = self.nova_client.servers.create(name=self.valid_vm_name,
                                                 image=valid_image,
                                                 flavor=valid_flavor,
                                                 nics=nics)
        self.valid_vm_id = new_vm.id

        self.flow = linear_flow.Flow("create vm flow")
        self.flow.add(
            list_vm_interfaces.ListVmInterfaces(os_client=self.nova_client,
                                                requires=('server', ),
                                                provides=('interface_list')))
Esempio n. 12
0
def create_cluster(cluster_id, node_ids, user_network_id,
                   management_network_id):
    """Create Cluster flow factory function

    This factory function uses :func:`cue.taskflow.flow.create_cluster_node` to
    create a multi node cluster.

    :param cluster_id: A unique ID assigned to the cluster being created
    :type cluster_id: string
    :param node_ids: The Cue Node id's associated with each node in the cluster
    :type node_ids: list of uuid strings
    :param user_network_id: The user's network id
    :type user_network_id: string
    :param management_network_id: The management network id
    :type management_network_id: string
    :return: A flow instance that represents the workflow for creating a
             cluster
    """
    cluster_name = "cue[%s]" % cluster_id
    flow = graph_flow.Flow("creating cluster %s" % cluster_id)
    start_flow_cluster_update = {
        'cluster_id': cluster_id,
        'cluster_values': {'status': models.Status.BUILDING}}

    extract_scheduler_hints = lambda vm_group: {'group': str(vm_group['id'])}
    end_flow_cluster_update = lambda vm_group: {
        'status': models.Status.ACTIVE,
        'group_id': str(vm_group['id'])}

    create_cluster_start_task = cue_tasks.UpdateClusterRecord(
        name="update cluster status start %s" % cluster_name,
        inject=start_flow_cluster_update)
    flow.add(create_cluster_start_task)

    cluster_anti_affinity = cfg.CONF.taskflow.cluster_node_anti_affinity
    if cluster_anti_affinity:
        create_vm_group = nova.CreateVmGroup(
            name="create cluster group %s" % cluster_name,
            os_client=client.nova_client(),
            requires=('name', 'policies'),
            inject={'name': "cue_group_%s" % cluster_id,
                    'policies': ['anti-affinity']},
            provides="cluster_group")
        flow.add(create_vm_group)

        get_scheduler_hints = os_common.Lambda(
            extract_scheduler_hints,
            name="extract scheduler hints %s" % cluster_name,
            rebind={'vm_group': "cluster_group"},
            provides="scheduler_hints")
        flow.add(get_scheduler_hints)

        build_cluster_info = os_common.Lambda(
            end_flow_cluster_update,
            name="build new cluster update values %s" % cluster_name,
            rebind={'vm_group': "cluster_group"},
            provides="cluster_values")
        flow.add(build_cluster_info)

        flow.link(create_cluster_start_task, create_vm_group)
        flow.link(create_vm_group, get_scheduler_hints)
        flow.link(get_scheduler_hints, build_cluster_info)
        create_node_start_task = build_cluster_info
        create_cluster_end_task = cue_tasks.UpdateClusterRecord(
            name="update cluster status end %s" % cluster_name,
            inject={'cluster_id': cluster_id})
    else:
        create_node_start_task = create_cluster_start_task
        end_flow_cluster_update = {
            'cluster_id': cluster_id,
            'cluster_values': {'status': models.Status.ACTIVE}}
        create_cluster_end_task = cue_tasks.UpdateClusterRecord(
            name="update cluster status end %s" % cluster_name,
            inject=end_flow_cluster_update)

    flow.add(create_cluster_end_task)

    show_network = os_neutron.ShowNetwork(
        name="get tenant network information",
        os_client=client.neutron_client(),
        inject={'network': user_network_id},
        provides="tenant_network_info"
    )
    flow.add(show_network)
    flow.link(create_node_start_task, show_network)

    validate_network_info = (lambda tenant_network_info, tenant_id:
                             tenant_network_info['shared'] or
                             tenant_network_info['tenant_id'] == tenant_id)

    validate_tenant_network = os_common.Assert(
        validate_network_info,
        name="validate tenant network info",
        requires=('tenant_network_info', 'tenant_id')
    )
    flow.add(validate_tenant_network)
    flow.link(show_network, validate_tenant_network)

    node_check_timeout = cfg.CONF.taskflow.cluster_node_check_timeout
    node_check_max_count = cfg.CONF.taskflow.cluster_node_check_max_count

    check_rabbit_online = linear_flow.Flow(
        name="wait for RabbitMQ ready state %s" % cluster_name,
        retry=retry.Times(node_check_max_count, revert_all=True))
    check_rabbit_online.add(
        cue_tasks.GetRabbitClusterStatus(
            name="get RabbitMQ status %s" % cluster_name,
            rebind={'vm_ip': "vm_management_ip_0"},
            provides="clustering_status",
            inject={'proto': 'http'}),
        os_common.CheckFor(
            name="check cluster status %s" % cluster_name,
            details="waiting for RabbitMQ clustered status",
            rebind={'check_var': "clustering_status"},
            check_value='OK',
            retry_delay_seconds=node_check_timeout),
    )
    flow.add(check_rabbit_online)

    flow.link(check_rabbit_online, create_cluster_end_task)

    #todo(dagnello): verify node_ids is a list and not a string
    for i, node_id in enumerate(node_ids):
        generate_userdata = cue_tasks.ClusterNodeUserData(
            name="generate userdata %s_%d" % (cluster_name, i),
            node_count=len(node_ids),
            node_ip_prefix="vm_management_ip_",
            inject={'node_name': "rabbit-node-%d" % i,
                    'cluster_id': cluster_id})
        flow.add(generate_userdata)

        create_cluster_node.create_cluster_node(cluster_id, i, node_id, flow,
                                                generate_userdata,
                                                validate_tenant_network,
                                                check_rabbit_online,
                                                user_network_id,
                                                management_network_id)

    return flow
Esempio n. 13
0
def delete_cluster_node(cluster_id, node_number, node_id):
    """Delete Cluster Node factory function

    This factory function deletes a flow for deleting a node of a cluster.

    :param cluster_id: Unique ID for the cluster that the node is part of.
    :type cluster_id: string
    :param node_number: Cluster node # for the node being deleted.
    :type node_number: number
    :param node_id: Unique ID for the node.
    :type node_id: string
    :return: A flow instance that represents the workflow for deleting a
             cluster node.
    """
    flow_name = "delete cluster %s node %d" % (cluster_id, node_number)
    node_name = "cluster[%s].node[%d]" % (cluster_id, node_number)

    extract_vm_id = lambda node: node['instance_id']
    extract_port_ids = lambda interfaces: [i['port_id'] for i in interfaces]

    deleted_node_values = {'status': models.Status.DELETED,
                           'deleted': True}

    deleted_endpoints_values = {'deleted': True}

    flow = linear_flow.Flow(flow_name)
    flow.add(
        cue_tasks.GetNode(
            name="Get Node %s" % node_name,
            inject={'node_id': node_id},
            provides="node_%d" % node_number),
        os_common.Lambda(
            extract_vm_id,
            name="extract vm id %s" % node_name,
            rebind={'node': "node_%d" % node_number},
            provides="vm_id_%d" % node_number),
        nova.ListVmInterfaces(
            os_client=client.nova_client(),
            name="list vm interfaces %s" % node_name,
            rebind={'server': "vm_id_%d" % node_number},
            inject={'ignore_nova_not_found_exception': True},
            provides="vm_interfaces_%d" % node_number),
        os_common.Lambda(
            extract_port_ids,
            name="extract port ids %s" % node_name,
            rebind={'interfaces': "vm_interfaces_%d" % node_number},
            provides="vm_port_list_%d" % node_number),
        nova.DeleteVm(
            os_client=client.nova_client(),
            name="delete vm %s" % node_name,
            rebind={'server': "vm_id_%d" % node_number}),
        neutron.DeletePorts(
            os_client=client.neutron_client(),
            name="delete vm %s ports" % node_name,
            rebind={'port_ids': "vm_port_list_%d" % node_number}),
        cue_tasks.UpdateNodeRecord(
            name="update node %s" % node_name,
            inject={'node_id': node_id,
                    'node_values': deleted_node_values}),
        cue_tasks.UpdateEndpointsRecord(
            name="update endpoint for node %s" % node_name,
            inject={'node_id': node_id,
                    'endpoints_values': deleted_endpoints_values}
        ))
    return flow
Esempio n. 14
0
def create_cluster_node(cluster_id, node_number, node_id, graph_flow,
                        generate_userdata, start_task, post_task,
                        user_network_id, management_network_id):
    """Create Cluster Node factory function

    This factory function creates a flow for creating a node of a cluster.

    :param cluster_id: Unique ID for the cluster that the node is part of.
    :type cluster_id: string
    :param node_number: Cluster node # for the node being created.
    :type node_number: number
    :param node_id: Unique ID for the node.
    :type node_id: string
    :param graph_flow: TaskFlow graph flow which contains create cluster flow
    :type graph_flow: taskflow.patterns.graph_flow
    :param start_task: Update cluster status start task
    :type start_task: cue.taskflow.task.UpdateClusterRecord
    :param post_task: Task/Subflow to run after the flow created here
    :type post_task: taskflow task or flow
    :param generate_userdata: generate user data task
    :type generate_userdata: cue.taskflow.task.ClusterNodeUserData
    :param user_network_id: The user's network id
    :type user_network_id: string
    :param management_network_id: The management network id
    :type management_network_id: string
    :return: A flow instance that represents the workflow for creating a
             cluster node.
    """
    node_name = "cue[%s].node[%d]" % (cluster_id, node_number)

    extract_port_info = (
        lambda user_port_info, management_port_info: (
            [  # nova boot requires a list of port-id's
                {
                    'port-id': user_port_info['port']['id']
                }, {
                    'port-id': management_port_info['port']['id']
                }
            ],
            # user port ip
            user_port_info['port']['fixed_ips'][0]['ip_address'],
            # management port ip
            management_port_info['port']['fixed_ips'][0]['ip_address']))

    extract_vm_id = lambda vm_info: str(vm_info['id'])

    new_node_values = lambda nova_vm_id, vm_management_ip: {
        'status': models.Status.ACTIVE,
        'instance_id': nova_vm_id,
        'management_ip': vm_management_ip
    }

    new_endpoint_values = lambda vm_ip: {
        'node_id': node_id,
        'uri': vm_ip + ':',
        'type': 'AMQP'
    }

    create_user_port = neutron.CreatePort(name="create port %s" % node_name,
                                          os_client=client.neutron_client(),
                                          inject={
                                              'network_id': user_network_id,
                                              'port_name': 'user_' + node_name
                                          },
                                          provides="user_port_info_%d" %
                                          node_number)
    graph_flow.add(create_user_port)
    graph_flow.link(start_task, create_user_port)

    create_management_port = neutron.CreatePort(
        name="create management port %s" % node_name,
        os_client=client.neutron_client(),
        inject={
            'network_id': management_network_id,
            'port_name': 'management_' + node_name
        },
        provides="management_port_info_%d" % node_number)
    graph_flow.add(create_management_port)
    graph_flow.link(start_task, create_management_port)

    extract_port_data = os_common.Lambda(
        extract_port_info,
        name="extract port id %s" % node_name,
        rebind={
            'user_port_info': "user_port_info_%d" % node_number,
            'management_port_info': "management_port_info_%d" % node_number
        },
        provides=("port_ids_%d" % node_number, "vm_user_ip_%d" % node_number,
                  "vm_management_ip_%d" % node_number))
    graph_flow.add(extract_port_data)
    graph_flow.link(create_user_port, extract_port_data)

    create_vm = nova.CreateVm(name="create vm %s" % node_name,
                              os_client=client.nova_client(),
                              requires=('name', 'image', 'flavor', 'nics'),
                              inject={'name': node_name},
                              rebind={'nics': "port_ids_%d" % node_number},
                              provides="vm_info_%d" % node_number)
    graph_flow.add(create_vm)
    graph_flow.link(create_management_port, create_vm)
    graph_flow.link(generate_userdata, create_vm)

    get_vm_id = os_common.Lambda(
        extract_vm_id,
        name="extract vm id %s" % node_name,
        rebind={'vm_info': "vm_info_%d" % node_number},
        provides="vm_id_%d" % node_number)

    graph_flow.add(get_vm_id)
    graph_flow.link(create_vm, get_vm_id)

    retry_count = CONF.flow_options.create_cluster_node_vm_active_retry_count
    check_vm_active = linear_flow.Flow(
        name="wait for VM active state %s" % node_name,
        retry=retry.ExceptionTimes(
            revert_exception_list=[cue_exceptions.VmErrorException],
            attempts=retry_count,
            revert_all=True))

    check_vm_active.add(
        nova.GetVmStatus(os_client=client.nova_client(),
                         name="get vm %s" % node_name,
                         rebind={'nova_vm_id': "vm_id_%d" % node_number},
                         provides="vm_status_%d" % node_number),
        cue_tasks.CheckForVmStatus(
            name="check vm status %s" % node_name,
            details="waiting for ACTIVE VM status",
            rebind={'check_var': "vm_status_%d" % node_number},
            retry_delay_seconds=10),
    )

    graph_flow.add(check_vm_active)
    graph_flow.link(get_vm_id, check_vm_active)

    build_node_info = os_common.Lambda(new_node_values,
                                       name="build new node values %s" %
                                       node_name,
                                       rebind={
                                           'nova_vm_id':
                                           "vm_id_%d" % node_number,
                                           'vm_management_ip':
                                           "vm_management_ip_%d" % node_number
                                       },
                                       provides="node_values_%d" % node_number)
    graph_flow.add(build_node_info)
    graph_flow.link(get_vm_id, build_node_info)

    update_node = cue_tasks.UpdateNodeRecord(
        name="update node %s" % node_name,
        rebind={'node_values': "node_values_%d" % node_number},
        inject={'node_id': node_id})
    graph_flow.add(update_node)
    graph_flow.link(build_node_info, update_node)

    build_endpoint_info = os_common.Lambda(
        new_endpoint_values,
        name="build new endpoint values %s" % node_name,
        rebind={'vm_ip': "vm_user_ip_%d" % node_number},
        inject={'node_id': node_id},
        provides="endpoint_values_%d" % node_number)
    graph_flow.add(build_endpoint_info)
    graph_flow.link(check_vm_active, build_endpoint_info)

    create_endpoint = cue_tasks.CreateEndpoint(
        name="update endpoint for node %s" % node_name,
        rebind={'endpoint_values': "endpoint_values_%d" % node_number})
    graph_flow.add(create_endpoint)
    graph_flow.link(check_vm_active, create_endpoint)

    graph_flow.link(update_node, post_task)
    graph_flow.link(create_endpoint, post_task)