def create(self):
        """Create a vm and vmi, find or create a network, and attach
        the vmi to a new veth interface

        Arguments:

          vm_name   name of the vm to create
          net_name  name of the netwok to arrach to
          subnet    x.x.x.x/len - optional if network already exists
          netns     Network namespace where the veth interface is bound to.  Defaults to net_name    

        Returns:

          A dict with the following elements:
          
          port_id  uuid of port
          ip
          veth     name of veth interface
          netns    Network namespace where the veth interface is bound to
          
        """
        
        # remember what to clean up if things go wrong
        port_created = False
        veth_created = False
        netns_created = False
        ip_created = False
        vmi_created = False
        vnet_created = False
        vm_created = False

        try:
            # sanity check
            net_name = self.args.get('net_name')
            if not net_name:
                raise ValueError("Network name argument is required")

            # sanitize netns since it gets passed to the shell
            netns = self.args.get('netns')
            if not netns:
                netns = net_name
            if not re.match(r'^[-.\w]+$', netns):
                raise ValueError("netns=[%s] must be a valid namespace name"
                                 + " (a single word)" % netns)

            
            vnc_client = self.vnc_connect()

            proj_fq_name = self.args['project'].split(':')

            # find or create the VM
            vm_fq_name = proj_fq_name + [ self.args['vm_name'] ]

            # debug
            #import pdb; pdb.set_trace()

            try:
                vm = vnc_client.virtual_machine_read(fq_name = vm_fq_name)
                if vm:
                    raise ValueError(("Virtual machine named %s already exists."
                                      + "  Use --delete to delete it")
                                     % self.args['vm_name'])
            except vnc_api.NoIdError:
                # create vm if necessary
                vm = vnc_api.VirtualMachine(':'.join(vm_fq_name),
                                            fq_name=vm_fq_name)
                vnc_client.virtual_machine_create(vm)
                vm = vnc_client.virtual_machine_read(fq_name = vm_fq_name)
                vm_created = True
                
            # find or create the network
            vnet_fq_name = proj_fq_name + [ net_name ]
            vnet_created = False
            try:
                vnet = vnc_client.virtual_network_read(fq_name = vnet_fq_name)
            except vnc_api.NoIdError:
                # create the network if it doesn't exist
                vnet = vnc_api.VirtualNetwork(vnet_fq_name[-1],
                                              parent_type = 'project',
                                              fq_name = vnet_fq_name)

                # add a subnet
                ipam = vnc_client.network_ipam_read(
                    fq_name = ['default-domain',
                               'default-project',
                               'default-network-ipam'])
                (prefix, plen) = self.args['subnet'].split('/')
                subnet = vnc_api.IpamSubnetType(
                    subnet = vnc_api.SubnetType(prefix, int(plen)))
                vnet.add_network_ipam(ipam, vnc_api.VnSubnetsType([subnet]))

                vnc_client.virtual_network_create(vnet)
                vnet_created = True

            # find or create the vmi
            vmi_fq_name = vm.fq_name + ['0']
            vmi_created = False
            try:
                vmi = vnc_client.virtual_machine_interface_read(
                    fq_name = vmi_fq_name)
            except vnc_api.NoIdError:
                vmi = vnc_api.VirtualMachineInterface(
                    parent_type = 'virtual-machine',
                    fq_name = vmi_fq_name)
                vmi_created = True
            vmi.set_virtual_network(vnet)
            if vmi_created:
                vnc_client.virtual_machine_interface_create(vmi)
            else:
                vnc_client.virtual_machine_interface_update(vmi)
            # re-read the vmi to get its mac addresses
            vmi = vnc_client.virtual_machine_interface_read(
                fq_name = vmi_fq_name)
            # create an IP for the VMI if it doesn't already have one
            ips = vmi.get_instance_ip_back_refs()
            if not ips:
                ip = vnc_api.InstanceIp(vm.name + '.0')
                ip.set_virtual_machine_interface(vmi)
                ip.set_virtual_network(vnet)
                ip_created = vnc_client.instance_ip_create(ip)

            # Create the veth port.  Create a veth pair.  Put one end
            # in the VMI port and the other in a network namespace
            
            # get the ip, mac, and gateway from the vmi
            ip_uuid = vmi.get_instance_ip_back_refs()[0]['uuid']
            ip = vnc_client.instance_ip_read(id=ip_uuid).instance_ip_address
            mac = vmi.virtual_machine_interface_mac_addresses.mac_address[0]
            subnet = vnet.network_ipam_refs[0]['attr'].ipam_subnets[0]
            gw = subnet.default_gateway
            dns = gw # KLUDGE - that's the default, but some networks
                     # have other DNS configurations
            ipnetaddr = netaddr.IPNetwork("%s/%s" %
                                          (subnet.subnet.ip_prefix,
                                           subnet.subnet.ip_prefix_len))
            
            # set up the veth pair with one part for vrouter and one
            # for the netns

            # find a name that's not already used in the default or
            # netns namespaces
            link_exists = link_exists_func('', netns)
            veth_vrouter = new_interface_name(suffix=vnet.uuid, prefix="ve1",
                                              exists_func=link_exists)
            veth_host = new_interface_name(suffix=vnet.uuid, prefix="ve0",
                                           exists_func=link_exists)
            
            sudo("ip link add %s type veth peer name %s",
                 (veth_vrouter, veth_host))
            veth_created = True
            try:
                sudo("ip netns add %s", (netns,))
                netns_created = True
            except ProcessExecutionError:
                pass
            
            sudo("ip link set %s netns %s",
                 (veth_host, netns))
            sudo("ip netns exec %s ip link set dev %s address %s",
                 (netns, veth_host, mac))
            sudo("ip netns exec %s ip address add %s broadcast %s dev %s",
                 (netns,
                  ("%s/%s" % (ip, subnet.subnet.ip_prefix_len)),
                  ipnetaddr.broadcast, veth_host))
            sudo("ip netns exec %s ip link set dev %s up",
                 (netns, veth_host))
            sudo("ip netns exec %s route add default gw %s dev %s",
                 (netns, gw, veth_host))
            sudo("ip link set dev %s up", (veth_vrouter,))

            # make a namespace-specific resolv.conf
            resolv_conf = "/etc/netns/%s/resolv.conf" % netns
            resolv_conf_body = "nameserver %s\n" % dns
            sudo("mkdir -p %s", (os.path.dirname(resolv_conf),))
            sudo("tee %s", (resolv_conf,), process_input=resolv_conf_body)

            # finally, create the Contrail port
            port = instance_service.ttypes.Port(
                uuid_from_string(vmi.uuid),
                uuid_from_string(vm.uuid), 
                veth_vrouter,
                ip,
                uuid_from_string(vnet.uuid),
                mac,
                )
            rpc = vrouter_rpc()
            rpc.AddPort([port])
            port_created = True
            
            return(dict(
                port_id = uuid_array_to_str(port.port_id),
                vm_id = vm.uuid,
                net_id = vnet.uuid,
                vmi_id = vmi.uuid,
                veth = veth_host,
                netns = netns,
                ip = ip,
                mac = mac,
                gw = gw,
                dns = dns,
                netmask = str(ipnetaddr.netmask),
                broadcast = str(ipnetaddr.broadcast),
                ))

        except:
            # something went wrong, clean up
            if port_created:
                rpc.DeletePort(port.port_id)
            if veth_created:
                sudo("ip link delete %s", (veth_vrouter,),
                     check_exit_code=False)
            if netns_created:
                sudo("ip netns delete %s", (netns,), check_exit_code=False)
            if ip_created:
                vnc_client.instance_ip_delete(id=ip_created)
            if vmi_created:
                vnc_client.virtual_machine_interface_delete(id=vmi.uuid)
            if vnet_created:
                vnc_client.virtual_network_delete(id=vnet.uuid)
            if vm_created:
                vnc_client.virtual_machine_delete(id=vm.uuid)
            raise
Example #2
0
print 'Execute>> Delete port %s' % vm_interface.uuid
rpc = vrouter_rpc()
rpc.DeletePort(uuid_from_string(vm_interface.uuid))

print 'Execute>> Add port %s' % vm_interface.uuid
port = ttypes.Port(
    uuid_from_string(vm_interface.uuid),
    uuid_from_string(vm_instance.uuid),
    peth,
    ip,
    uuid_from_string(vnet.uuid),
    mac,
)
rpc.AddPort([port])

print(
    dict(
        port_id=uuid_array_to_str(port.port_id),
        vm_id=vm_instance.uuid,
        net_id=vnet.uuid,
        vmi_id=vm_interface.uuid,
        veth=peth,
        netns=ns_name,
        ip=ip,
        mac=mac,
        gw=gw,
        dns=dns,
        netmask=subnet.subnet.ip_prefix_len,
        broadcast=subnet.subnet.ip_prefix,
    ))

print 'Execute>> Delete port %s' %vm_interface.uuid
rpc = vrouter_rpc()
rpc.DeletePort(uuid_from_string(vm_interface.uuid))

print 'Execute>> Add port %s' %vm_interface.uuid
port = ttypes.Port(
    uuid_from_string(vm_interface.uuid),
    uuid_from_string(vm_instance.uuid),
    peth,
    ip,
    uuid_from_string(vnet.uuid),
    mac,
    )
rpc.AddPort([port])

print (dict(port_id = uuid_array_to_str(port.port_id),
            vm_id = vm_instance.uuid,
            net_id = vnet.uuid,
            vmi_id = vm_interface.uuid,
            veth = peth,
            netns = ns_name,
            ip = ip,
            mac = mac,
            gw = gw,
            dns = dns,
            netmask = subnet.subnet.ip_prefix_len,
            broadcast = subnet.subnet.ip_prefix,
            ))
    def create(self):
        """Create a vm and vmi, find or create a network, and attach
        the vmi to a new veth interface

        Arguments:

          vm_name   name of the vm to create
          net_name  name of the netwok to arrach to
          subnet    x.x.x.x/len - optional if network already exists
          netns     Network namespace where the veth interface is bound to.  Defaults to net_name    

        Returns:

          A dict with the following elements:
          
          port_id  uuid of port
          ip
          veth     name of veth interface
          netns    Network namespace where the veth interface is bound to
          
        """
        
        # remember what to clean up if things go wrong
        port_created = False
        veth_created = False
        netns_created = False
        ip_created = False
        vmi_created = False
        vnet_created = False
        vm_created = False

        try:
            # sanity check
            net_name = self.args.get('net_name')
            if not net_name:
                raise ValueError("Network name argument is required")

            # sanitize netns since it gets passed to the shell
            netns = self.args.get('netns')
            if not netns:
                netns = net_name
            if not re.match(r'^[-.\w]+$', netns):
                raise ValueError("netns=[%s] must be a valid namespace name"
                                 + " (a single word)" % netns)

            
            vnc_client = self.vnc_connect()

            proj_fq_name = self.args['project'].split(':')

            # find or create the VM
            vm_fq_name = proj_fq_name + [ self.args['vm_name'] ]

            # debug
            #import pdb; pdb.set_trace()

            try:
                vm = vnc_client.virtual_machine_read(fq_name = vm_fq_name)
                if vm:
                    raise ValueError(("Virtual machine named %s already exists."
                                      + "  Use --delete to delete it")
                                     % self.args['vm_name'])
            except vnc_api.NoIdError:
                # create vm if necessary
                vm = vnc_api.VirtualMachine(':'.join(vm_fq_name),
                                            fq_name=vm_fq_name)
                vnc_client.virtual_machine_create(vm)
                vm = vnc_client.virtual_machine_read(fq_name = vm_fq_name)
                vm_created = True
                
            # find or create the network
            vnet_fq_name = proj_fq_name + [ net_name ]
            vnet_created = False
            try:
                vnet = vnc_client.virtual_network_read(fq_name = vnet_fq_name)
            except vnc_api.NoIdError:
                # create the network if it doesn't exist
                vnet = vnc_api.VirtualNetwork(vnet_fq_name[-1],
                                              parent_type = 'project',
                                              fq_name = vnet_fq_name)

                # add a subnet
                ipam = vnc_client.network_ipam_read(
                    fq_name = ['default-domain',
                               'default-project',
                               'default-network-ipam'])
                (prefix, plen) = self.args['subnet'].split('/')
                subnet = vnc_api.IpamSubnetType(
                    subnet = vnc_api.SubnetType(prefix, int(plen)))
                vnet.add_network_ipam(ipam, vnc_api.VnSubnetsType([subnet]))

                vnc_client.virtual_network_create(vnet)
                vnet_created = True

            # find or create the vmi
            vmi_fq_name = vm.fq_name + ['0']
            vmi_created = False
            try:
                vmi = vnc_client.virtual_machine_interface_read(
                    fq_name = vmi_fq_name)
            except vnc_api.NoIdError:
                vmi = vnc_api.VirtualMachineInterface(
                    parent_type = 'virtual-machine',
                    fq_name = vmi_fq_name)
                vmi_created = True
            vmi.set_virtual_network(vnet)
            if vmi_created:
                vnc_client.virtual_machine_interface_create(vmi)
            else:
                vnc_client.virtual_machine_interface_update(vmi)
            # re-read the vmi to get its mac addresses
            vmi = vnc_client.virtual_machine_interface_read(
                fq_name = vmi_fq_name)
            # create an IP for the VMI if it doesn't already have one
            ips = vmi.get_instance_ip_back_refs()
            if not ips:
                ip = vnc_api.InstanceIp(vm.name + '.0')
                ip.set_virtual_machine_interface(vmi)
                ip.set_virtual_network(vnet)
                ip_created = vnc_client.instance_ip_create(ip)

            # Create the veth port.  Create a veth pair.  Put one end
            # in the VMI port and the other in a network namespace
            
            # get the ip, mac, and gateway from the vmi
            ip_uuid = vmi.get_instance_ip_back_refs()[0]['uuid']
            ip = vnc_client.instance_ip_read(id=ip_uuid).instance_ip_address
            mac = vmi.virtual_machine_interface_mac_addresses.mac_address[0]
            subnet = vnet.network_ipam_refs[0]['attr'].ipam_subnets[0]
            gw = subnet.default_gateway
            dns = gw # KLUDGE - that's the default, but some networks
                     # have other DNS configurations
            ipnetaddr = netaddr.IPNetwork("%s/%s" %
                                          (subnet.subnet.ip_prefix,
                                           subnet.subnet.ip_prefix_len))
            
            # set up the veth pair with one part for vrouter and one
            # for the netns

            # find a name that's not already used in the default or
            # netns namespaces
            link_exists = link_exists_func('', netns)
            veth_vrouter = new_interface_name(suffix=vnet.uuid, prefix="ve1",
                                              exists_func=link_exists)
            veth_host = new_interface_name(suffix=vnet.uuid, prefix="ve0",
                                           exists_func=link_exists)
            
            sudo("ip link add %s type veth peer name %s",
                 (veth_vrouter, veth_host))
            veth_created = True
            try:
                sudo("ip netns add %s", (netns,))
                netns_created = True
            except ProcessExecutionError:
                pass
            
            sudo("ip link set %s netns %s",
                 (veth_host, netns))
            sudo("ip netns exec %s ip link set dev %s address %s",
                 (netns, veth_host, mac))
            sudo("ip netns exec %s ip address add %s broadcast %s dev %s",
                 (netns,
                  ("%s/%s" % (ip, subnet.subnet.ip_prefix_len)),
                  ipnetaddr.broadcast, veth_host))
            sudo("ip netns exec %s ip link set dev %s up",
                 (netns, veth_host))
            sudo("ip netns exec %s route add default gw %s dev %s",
                 (netns, gw, veth_host))
            sudo("ip link set dev %s up", (veth_vrouter,))

            # make a namespace-specific resolv.conf
            resolv_conf = "/etc/netns/%s/resolv.conf" % netns
            resolv_conf_body = "nameserver %s\n" % dns
            sudo("mkdir -p %s", (os.path.dirname(resolv_conf),))
            sudo("tee %s", (resolv_conf,), process_input=resolv_conf_body)

            # finally, create the Contrail port
            port = instance_service.ttypes.Port(
                uuid_from_string(vmi.uuid),
                uuid_from_string(vm.uuid), 
                veth_vrouter,
                ip,
                uuid_from_string(vnet.uuid),
                mac,
                )
            rpc = vrouter_rpc()
            rpc.AddPort([port])
            port_created = True
            
            return(dict(
                port_id = uuid_array_to_str(port.port_id),
                vm_id = vm.uuid,
                net_id = vnet.uuid,
                vmi_id = vmi.uuid,
                veth = veth_host,
                netns = netns,
                ip = ip,
                mac = mac,
                gw = gw,
                dns = dns,
                netmask = str(ipnetaddr.netmask),
                broadcast = str(ipnetaddr.broadcast),
                ))

        except:
            # something went wrong, clean up
            if port_created:
                rpc.DeletePort(port.port_id)
            if veth_created:
                sudo("ip link delete %s", (veth_vrouter,),
                     check_exit_code=False)
            if netns_created:
                sudo("ip netns delete %s", (netns,), check_exit_code=False)
            if ip_created:
                vnc_client.instance_ip_delete(id=ip_created)
            if vmi_created:
                vnc_client.virtual_machine_interface_delete(id=vmi.uuid)
            if vnet_created:
                vnc_client.virtual_network_delete(id=vnet.uuid)
            if vm_created:
                vnc_client.virtual_machine_delete(id=vm.uuid)
            raise
    def create(self):
        # remember what to clean up if things go wrong
        port_created = False
        veth_created = False
        netns_created = False
        ip_created = False
        vmi_created = False
        vnet_created = False
        vm_created = False

        try:
            vnc_client = self.vnc_connect()

            proj_fq_name = self.args['project'].split(':')

            vm_fq_name = [ self.args['vm_name']]

            try:
                vm = vnc_client.virtual_machine_read(fq_name = vm_fq_name)
            except cfgm_common.exceptions.NoIdError:
                # create vm if necessary
                vm = vnc_api.VirtualMachine(self.args['vm_name'],
                                            fq_name=vm_fq_name)
                vnc_client.virtual_machine_create(vm)
                vm = vnc_client.virtual_machine_read(fq_name = vm_fq_name)
                vm_created = True
    
            # find the network
            vnet_fq_name = proj_fq_name + [ self.args['net_name'] ]
            vnet_created = False
            vnet = vnc_client.virtual_network_read(fq_name = vnet_fq_name)

            # find or create the vmi
            vmi_fq_name = proj_fq_name+['web_proxy_vmi']
            vmi_created = False
            try:
                vmi = vnc_client.virtual_machine_interface_read(
                    fq_name = vmi_fq_name)
            except cfgm_common.exceptions.NoIdError:
                vmi = vnc_api.VirtualMachineInterface(
                    parent_type = 'project',
                    fq_name = vmi_fq_name)
                vmi_created = True

            vmi.set_virtual_network(vnet)
            vmi.set_virtual_machine(vm)

            if vmi_created:
                vnc_client.virtual_machine_interface_create(vmi)
            else:
                vnc_client.virtual_machine_interface_update(vmi)
            # re-read the vmi to get its mac addresses
            vmi = vnc_client.virtual_machine_interface_read(
                fq_name = vmi_fq_name)
            # create an IP for the VMI if it doesn't already have one
            ips = vmi.get_instance_ip_back_refs()
            if not ips:
                ip = vnc_api.InstanceIp(vm.name + '.0')
                ip.set_virtual_machine_interface(vmi)
                ip.set_virtual_network(vnet)
                ip_created = vnc_client.instance_ip_create(ip)

            # Create the veth port.  Create a veth pair.  Put one end
            # in the VMI port and the other in a network namespace
            
            # get the ip, mac, and gateway from the vmi
            ip_uuid = vmi.get_instance_ip_back_refs()[0]['uuid']
            ip = vnc_client.instance_ip_read(id=ip_uuid).instance_ip_address
            mac = vmi.virtual_machine_interface_mac_addresses.mac_address[0]
            subnet = vnet.network_ipam_refs[0]['attr'].ipam_subnets[0]
            gw = subnet.default_gateway
            dns = gw # KLUDGE - that's the default, but some networks
                     # have other DNS configurations
            ipnetaddr = netaddr.IPNetwork("%s/%s" %
                                          (subnet.subnet.ip_prefix,
                                           subnet.subnet.ip_prefix_len))
            
            # set up the veth pair with one part for vrouter and one
            # for the netns

            # find a name that's not already used in the default or
            # netns namespaces
            netns=self.args['netns']
            link_exists = link_exists_func('', netns)
            veth_vrouter = new_interface_name(suffix=vnet.uuid, prefix="ve1",
                                              exists_func=link_exists)
            veth_host = new_interface_name(suffix=vnet.uuid, prefix="ve0",
                                           exists_func=link_exists)
            
            os.system("ip link add %s type veth peer name %s"%
                 (veth_vrouter, veth_host))
            veth_created = True
            
            if os.system("ip netns add %s"%(netns))==0:
                netns_created = True
            
            os.system("ip link set %s netns %s"%(veth_host, netns))
            os.system("ip netns exec %s ip link set dev %s address %s"%(netns, veth_host, mac))
            os.system("ip netns exec %s ip address add %s broadcast %s dev %s"%(netns,
                  ("%s/%s" % (ip, subnet.subnet.ip_prefix_len)),
                  ipnetaddr.broadcast, veth_host))
            os.system("ip netns exec %s ip link set dev %s up"%(netns, veth_host))
            os.system("ip netns exec %s route add default gw %s dev %s"%(netns, gw, veth_host))
            os.system("ip link set dev %s up"%(veth_vrouter))

            # make a namespace-specific resolv.conf
            resolv_conf = "/etc/netns/%s/resolv.conf" % netns
            resolv_conf_body = "nameserver %s" % dns
            os.system("mkdir -p %s"%(os.path.dirname(resolv_conf)))
            os.system("echo %s > %s"%(resolv_conf_body,resolv_conf))

            # finally, create the Contrail port
            port = instance_service.ttypes.Port(
                uuid_from_string(vmi.uuid),
                uuid_from_string(vm.uuid), 
                veth_vrouter,
                ip,
                uuid_from_string(vnet.uuid),
                mac,
                )
            rpc = vrouter_rpc()
            rpc.AddPort([port])
            port_created = True
            
            return(dict(
                port_id = uuid_array_to_str(port.port_id),
                vm_id = vm.uuid,
                net_id = vnet.uuid,
                vmi_id = vmi.uuid,
                veth = veth_host,
                netns = netns,
                ip = ip,
                mac = mac,
                gw = gw,
                dns = dns,
                netmask = str(ipnetaddr.netmask),
                broadcast = str(ipnetaddr.broadcast),
                ))

        except:
            # something went wrong, clean up
            if port_created:
                rpc.DeletePort(port.port_id)
            if veth_created:
                os.system("ip link delete %s"%(veth_vrouter))
            if netns_created:
                os.system("ip netns delete %s"%(netns))
            if ip_created:
                vnc_client.instance_ip_delete(id=ip_created)
            if vmi_created:
                vnc_client.virtual_machine_interface_delete(id=vmi.uuid)
            if vnet_created:
                vnc_client.virtual_network_delete(id=vnet.uuid)
            if vm_created:
                vnc_client.virtual_machine_delete(id=vm.uuid)
            raise