class TestLan(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.resource = resource()
        self.client = ProfitBricksService(
            username=configuration.USERNAME,
            password=configuration.PASSWORD,
            headers=configuration.HEADERS)

        # Create test datacenter.
        self.datacenter = self.client.create_datacenter(
            datacenter=Datacenter(**self.resource['datacenter']))
        wait_for_completion(self.client, self.datacenter, 'create_datacenter')

        # Create test LAN.
        self.lan = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=LAN(**self.resource['lan']))
        wait_for_completion(self.client, self.lan, 'create_lan')

        # Create test server.
        self.server = self.client.create_server(
            datacenter_id=self.datacenter['id'],
            server=Server(**self.resource['server']))
        wait_for_completion(self.client, self.server, 'create_server')

        # Create test NIC1.
        nic1 = NIC(**self.resource['nic'])
        nic1.lan = self.lan['id']
        self.nic1 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic1)
        wait_for_completion(self.client, self.nic1, 'create_nic1')

        # Create test NIC2.
        nic2 = NIC(**self.resource['nic'])
        nic2.lan = self.lan['id']
        self.nic2 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic2)
        wait_for_completion(self.client, self.nic2, 'create_nic2')

    @classmethod
    def tearDownClass(self):
        self.client.delete_datacenter(datacenter_id=self.datacenter['id'])
Example #2
0
class TestLan(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.resource = resource()
        self.client = ProfitBricksService(
            username=configuration.USERNAME,
            password=configuration.PASSWORD,
            headers=configuration.HEADERS)

        # Create test datacenter.
        self.datacenter = self.client.create_datacenter(
            datacenter=Datacenter(**self.resource['datacenter']))
        self.client.wait_for_completion(self.datacenter)

        # Create test LAN.
        self.lan = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=LAN(**self.resource['lan']))
        self.client.wait_for_completion(self.lan)

        # Create test server.
        self.server = self.client.create_server(
            datacenter_id=self.datacenter['id'],
            server=Server(**self.resource['server']))
        self.client.wait_for_completion(self.server)

        # Create test NIC1.
        nic1 = NIC(**self.resource['nic'])
        nic1.lan = self.lan['id']
        self.nic1 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic1)
        self.client.wait_for_completion(self.nic1)

        # Create test NIC2.
        nic2 = NIC(**self.resource['nic'])
        nic2.lan = self.lan['id']
        self.nic2 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic2)
        self.client.wait_for_completion(self.nic2)

    @classmethod
    def tearDownClass(self):
        self.client.delete_datacenter(datacenter_id=self.datacenter['id'])

    def test_list_lans(self):
        lans = self.client.list_lans(datacenter_id=self.datacenter['id'])

        self.assertGreater(len(lans), 0)
        self.assertEqual(lans['items'][0]['type'], 'lan')
        self.assertIn(lans['items'][0]['id'], ('1', '2', '3'))
        self.assertEqual(lans['items'][0]['properties']['name'], self.resource['lan']['name'])
        self.assertTrue(lans['items'][0]['properties']['public'], self.resource['lan']['public'])

    def test_get_lan(self):
        lan = self.client.get_lan(datacenter_id=self.datacenter['id'], lan_id=self.lan['id'])

        self.assertEqual(lan['type'], 'lan')
        self.assertEqual(lan['id'], self.lan['id'])
        self.assertEqual(lan['properties']['name'], self.resource['lan']['name'])
        self.assertTrue(lan['properties']['public'], self.resource['lan']['public'])

    def test_remove_lan(self):
        lan = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=LAN(**self.resource['lan']))

        self.client.wait_for_completion(lan)

        lan = self.client.delete_lan(datacenter_id=self.datacenter['id'], lan_id=lan['id'])

        self.assertTrue(lan)

    def test_update_lan(self):
        lan = self.client.update_lan(
            datacenter_id=self.datacenter['id'],
            lan_id=self.lan['id'],
            name=self.resource['lan']['name'] + ' - RENAME',
            public=False)

        self.assertEqual(lan['type'], 'lan')
        self.assertEqual(lan['properties']['name'], self.resource['lan']['name'] + ' - RENAME')
        self.assertFalse(lan['properties']['public'])

    def test_create_lan(self):
        self.assertEqual(self.lan['id'], '1')
        self.assertEqual(self.lan['type'], 'lan')
        self.assertEqual(self.lan['properties']['name'], self.resource['lan']['name'])
        self.assertEqual(self.lan['properties']['public'], self.resource['lan']['public'])

    def test_create_complex_lan(self):
        resource = NIC(**self.resource['nic'])

        nic1 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=resource)
        self.client.wait_for_completion(nic1)
        self.assertFalse(nic1['properties']['nat'])
        self.assertEqual(nic1['properties']['name'], 'Python SDK Test')
        self.assertTrue(nic1['properties']['dhcp'])
        self.assertEqual(nic1['properties']['lan'], 1)
        self.assertTrue(nic1['properties']['firewallActive'])

        nics = [nic1['id']]
        lan = LAN(nics=nics, **self.resource['lan'])

        response = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=lan)
        self.client.wait_for_completion(response)

        self.assertEqual(response['type'], 'lan')
        self.assertEqual(response['properties']['name'], self.resource['lan']['name'])
        self.assertTrue(response['properties']['public'])

    def test_get_lan_members(self):
        members = self.client.get_lan_members(
            datacenter_id=self.datacenter['id'],
            lan_id=self.lan['id'])

        self.assertGreater(len(members), 0)
        self.assertEqual(members['items'][0]['type'], 'nic')
        self.assertEqual(members['items'][0]['properties']['name'], self.resource['nic']['name'])
        assertRegex(self, members['items'][0]['properties']['mac'], self.resource['mac_match'])

    def test_get_failure(self):
        try:
            self.client.get_lan(datacenter_id=self.datacenter['id'], lan_id=0)
        except PBNotFoundError as e:
            self.assertIn(self.resource['not_found_error'], e.content[0]['message'])

    def test_create_failure(self):
        try:
            self.client.create_lan(
                datacenter_id='00000000-0000-0000-0000-000000000000', lan=LAN())
        except PBNotFoundError as e:
            self.assertIn(self.resource['not_found_error'], e.content[0]['message'])
print(lans)
"""Create Complex LAN
"""
from profitbricks.client import ProfitBricksService, LAN  # noqa

lan_id = '4'
datacenter_id = '700e1cab-99b2-4c30-ba8c-1d273ddba022'

client = ProfitBricksService(username='******', password='******')

nics = ['<NIC-ID-1>', '<NIC-ID-2>']

i = LAN(name='public Lan 4', public=True, nics=nics)

response = client.create_lan(datacenter_id=datacenter_id, lan=i)
"""Create LAN
"""
from profitbricks.client import ProfitBricksService, LAN  # noqa

lan_id = '4'
datacenter_id = '700e1cab-99b2-4c30-ba8c-1d273ddba022'

client = ProfitBricksService(username='******', password='******')

i = LAN(name='public Lan 4', public=True)

response = client.create_lan(datacenter_id=datacenter_id, lan=i)
"""Get LAN Members
"""
from profitbricks.client import ProfitBricksService  # noqa
class TestNic(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.resource = resource()
        self.client = ProfitBricksService(
            username=configuration.USERNAME,
            password=configuration.PASSWORD,
            headers=configuration.HEADERS)

        # Create test datacenter.
        self.datacenter = self.client.create_datacenter(
            datacenter=Datacenter(**self.resource['datacenter']))
        self.client.wait_for_completion(self.datacenter)

        # Create test LAN.
        self.lan = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=LAN(name=self.resource['lan']['name'], public=False))
        self.client.wait_for_completion(self.lan)

        # Create test server.
        self.server = self.client.create_server(
            datacenter_id=self.datacenter['id'],
            server=Server(**self.resource['server']))
        self.client.wait_for_completion(self.server)

        # Create test NIC1.
        nic1 = NIC(**self.resource['nic'])
        nic1.lan = self.lan['id']
        self.ips = ['10.0.0.1']
        nic1.ips = self.ips
        self.nic1 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic1)
        self.client.wait_for_completion(self.nic1)

        # Create test NIC2.
        nic2 = NIC(**self.resource['nic'])
        nic2.lan = self.lan['id']
        self.nic2 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic2)
        self.client.wait_for_completion(self.nic2)

    @classmethod
    def tearDownClass(self):
        self.client.delete_datacenter(datacenter_id=self.datacenter['id'])

    def test_list_nics(self):
        nics = self.client.list_nics(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'])

        self.assertGreater(len(nics), 0)
        self.assertIn(nics['items'][0]['id'], (self.nic1['id'], self.nic2['id']))
        self.assertEqual(nics['items'][0]['type'], 'nic')

    def test_get_nic(self):
        nic = self.client.get_nic(datacenter_id=self.datacenter['id'],
                                  server_id=self.server['id'],
                                  nic_id=self.nic1['id'])

        self.assertEqual(nic['type'], 'nic')
        self.assertEqual(nic['id'], self.nic1['id'])
        assertRegex(self, nic['id'], self.resource['uuid_match'])
        self.assertEqual(nic['properties']['name'], self.resource['nic']['name'])
        self.assertEqual(nic['properties']['firewallActive'],
                         self.resource['nic']['firewall_active'])
        self.assertIsInstance(nic['properties']['ips'], list)
        self.assertEqual(nic['properties']['dhcp'], self.resource['nic']['dhcp'])
        self.assertEqual(nic['properties']['nat'], self.resource['nic']['nat'])
        self.assertEqual(nic['properties']['lan'], self.resource['nic']['lan'])

    def test_delete_nic(self):
        nic2 = self.client.delete_nic(datacenter_id=self.datacenter['id'],
                                      server_id=self.server['id'],
                                      nic_id=self.nic2['id'])

        self.assertTrue(nic2)

    def test_update_nic(self):
        nic = self.client.update_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic_id=self.nic1['id'],
            name=self.resource['nic']['name'] + ' - RENAME')

        self.assertEqual(nic['id'], self.nic1['id'])
        self.assertEqual(nic['type'], 'nic')
        self.assertEqual(nic['properties']['name'], self.resource['nic']['name'] + ' - RENAME')

    def test_create_nic(self):
        self.assertEqual(self.nic1['type'], 'nic')
        self.assertEqual(self.nic1['properties']['name'], self.resource['nic']['name'])
        self.assertEqual(self.nic1['properties']['firewallActive'],
                         self.resource['nic']['firewall_active'])
        self.assertIsInstance(self.nic1['properties']['ips'], list)
        self.assertEqual(self.nic1['properties']['dhcp'], self.resource['nic']['dhcp'])
        self.assertIsNone(self.nic1['properties']['nat'])
        self.assertEqual(str(self.nic1['properties']['lan']), self.lan['id'])

    def test_get_failure(self):
        try:
            self.client.get_nic(
                datacenter_id=self.datacenter['id'],
                server_id=self.server['id'],
                nic_id='00000000-0000-0000-0000-000000000000')
        except PBNotFoundError as e:
            self.assertIn(self.resource['not_found_error'], e.content[0]['message'])

    def test_create_failure(self):
        try:
            nic = NIC(name=self.resource['nic']['name'])
            self.client.create_nic(
                datacenter_id=self.datacenter['id'],
                server_id=self.server['id'],
                nic=nic)
        except PBError as e:
            self.assertIn(self.resource['missing_attribute_error'] % 'lan',
                          e.content[0]['message'])
def main(argv=None):
    '''Parse command line options and create a server/volume composite.'''

    if argv is None:
        argv = sys.argv
    else:
        sys.argv.extend(argv)

    program_name = os.path.basename(sys.argv[0])
    program_version = "v%s" % __version__
    program_build_date = str(__updated__)
    program_version_message = '%%(prog)s %s (%s)' % (program_version,
                                                     program_build_date)
    program_shortdesc = __import__('__main__').__doc__.split("\n")[1]
    program_license = '''%s

  Created by J. Buchhammer on %s.
  Copyright 2016 ProfitBricks GmbH. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.

USAGE
''' % (program_shortdesc, str(__date__))
    # Setup argument parser
    parser = ArgumentParser(description=program_license,
                            formatter_class=RawDescriptionHelpFormatter)
    parser.add_argument('-u', '--user', dest='user', help='the login name')
    parser.add_argument('-p',
                        '--password',
                        dest='password',
                        help='the login password')
    parser.add_argument('-L',
                        '--Login',
                        dest='loginfile',
                        default=None,
                        help='the login file to use')
    parser.add_argument('-i',
                        '--infile',
                        dest='infile',
                        default=None,
                        required=True,
                        help='the input file name')
    parser.add_argument('-D',
                        '--DCname',
                        dest='dcname',
                        default=None,
                        help='new datacenter name')
    # TODO: add/overwrite image password for creation
    #    parser.add_argument('-P', '--imagepassword', dest='imgpassword',
    #                        default=None, help='the image password')
    parser.add_argument('-v',
                        '--verbose',
                        dest="verbose",
                        action="count",
                        default=0,
                        help="set verbosity level [default: %(default)s]")
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version=program_version_message)

    # Process arguments
    args = parser.parse_args()
    global verbose
    verbose = args.verbose

    if verbose > 0:
        print("Verbose mode on")
        print("start {} with args {}".format(program_name, str(args)))

    (user, password) = getLogin(args.loginfile, args.user, args.password)
    if user is None or password is None:
        raise ValueError("user or password resolved to None")
    pbclient = ProfitBricksService(user, password)

    usefile = args.infile
    print("read dc from {}".format(usefile))
    dcdef = read_dc_definition(usefile)
    if verbose > 0:
        print("using DC-DEF {}".format(json.dumps(dcdef)))

    # setup dc:
    #     + create empty dc
    #     + create volumes (unattached), map uuid to servers (custom dict)
    #     + create servers
    #     + create nics
    #     + attach volumes

    if 'custom' in dcdef and 'id' in dcdef['custom']:
        dc_id = dcdef['custom']['id']
        print("using existing DC w/ id {}".format(str(dc_id)))
    else:
        if args.dcname is not None:
            print("Overwrite DC name w/ '{}'".format(args.dcname))
            dcdef['properties']['name'] = args.dcname
        dc = getDatacenterObject(dcdef)
        # print("create DC {}".format(str(dc)))
        response = pbclient.create_datacenter(dc)
        dc_id = response['id']
        if 'custom' not in dcdef:
            dcdef['custom'] = dict()
        dcdef['custom']['id'] = dc_id
        result = wait_for_request(pbclient, response['requestId'])
        print("wait loop returned {}".format(result))
        tmpfile = usefile + ".tmp_postdc"
        write_dc_definition(dcdef, tmpfile)

    requests = []
    print("create Volumes {}".format(str(dc)))
    # we do NOT consider dangling volumes, only server-attached ones
    for server in dcdef['entities']['servers']['items']:
        print("- server {}".format(server['properties']['name']))
        if 'volumes' not in server['entities']:
            print(" server {} has no volumes".format(
                server['properties']['name']))
            continue
        for volume in server['entities']['volumes']['items']:
            if 'custom' in volume and 'id' in volume['custom']:
                vol_id = volume['custom']['id']
                print("using existing volume w/ id {}".format(str(vol_id)))
            else:
                dcvol = getVolumeObject(volume)
                print("OBJ: {}".format(str(dcvol)))
                response = pbclient.create_volume(dc_id, dcvol)
                volume.update({'custom': {'id': response['id']}})
                requests.append(response['requestId'])
        # end for(volume)
    # end for(server)
    if requests:
        result = wait_for_requests(pbclient,
                                   requests,
                                   initial_wait=10,
                                   scaleup=15)
        print("wait loop returned {}".format(str(result)))
        tmpfile = usefile + ".tmp_postvol"
        write_dc_definition(dcdef, tmpfile)
    else:
        print("all volumes existed already")

    requests = []
    print("create Servers {}".format(str(dc)))
    # we do NOT consider dangling volumes, only server-attached ones
    for server in dcdef['entities']['servers']['items']:
        print("- server {}".format(server['properties']['name']))
        if 'custom' in server and 'id' in server['custom']:
            srv_id = server['custom']['id']
            print("using existing server w/ id {}".format(str(srv_id)))
        else:
            dcsrv = getServerObject(server)
            print("OBJ: {}".format(str(dcsrv)))
            response = pbclient.create_server(dc_id, dcsrv)
            server.update({'custom': {'id': response['id']}})
            requests.append(response['requestId'])
    # end for(server)
    if requests:
        result = wait_for_requests(pbclient,
                                   requests,
                                   initial_wait=10,
                                   scaleup=15)
        print("wait loop returned {}".format(str(result)))
        tmpfile = usefile + ".tmp_postsrv"
        write_dc_definition(dcdef, tmpfile)
    else:
        print("all servers existed already")

# TODO: only do this if we have lan entities
    requests = []
    # Huuh, looks like we get unpredictable order for LANs!
    # Nope, order of creation determines the LAN id,
    # thus we better wait for each request
    print("create LANs {}".format(str(dc)))
    for lan in dcdef['entities']['lans']['items']:
        print("- lan {}".format(lan['properties']['name']))
        dclan = getLANObject(lan)
        print("OBJ: {}".format(str(dclan)))
        response = pbclient.create_lan(dc_id, dclan)
        lan.update({'custom': {'id': response['id']}})
        result = wait_for_request(pbclient, response['requestId'])
        print("wait loop returned {}".format(str(result)))
    # end for(lan)
    tmpfile = usefile + ".tmp_postlan"
    write_dc_definition(dcdef, tmpfile)

    requests = []
    # Attention:
    # NICs appear in OS in the order, they are created.
    # But DCD rearranges the display by ascending MAC addresses.
    # This does not change the OS order.
    # MAC may not be available from create response,
    # thus we wait for each request :-(
    print("create NICs {}".format(str(dc)))
    for server in dcdef['entities']['servers']['items']:
        print("- server {}".format(server['properties']['name']))
        srv_id = server['custom']['id']
        if 'nics' not in server['entities']:
            print(" server {} has no NICs".format(
                server['properties']['name']))
            continue
        macmap = dict()
        for nic in server['entities']['nics']['items']:
            dcnic = getNICObject(nic)
            response = pbclient.create_nic(dc_id, srv_id, dcnic)
            # print("dcnic response {}".format(str(response)))
            # mac = response['properties']['mac'] # we don't get it here !?
            nic_id = response['id']
            result = wait_for_request(pbclient, response['requestId'])
            print("wait loop returned {}".format(str(result)))
            response = pbclient.get_nic(dc_id, srv_id, nic_id, 2)
            mac = response['properties']['mac']
            print("dcnic has MAC {} for {}".format(mac, nic_id))
            macmap[mac] = nic_id
        # end for(nic)
        macs = sorted(macmap)
        print("macs will be displayed by DCD in th following order:")
        for mac in macs:
            print("mac {} -> id{}".format(mac, macmap[mac]))
    # end for(server)
    tmpfile = usefile + ".tmp_postnic"
    write_dc_definition(dcdef, tmpfile)

    requests = []
    # don't know if we get a race here too, so better wait for each request :-/
    print("attach volumes {}".format(str(dc)))
    for server in dcdef['entities']['servers']['items']:
        print("- server {}".format(server['properties']['name']))
        if 'volumes' not in server['entities']:
            print(" server {} has no volumes".format(
                server['properties']['name']))
            continue
        srv_id = server['custom']['id']
        for volume in server['entities']['volumes']['items']:
            print("OBJ: {}".format(volume['properties']['name']))
            response = pbclient.attach_volume(dc_id, srv_id,
                                              volume['custom']['id'])
            result = wait_for_request(pbclient, response['requestId'])
            print("wait loop returned {}".format(str(result)))
        # end for(volume)
    # end for(server)
    tmpfile = usefile + ".tmp_postatt"
    write_dc_definition(dcdef, tmpfile)

    # TODO: do we need to set boot volume for each server?
    # looks like it's working without

    return 0
Example #6
0
class TestFirewall(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.resource = resource()
        self.client = ProfitBricksService(username=configuration.USERNAME,
                                          password=configuration.PASSWORD,
                                          headers=configuration.HEADERS)

        # Create test datacenter.
        self.datacenter = self.client.create_datacenter(datacenter=Datacenter(
            **self.resource['datacenter']))
        self.client.wait_for_completion(self.datacenter)

        # Create test LAN.
        self.lan = self.client.create_lan(datacenter_id=self.datacenter['id'],
                                          lan=LAN(**self.resource['lan']))
        self.client.wait_for_completion(self.lan)

        # Create test server.
        self.server = self.client.create_server(
            datacenter_id=self.datacenter['id'],
            server=Server(**self.resource['server']))
        self.client.wait_for_completion(self.server)

        # Create test NIC1.
        nic1 = NIC(**self.resource['nic'])
        nic1.lan = self.lan['id']
        self.nic1 = self.client.create_nic(datacenter_id=self.datacenter['id'],
                                           server_id=self.server['id'],
                                           nic=nic1)
        self.client.wait_for_completion(self.nic1)

        # Create test Firewall Rule
        fwrule = FirewallRule(**self.resource['fwrule'])
        self.fwrule = self.client.create_firewall_rule(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic_id=self.nic1['id'],
            firewall_rule=fwrule)
        self.client.wait_for_completion(self.fwrule)

        # Create test Firewall Rule 2
        fwrule2 = FirewallRule(**self.resource['fwrule'])
        fwrule2.port_range_start = 8080
        fwrule2.port_range_end = 8080
        fwrule2.name = "8080"
        self.fwrule2 = self.client.create_firewall_rule(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic_id=self.nic1['id'],
            firewall_rule=fwrule2)
        self.client.wait_for_completion(self.fwrule2)

    @classmethod
    def tearDownClass(self):
        self.client.delete_datacenter(datacenter_id=self.datacenter['id'])

    def test_list_fwrules(self):
        fwrules = self.client.get_firewall_rules(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic_id=self.nic1['id'])

        self.assertGreater(len(fwrules), 0)
        self.assertIn(fwrules['items'][0]['id'],
                      (self.fwrule['id'], self.fwrule2['id']))
        self.assertEqual(fwrules['items'][0]['type'], 'firewall-rule')

    def test_get_fwrule(self):
        fwrule = self.client.get_firewall_rule(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic_id=self.nic1['id'],
            firewall_rule_id=self.fwrule['id'])

        self.assertEqual(fwrule['type'], 'firewall-rule')
        self.assertEqual(fwrule['id'], self.fwrule['id'])
        assertRegex(self, fwrule['id'], self.resource['uuid_match'])
        self.assertEqual(fwrule['properties']['name'],
                         self.fwrule['properties']['name'])
        self.assertEqual(fwrule['properties']['protocol'],
                         self.fwrule['properties']['protocol'])
        self.assertEqual(fwrule['properties']['sourceMac'],
                         self.fwrule['properties']['sourceMac'])
        self.assertIsNone(fwrule['properties']['sourceIp'])
        self.assertIsNone(fwrule['properties']['targetIp'])
        self.assertIsNone(fwrule['properties']['icmpCode'])
        self.assertIsNone(fwrule['properties']['icmpType'])
        self.assertEqual(fwrule['properties']['portRangeStart'],
                         self.fwrule['properties']['portRangeStart'])
        self.assertEqual(fwrule['properties']['portRangeEnd'],
                         self.fwrule['properties']['portRangeEnd'])

    def test_delete_fwrule(self):
        fwrule = self.client.delete_firewall_rule(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic_id=self.nic1['id'],
            firewall_rule_id=self.fwrule2['id'])

        self.assertTrue(fwrule)

    def test_update_fwrule(self):
        fwrule = self.client.update_firewall_rule(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic_id=self.nic1['id'],
            firewall_rule_id=self.fwrule['id'],
            name=self.resource['fwrule']['name'] + ' - RENAME')

        self.assertEqual(fwrule['type'], 'firewall-rule')
        self.assertEqual(fwrule['properties']['name'],
                         self.resource['fwrule']['name'] + ' - RENAME')

    def test_create_fwrule(self):
        self.assertEqual(self.fwrule['type'], 'firewall-rule')
        self.assertEqual(self.fwrule['properties']['name'],
                         self.resource['fwrule']['name'])
        self.assertEqual(self.fwrule['properties']['protocol'],
                         self.resource['fwrule']['protocol'])
        self.assertEqual(self.fwrule['properties']['sourceMac'],
                         self.resource['fwrule']['source_mac'])
        self.assertIsNone(self.fwrule['properties']['sourceIp'])
        self.assertIsNone(self.fwrule['properties']['targetIp'])
        self.assertIsNone(self.fwrule['properties']['icmpCode'])
        self.assertIsNone(self.fwrule['properties']['icmpType'])
        self.assertEqual(self.fwrule['properties']['portRangeStart'],
                         self.resource['fwrule']['port_range_start'])
        self.assertEqual(self.fwrule['properties']['portRangeEnd'],
                         self.resource['fwrule']['port_range_end'])

    def test_get_failure(self):
        try:
            self.client.get_firewall_rule(
                datacenter_id=self.datacenter['id'],
                server_id=self.server['id'],
                nic_id=self.nic1['id'],
                firewall_rule_id='00000000-0000-0000-0000-000000000000')
        except PBNotFoundError as e:
            self.assertIn(self.resource['not_found_error'],
                          e.content[0]['message'])

    def test_create_failure(self):
        try:
            fwrule = FirewallRule(name=self.resource['fwrule']['name'])
            self.client.create_firewall_rule(
                datacenter_id=self.datacenter['id'],
                server_id=self.server['id'],
                nic_id=self.nic1['id'],
                firewall_rule=fwrule)
        except PBError as e:
            self.assertIn(
                self.resource['missing_attribute_error'] % 'protocol',
                e.content[0]['message'])
from profitbricks.client import ProfitBricksService, LAN

lan_id = '4'
datacenter_id = '700e1cab-99b2-4c30-ba8c-1d273ddba022'

client = ProfitBricksService(
    username='******', password='******')

nics = ['<NIC-ID-1>', '<NIC-ID-2>']

i = LAN(
    name='public Lan 4',
    public=True,
    nics=nics)

response = client.create_lan(datacenter_id=datacenter_id, lan=i)

"""Create LAN
"""
from profitbricks.client import ProfitBricksService, LAN

lan_id = '4'
datacenter_id = '700e1cab-99b2-4c30-ba8c-1d273ddba022'

client = ProfitBricksService(
    username='******', password='******')

i = LAN(
    name='public Lan 4',
    public=True)
class TestLan(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.resource = resource()
        self.client = ProfitBricksService(
            username=configuration.USERNAME,
            password=configuration.PASSWORD,
            headers=configuration.HEADERS)

        # Create test datacenter.
        self.datacenter = self.client.create_datacenter(
            datacenter=Datacenter(**self.resource['datacenter']))
        wait_for_completion(self.client, self.datacenter, 'create_datacenter')

        # Create test LAN.
        self.lan = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=LAN(**self.resource['lan']))
        wait_for_completion(self.client, self.lan, 'create_lan')

        # Create test server.
        self.server = self.client.create_server(
            datacenter_id=self.datacenter['id'],
            server=Server(**self.resource['server']))
        wait_for_completion(self.client, self.server, 'create_server')

        # Create test NIC1.
        nic1 = NIC(**self.resource['nic'])
        nic1.lan = self.lan['id']
        self.nic1 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic1)
        wait_for_completion(self.client, self.nic1, 'create_nic1')

        # Create test NIC2.
        nic2 = NIC(**self.resource['nic'])
        nic2.lan = self.lan['id']
        self.nic2 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=nic2)
        wait_for_completion(self.client, self.nic2, 'create_nic2')

    @classmethod
    def tearDownClass(self):
        self.client.delete_datacenter(datacenter_id=self.datacenter['id'])

    def test_list_lans(self):
        lans = self.client.list_lans(datacenter_id=self.datacenter['id'])

        self.assertGreater(len(lans), 0)
        self.assertEqual(lans['items'][0]['type'], 'lan')
        self.assertIn(lans['items'][0]['id'], ('1', '2', '3'))
        self.assertEqual(lans['items'][0]['properties']['name'], self.resource['lan']['name'])
        self.assertTrue(lans['items'][0]['properties']['public'], self.resource['lan']['public'])

    def test_get_lan(self):
        lan = self.client.get_lan(datacenter_id=self.datacenter['id'], lan_id=self.lan['id'])

        self.assertEqual(lan['type'], 'lan')
        self.assertEqual(lan['id'], self.lan['id'])
        self.assertEqual(lan['properties']['name'], self.resource['lan']['name'])
        self.assertTrue(lan['properties']['public'], self.resource['lan']['public'])

    def test_delete_lan(self):
        lan = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=LAN(**self.resource['lan']))
        wait_for_completion(self.client, self.lan, 'create_lan')

        lan = self.client.delete_lan(datacenter_id=self.datacenter['id'], lan_id=lan['id'])

        self.assertTrue(lan)

    def test_update_lan(self):
        lan = self.client.update_lan(
            datacenter_id=self.datacenter['id'],
            lan_id=self.lan['id'],
            name=self.resource['lan']['name'] + ' RENAME',
            public=False)

        self.assertEqual(lan['type'], 'lan')
        self.assertEqual(lan['properties']['name'], self.resource['lan']['name'] + ' RENAME')
        self.assertFalse(lan['properties']['public'])

    def test_create_lan(self):
        self.assertEqual(self.lan['id'], '1')
        self.assertEqual(self.lan['type'], 'lan')
        self.assertEqual(self.lan['properties']['name'], self.resource['lan']['name'])
        self.assertEqual(self.lan['properties']['public'], self.resource['lan']['public'])

    def test_create_complex_lan(self):
        resource = NIC(**self.resource['nic'])

        nic1 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=resource)
        wait_for_completion(self.client, nic1, 'create_nic1')

        nic2 = self.client.create_nic(
            datacenter_id=self.datacenter['id'],
            server_id=self.server['id'],
            nic=resource)
        wait_for_completion(self.client, nic2, 'create_nic2')

        nics = [nic1['id'], nic2['id']]
        lan = LAN(nics=nics, **self.resource['lan'])

        response = self.client.create_lan(
            datacenter_id=self.datacenter['id'],
            lan=lan)
        wait_for_completion(self.client, response, 'create_lan')

        self.assertEqual(response['type'], 'lan')
        self.assertEqual(response['properties']['name'], self.resource['lan']['name'])
        self.assertTrue(response['properties']['public'])

    def test_get_lan_members(self):
        members = self.client.get_lan_members(
            datacenter_id=self.datacenter['id'],
            lan_id=self.lan['id'])

        self.assertGreater(len(members), 0)
        assertRegex(self, members['items'][0]['id'], self.resource['uuid_match'])
        self.assertEqual(members['items'][0]['type'], 'nic')
        self.assertEqual(members['items'][0]['properties']['name'], self.resource['nic']['name'])
        assertRegex(self, members['items'][0]['properties']['mac'], self.resource['mac_match'])
class TestLoadBalancer(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.resource = resource()
        self.client = ProfitBricksService(username=configuration.USERNAME,
                                          password=configuration.PASSWORD,
                                          headers=configuration.HEADERS)

        # Create test datacenter.
        self.datacenter = self.client.create_datacenter(datacenter=Datacenter(
            **self.resource['datacenter']))
        self.client.wait_for_completion(self.datacenter)

        # Create test LAN.
        self.lan = self.client.create_lan(datacenter_id=self.datacenter['id'],
                                          lan=LAN(**self.resource['lan']))
        self.client.wait_for_completion(self.lan)

        # Create test server.
        self.server = self.client.create_server(
            datacenter_id=self.datacenter['id'],
            server=Server(**self.resource['server']))
        self.client.wait_for_completion(self.server)

        # Create test NIC1.
        nic1 = NIC(**self.resource['nic'])
        nic1.lan = self.lan['id']
        self.nic1 = self.client.create_nic(datacenter_id=self.datacenter['id'],
                                           server_id=self.server['id'],
                                           nic=nic1)
        self.client.wait_for_completion(self.nic1)

        # Create test NIC2.
        # nic2 = NIC(**self.resource['nic'])
        # nic2.lan = self.lan['id']
        # self.nic2 = self.client.create_nic(
        #     datacenter_id=self.datacenter['id'],
        #     server_id=self.server['id'],
        #     nic=nic2)
        # self.client.wait_for_completion(self.nic2)

        # Create test LoadBalancer
        loadbalancer = LoadBalancer(**self.resource['loadbalancer'])
        loadbalancer.balancednics = [self.nic1['id']]
        self.loadbalancer = self.client.create_loadbalancer(
            datacenter_id=self.datacenter['id'], loadbalancer=loadbalancer)

        self.client.wait_for_completion(self.loadbalancer)

        # Create test LoadBalancer2
        loadbalancer2 = LoadBalancer(**self.resource['loadbalancer'])
        loadbalancer2.name = "Python SDK Test 2"
        self.loadbalancer2 = self.client.create_loadbalancer(
            datacenter_id=self.datacenter['id'], loadbalancer=loadbalancer2)

        self.client.wait_for_completion(self.loadbalancer2)

        # Create test LoadBalancer3
        loadbalancer3 = LoadBalancer(**self.resource['loadbalancer'])
        loadbalancer3.balancednics = [self.nic1['id']]
        loadbalancer3.name = "Python SDK Test 3"
        self.loadbalancer3 = self.client.create_loadbalancer(
            datacenter_id=self.datacenter['id'], loadbalancer=loadbalancer3)

        self.client.wait_for_completion(self.loadbalancer3)

    @classmethod
    def tearDownClass(self):
        self.client.delete_datacenter(datacenter_id=self.datacenter['id'])

    def test_list_loadbalancers(self):
        loadbalancers = self.client.list_loadbalancers(
            datacenter_id=self.datacenter['id'])

        self.assertGreater(len(loadbalancers), 0)
        self.assertIn(loadbalancers['items'][0]['id'],
                      (self.loadbalancer['id'], self.loadbalancer2['id'],
                       self.loadbalancer3['id']))
        self.assertEqual(loadbalancers['items'][0]['type'], 'loadbalancer')

    def test_get_loadbalancer(self):
        loadbalancer = self.client.get_loadbalancer(
            datacenter_id=self.datacenter['id'],
            loadbalancer_id=self.loadbalancer['id'])

        self.assertEqual(loadbalancer['type'], 'loadbalancer')
        self.assertEqual(loadbalancer['id'], self.loadbalancer['id'])
        assertRegex(self, loadbalancer['id'], self.resource['uuid_match'])
        self.assertEqual(loadbalancer['properties']['name'],
                         self.loadbalancer['properties']['name'])
        self.assertEqual(loadbalancer['properties']['dhcp'],
                         self.loadbalancer['properties']['dhcp'])
        self.assertIsNotNone(loadbalancer['properties']['ip'])

    def test_delete_loadbalancer(self):
        loadbalancer = self.client.delete_loadbalancer(
            datacenter_id=self.datacenter['id'],
            loadbalancer_id=self.loadbalancer2['id'])

        self.assertTrue(loadbalancer)

    def test_update_loadbalancer(self):
        loadbalancer = self.client.update_loadbalancer(
            datacenter_id=self.datacenter['id'],
            loadbalancer_id=self.loadbalancer['id'],
            name=self.resource['loadbalancer']['name'] + ' - RENAME')

        self.assertEqual(loadbalancer['type'], 'loadbalancer')
        self.assertEqual(loadbalancer['properties']['name'],
                         self.resource['loadbalancer']['name'] + ' - RENAME')

    def test_create_loadbalancer(self):
        self.assertEqual(self.loadbalancer['type'], 'loadbalancer')
        self.assertIsNotNone(self.loadbalancer['entities']['balancednics'])
        self.assertEqual(self.loadbalancer['properties']['name'],
                         self.resource['loadbalancer']['name'])
        self.assertEqual(self.loadbalancer['properties']['dhcp'],
                         self.resource['loadbalancer']['dhcp'])

    def test_associate_nic(self):
        associated_nic = self.client.add_loadbalanced_nics(
            datacenter_id=self.datacenter['id'],
            loadbalancer_id=self.loadbalancer2['id'],
            nic_id=self.nic1['id'])

        self.client.wait_for_completion(associated_nic)

        self.assertEqual(associated_nic['id'], self.nic1['id'])
        self.assertEqual(associated_nic['properties']['name'],
                         self.nic1['properties']['name'])

    def test_remove_nic(self):
        remove_nic = self.client.remove_loadbalanced_nic(
            datacenter_id=self.datacenter['id'],
            loadbalancer_id=self.loadbalancer3['id'],
            nic_id=self.nic1['id'])
        self.assertTrue(remove_nic)
        sleep(30)

    def test_list_balanced_nics(self):
        balanced_nics = self.client.get_loadbalancer_members(
            datacenter_id=self.datacenter['id'],
            loadbalancer_id=self.loadbalancer['id'])

        self.assertGreater(len(balanced_nics['items']), 0)
        self.assertEqual(balanced_nics['items'][0]['id'], self.nic1['id'])
        self.assertEqual(balanced_nics['items'][0]['type'], 'nic')

    def test_get_balanced_nic(self):
        balanced_nic = self.client.get_loadbalanced_nic(
            datacenter_id=self.datacenter['id'],
            loadbalancer_id=self.loadbalancer['id'],
            nic_id=self.nic1['id'])

        self.assertEqual(balanced_nic['id'], self.nic1['id'])
        self.assertEqual(balanced_nic['type'], 'nic')
        self.assertEqual(balanced_nic['properties']['name'],
                         self.nic1['properties']['name'])
        self.assertEqual(balanced_nic['properties']['dhcp'],
                         self.nic1['properties']['dhcp'])
        self.assertIsInstance(balanced_nic['properties']['nat'], bool)
        self.assertIsInstance(balanced_nic['properties']['firewallActive'],
                              bool)
        self.assertGreater(len(balanced_nic['properties']['ips']), 0)
        self.assertIsInstance(balanced_nic['properties']['lan'], int)
        assertRegex(self, balanced_nic['properties']['mac'],
                    self.resource['mac_match'])

    def test_get_failure(self):
        try:
            self.client.get_loadbalancer(
                datacenter_id=self.datacenter['id'],
                loadbalancer_id='00000000-0000-0000-0000-000000000000')
        except PBNotFoundError as e:
            self.assertIn(self.resource['not_found_error'],
                          e.content[0]['message'])

    def test_create_failure(self):
        try:
            self.client.create_loadbalancer(
                datacenter_id=self.datacenter['id'],
                loadbalancer=LoadBalancer())
        except PBError as e:
            self.assertIn(self.resource['missing_attribute_error'] % 'lan',
                          e.content[0]['message'])
class TestLan(unittest.TestCase):
    def setUp(self):
        self.lan = ProfitBricksService(username='******', password='******')

    def test_list_lans(self):
        lans = self.lan.list_lans(datacenter_id=datacenter_id)

        self.assertEqual(len(lans), 4)
        self.assertEqual(lans['items'][0]['id'], lan_id)
        self.assertEqual(lans['items'][0]['properties']['name'], 'public Lan 4')

    def test_get_lan(self):
        lan = self.lan.get_lan(datacenter_id=datacenter_id, lan_id=lan_id)

        self.assertEqual(lan['properties']['name'], 'public Lan 4')
        self.assertTrue(lan['properties']['public'])

    def test_delete_lan(self):
        lan = self.lan.delete_lan(datacenter_id=datacenter_id, lan_id=lan_id)
        self.assertTrue(lan)

    def test_update_lan(self):
        lan = self.lan.update_lan(datacenter_id=datacenter_id,
                                  lan_id=lan_id,
                                  name='new lan 4 name',
                                  public=False)

        self.assertEqual(lan['properties']['name'], 'public Lan 4')
        self.assertTrue(lan['properties']['public'])

    def test_create_lan(self):
        i = LAN(
            name='public Lan 4',
            public=True)

        response = self.lan.create_lan(datacenter_id=datacenter_id, lan=i)

        self.assertEqual(response['properties']['name'], 'public Lan 4')
        self.assertTrue(response['properties']['public'])

    def test_create_complex_lan(self):
        nics = ['<NIC-ID-1>', '<NIC-ID-2>']

        i = LAN(
            name='public Lan 4',
            public=True,
            nics=nics)

        response = self.lan.create_lan(datacenter_id=datacenter_id, lan=i)

        self.assertEqual(response['properties']['name'], 'public Lan 4')
        self.assertTrue(response['properties']['public'])

    def test_get_lan_members(self):
        members = self.lan.get_lan_members(datacenter_id=datacenter_id,
                                           lan_id=lan_id)

        self.assertEqual(len(members), 4)
        self.assertEqual(members['items'][0]['id'], '<NIC-ID>')
        self.assertEqual(members['items'][0]['properties']['name'], 'nic1')
        self.assertEqual(members['items'][0]['properties']['mac'], 'AB:21:23:09:78:C2')
def main(argv=None):
    """Parse command line options and create a server/volume composite."""

    if argv is None:
        argv = sys.argv
    else:
        sys.argv.extend(argv)

    program_name = os.path.basename(sys.argv[0])
    program_version = "v%s" % __version__
    program_build_date = str(__updated__)
    program_version_message = "%%(prog)s %s (%s)" % (program_version, program_build_date)
    program_shortdesc = __import__("__main__").__doc__.split("\n")[1]
    program_license = """%s

  Created by J. Buchhammer on %s.
  Copyright 2016 ProfitBricks GmbH. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.

USAGE
""" % (
        program_shortdesc,
        str(__date__),
    )
    # Setup argument parser
    parser = ArgumentParser(description=program_license, formatter_class=RawDescriptionHelpFormatter)
    parser.add_argument("-u", "--user", dest="user", help="the login name")
    parser.add_argument("-p", "--password", dest="password", help="the login password")
    parser.add_argument("-L", "--Login", dest="loginfile", default=None, help="the login file to use")
    parser.add_argument("-i", "--infile", dest="infile", default=None, required=True, help="the input file name")
    parser.add_argument("-D", "--DCname", dest="dcname", default=None, help="new datacenter name")
    # TODO: add/overwrite image password for creation
    #    parser.add_argument('-P', '--imagepassword', dest='imgpassword',
    #                        default=None, help='the image password')
    parser.add_argument(
        "-v", "--verbose", dest="verbose", action="count", default=0, help="set verbosity level [default: %(default)s]"
    )
    parser.add_argument("-V", "--version", action="version", version=program_version_message)

    # Process arguments
    args = parser.parse_args()
    global verbose
    verbose = args.verbose

    if verbose > 0:
        print("Verbose mode on")
        print("start {} with args {}".format(program_name, str(args)))

    (user, password) = getLogin(args.loginfile, args.user, args.password)
    if user is None or password is None:
        raise ValueError("user or password resolved to None")
    pbclient = ProfitBricksService(user, password)

    usefile = args.infile
    print("read dc from {}".format(usefile))
    dcdef = read_dc_definition(pbclient, usefile)
    if verbose > 0:
        print("using DC-DEF {}".format(json.dumps(dcdef)))

    # setup dc:
    #     + create empty dc
    #     + create volumes (unattached), map uuid to servers (custom dict)
    #     + create servers
    #     + create nics
    #     + attach volumes

    if "custom" in dcdef and "id" in dcdef["custom"]:
        dc_id = dcdef["custom"]["id"]
        print("using existing DC w/ id {}".format(str(dc_id)))
    else:
        if args.dcname is not None:
            print("Overwrite DC name w/ '{}'".format(args.dcname))
            dcdef["properties"]["name"] = args.dcname
        dc = getDatacenterObject(dcdef)
        # print("create DC {}".format(str(dc)))
        response = pbclient.create_datacenter(dc)
        dc_id = response["id"]
        if "custom" not in dcdef:
            dcdef["custom"] = dict()
        dcdef["custom"]["id"] = dc_id
        result = wait_for_request(pbclient, response["requestId"])
        print("wait loop returned {}".format(result))
        tmpfile = usefile + ".tmp_postdc"
        write_dc_definition(pbclient, dcdef, tmpfile)

    requests = []
    print("create Volumes {}".format(str(dc)))
    # we do NOT consider dangling volumes, only server-attached ones
    for server in dcdef["entities"]["servers"]["items"]:
        print("- server {}".format(server["properties"]["name"]))
        if "volumes" not in server["entities"]:
            print(" server {} has no volumes".format(server["properties"]["name"]))
            continue
        for volume in server["entities"]["volumes"]["items"]:
            if "custom" in volume and "id" in volume["custom"]:
                vol_id = volume["custom"]["id"]
                print("using existing volume w/ id {}".format(str(vol_id)))
            else:
                dcvol = getVolumeObject(volume)
                print("OBJ: {}".format(str(dcvol)))
                response = pbclient.create_volume(dc_id, dcvol)
                volume.update({"custom": {"id": response["id"]}})
                requests.append(response["requestId"])
        # end for(volume)
    # end for(server)
    if len(requests) != 0:
        result = wait_for_requests(pbclient, requests, initial_wait=10, scaleup=15)
        print("wait loop returned {}".format(str(result)))
        tmpfile = usefile + ".tmp_postvol"
        write_dc_definition(pbclient, dcdef, tmpfile)
    else:
        print("all volumes existed already")

    requests = []
    print("create Servers {}".format(str(dc)))
    # we do NOT consider dangling volumes, only server-attached ones
    for server in dcdef["entities"]["servers"]["items"]:
        print("- server {}".format(server["properties"]["name"]))
        if "custom" in server and "id" in server["custom"]:
            srv_id = server["custom"]["id"]
            print("using existing server w/ id {}".format(str(srv_id)))
        else:
            dcsrv = getServerObject(server)
            print("OBJ: {}".format(str(dcsrv)))
            response = pbclient.create_server(dc_id, dcsrv)
            server.update({"custom": {"id": response["id"]}})
            requests.append(response["requestId"])
    # end for(server)
    if len(requests) != 0:
        result = wait_for_requests(pbclient, requests, initial_wait=10, scaleup=15)
        print("wait loop returned {}".format(str(result)))
        tmpfile = usefile + ".tmp_postsrv"
        write_dc_definition(pbclient, dcdef, tmpfile)
    else:
        print("all servers existed already")

    # TODO: only do this if we have lan entities
    requests = []
    # Huuh, looks like we get unpredictable order for LANs!
    # Nope, order of creation determines the LAN id,
    # thus we better wait for each request
    print("create LANs {}".format(str(dc)))
    for lan in dcdef["entities"]["lans"]["items"]:
        print("- lan {}".format(lan["properties"]["name"]))
        dclan = getLANObject(lan)
        print("OBJ: {}".format(str(dclan)))
        response = pbclient.create_lan(dc_id, dclan)
        lan.update({"custom": {"id": response["id"]}})
        result = wait_for_request(pbclient, response["requestId"])
        print("wait loop returned {}".format(str(result)))
    # end for(lan)
    tmpfile = usefile + ".tmp_postlan"
    write_dc_definition(pbclient, dcdef, tmpfile)

    requests = []
    # Attention:
    # NICs appear in OS in the order, they are created.
    # But DCD rearranges the display by ascending MAC addresses.
    # This does not change the OS order.
    # MAC may not be available from create response,
    # thus we wait for each request :-(
    print("create NICs {}".format(str(dc)))
    for server in dcdef["entities"]["servers"]["items"]:
        print("- server {}".format(server["properties"]["name"]))
        srv_id = server["custom"]["id"]
        if "nics" not in server["entities"]:
            print(" server {} has no NICs".format(server["properties"]["name"]))
            continue
        macmap = dict()
        for nic in server["entities"]["nics"]["items"]:
            dcnic = getNICObject(nic)
            response = pbclient.create_nic(dc_id, srv_id, dcnic)
            # print("dcnic response {}".format(str(response)))
            # mac = response['properties']['mac'] # we don't get it here !?
            nic_id = response["id"]
            result = wait_for_request(pbclient, response["requestId"])
            print("wait loop returned {}".format(str(result)))
            response = pbclient.get_nic(dc_id, srv_id, nic_id, 2)
            mac = response["properties"]["mac"]
            print("dcnic has MAC {} for {}".format(mac, nic_id))
            macmap[mac] = nic_id
        # end for(nic)
        macs = sorted(macmap)
        print("macs will be displayed by DCD in th following order:")
        for mac in macs:
            print("mac {} -> id{}".format(mac, macmap[mac]))
    # end for(server)
    tmpfile = usefile + ".tmp_postnic"
    write_dc_definition(pbclient, dcdef, tmpfile)

    requests = []
    # don't know if we get a race here too, so better wait for each request :-/
    print("attach volumes {}".format(str(dc)))
    for server in dcdef["entities"]["servers"]["items"]:
        print("- server {}".format(server["properties"]["name"]))
        if "volumes" not in server["entities"]:
            print(" server {} has no volumes".format(server["properties"]["name"]))
            continue
        srv_id = server["custom"]["id"]
        for volume in server["entities"]["volumes"]["items"]:
            print("OBJ: {}".format(volume["properties"]["name"]))
            response = pbclient.attach_volume(dc_id, srv_id, volume["custom"]["id"])
            result = wait_for_request(pbclient, response["requestId"])
            print("wait loop returned {}".format(str(result)))
        # end for(volume)
    # end for(server)
    tmpfile = usefile + ".tmp_postatt"
    write_dc_definition(pbclient, dcdef, tmpfile)

    # TODO: do we need to set boot volume for each server?
    # looks like it's working without

    return 0