Merge "Extend AssignMachinesIP,fix Machine define"
diff --git a/README.rst b/README.rst
index 71c356d..fdfbb38 100644
--- a/README.rst
+++ b/README.rst
@@ -46,14 +46,16 @@
user: mirantis
token: "89EgtWkX45ddjMYpuL:SqVjxFG87Dr6kVf4Wp:5WLfbUgmm9XQtJxm3V2LUUy7bpCmqmnk"
fabrics:
- test-fabric:
- description: Test fabric
+ test-fabric1:
+ description: "Test fabric"
+ test-fabric2:
+ description: "Test fabric2"
subnets:
subnet1:
- fabric: test-fabric
+ fabric: test-fabric1
cidr: 2.2.3.0/24
gateway_ip: 2.2.3.2
- iprange:
+ iprange: # reserved range for DHCP\auto mapping
start: 2.2.3.20
end: 2.2.3.250
dhcp_snippets:
@@ -80,38 +82,29 @@
Version: GnuPG v2
mQENBFOpvpgBCADkP656H41i8fpplEEB8IeLhugyC2rTEwwSclb8tQNYtUiGdna9
- m38kb0OS2DDrEdtdQb2hWCnswxaAkUunb2qq18vd3dBvlnI+C4/xu5ksZZkRj+fW
- tArNR18V+2jkwcG26m8AxIrT+m4M6/bgnSfHTBtT5adNfVcTHqiT1JtCbQcXmwVw
- WbqS6v/LhcsBE//SHne4uBCK/GHxZHhQ5jz5h+3vWeV4gvxS3Xu6v1IlIpLDwUts
- kT1DumfynYnnZmWTGc6SYyIFXTPJLtnoWDb9OBdWgZxXfHEcBsKGha+bXO+m2tHA
- gNneN9i5f8oNxo5njrL8jkCckOpNpng18BKXABEBAAG0MlNhbHRTdGFjayBQYWNr
- YWdpbmcgVGVhbSA8cGFja2FnaW5nQHNhbHRzdGFjay5jb20+iQE4BBMBAgAiBQJT
- qb6YAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAOCKFJ3le/vhkqB/0Q
- WzELZf4d87WApzolLG+zpsJKtt/ueXL1W1KA7JILhXB1uyvVORt8uA9FjmE083o1
- yE66wCya7V8hjNn2lkLXboOUd1UTErlRg1GYbIt++VPscTxHxwpjDGxDB1/fiX2o
- nK5SEpuj4IeIPJVE/uLNAwZyfX8DArLVJ5h8lknwiHlQLGlnOu9ulEAejwAKt9CU
- 4oYTszYM4xrbtjB/fR+mPnYh2fBoQO4d/NQiejIEyd9IEEMd/03AJQBuMux62tjA
- /NwvQ9eqNgLw9NisFNHRWtP4jhAOsshv1WW+zPzu3ozoO+lLHixUIz7fqRk38q8Q
- 9oNR31KvrkSNrFbA3D89uQENBFOpvpgBCADJ79iH10AfAfpTBEQwa6vzUI3Eltqb
- 9aZ0xbZV8V/8pnuU7rqM7Z+nJgldibFk4gFG2bHCG1C5aEH/FmcOMvTKDhJSFQUx
- uhgxttMArXm2c22OSy1hpsnVG68G32Nag/QFEJ++3hNnbyGZpHnPiYgej3FrerQJ
- zv456wIsxRDMvJ1NZQB3twoCqwapC6FJE2hukSdWB5yCYpWlZJXBKzlYz/gwD/Fr
- GL578WrLhKw3UvnJmlpqQaDKwmV2s7MsoZogC6wkHE92kGPG2GmoRD3ALjmCvN1E
- PsIsQGnwpcXsRpYVCoW7e2nW4wUf7IkFZ94yOCmUq6WreWI4NggRcFC5ABEBAAGJ
- AR8EGAECAAkFAlOpvpgCGwwACgkQDgihSd5Xv74/NggA08kEdBkiWWwJZUZEy7cK
- WWcgjnRuOHd4rPeT+vQbOWGu6x4bxuVf9aTiYkf7ZjVF2lPn97EXOEGFWPZeZbH4
- vdRFH9jMtP+rrLt6+3c9j0M8SIJYwBL1+CNpEC/BuHj/Ra/cmnG5ZNhYebm76h5f
- T9iPW9fFww36FzFka4VPlvA4oB7ebBtquFg3sdQNU/MmTVV4jPFWXxh4oRDDR+8N
- 1bcPnbB11b5ary99F/mqr7RgQ+YFF0uKRE3SKa7a+6cIuHEZ7Za+zhPaQlzAOZlx
+ ......
fuBmScum8uQTrEF5+Um5zkwC7EXTdH1co/+/V/fpOtxIg4XO4kcugZefVm5ERfVS
MA==
=dtMN
-----END PGP PUBLIC KEY BLOCK-----"
enabled: true
machines:
- machine1:
- interface:
- mac: "11:22:33:44:55:66"
+ machine1_new_schema:
+ pxe_interface_mac: "11:22:33:44:55:66" # Node will be identified by those mac
+ interfaces:
+ nic01: # could be any, used for iterate only
+ type: eth # NotImplemented
+ name: eth0 # Override default nic name. Interface to rename will be identified by mac
+ mac: "11:22:33:44:55:66"
+ mode: "static"
+ ip: "2.2.3.19" # ip should be out of reserved subnet range, but still in subnet range
+ subnet: "subnet1"
+ gateway: "2.2.3.2" # override default gateway from subnet
+ nic02:
+ type: eth # Not-implemented
+ mac: "11:22:33:44:55:78"
+ subnet: "subnet2"
+ mode: "dhcp"
power_parameters:
power_type: ipmi
power_address: '192.168.10.10'
@@ -119,6 +112,23 @@
power_password: bmc_password
#Optional (for legacy HW)
power_driver: LAN
+ distro_series: xenial
+ hwe_kernel: hwe-16.04
+ machine1_old_schema:
+ interface:
+ mac: "11:22:33:44:55:88" # Node will be identified by those mac
+ mode: "static"
+ ip: "2.2.3.15"
+ subnet: "subnet1"
+ gateway: "2.2.3.2"
+ power_parameters:
+ power_type: ipmi
+ power_address: '192.168.10.10'
+ power_user: bmc_user
+ power_password: bmc_password
+ #Optional (for legacy HW)
+ power_driver: LAN
+ # FIXME: that's should be moved into another,livirt example.
# Used in case of power_type: virsh
power_id: my_libvirt_vm_name
distro_series: xenial
@@ -150,7 +160,7 @@
enable_http_proxy: true
default_min_hwe_kernel: ''
sshprefs:
- - 'ssh-rsa ASDFOSADFISdfasdfasjdklfjasdJFASDJfASdf923@AAAAB3NzaC1yc2EAAAADAQABAAACAQCv8ISOESGgYUOycYw1SAs/SfHTqtSCTephD/7o2+mEZO53xN98sChiFscFaPA2ZSMoZbJ6MQLKcWKMK2OaTdNSAvn4UE4T6VP0ccdumHDNRwO3f6LptvXr9NR5Wocz2KAgptk+uaA8ytM0Aj9NT0UlfjAXkKnoKyNq6yG+lx4HpwolVaFSlqRXf/iuHpCrspv/u1NW7ReMElJoXv+0zZ7Ow0ZylISdYkaqbV8QatCb17v1+xX03xLsZigfugce/8CDsibSYvJv+Hli5CCBsKgfFqLy4R5vGxiLSVzG/asdjalskjdlkasjdasd/asdajsdkjalaksdjfasd/fa/sdf/asd/fas/dfsadf blah@blah'
+ - 'ssh-rsa ASD.........dfsadf blah@blah'
@@ -169,29 +179,7 @@
Version: GnuPG v2
mQENBFOpvpgBCADkP656H41i8fpplEEB8IeLhugyC2rTEwwSclb8tQNYtUiGdna9
- m38kb0OS2DDrEdtdQb2hWCnswxaAkUunb2qq18vd3dBvlnI+C4/xu5ksZZkRj+fW
- tArNR18V+2jkwcG26m8AxIrT+m4M6/bgnSfHTBtT5adNfVcTHqiT1JtCbQcXmwVw
- WbqS6v/LhcsBE//SHne4uBCK/GHxZHhQ5jz5h+3vWeV4gvxS3Xu6v1IlIpLDwUts
- kT1DumfynYnnZmWTGc6SYyIFXTPJLtnoWDb9OBdWgZxXfHEcBsKGha+bXO+m2tHA
- gNneN9i5f8oNxo5njrL8jkCckOpNpng18BKXABEBAAG0MlNhbHRTdGFjayBQYWNr
- YWdpbmcgVGVhbSA8cGFja2FnaW5nQHNhbHRzdGFjay5jb20+iQE4BBMBAgAiBQJT
- qb6YAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAOCKFJ3le/vhkqB/0Q
- WzELZf4d87WApzolLG+zpsJKtt/ueXL1W1KA7JILhXB1uyvVORt8uA9FjmE083o1
- yE66wCya7V8hjNn2lkLXboOUd1UTErlRg1GYbIt++VPscTxHxwpjDGxDB1/fiX2o
- nK5SEpuj4IeIPJVE/uLNAwZyfX8DArLVJ5h8lknwiHlQLGlnOu9ulEAejwAKt9CU
- 4oYTszYM4xrbtjB/fR+mPnYh2fBoQO4d/NQiejIEyd9IEEMd/03AJQBuMux62tjA
- /NwvQ9eqNgLw9NisFNHRWtP4jhAOsshv1WW+zPzu3ozoO+lLHixUIz7fqRk38q8Q
- 9oNR31KvrkSNrFbA3D89uQENBFOpvpgBCADJ79iH10AfAfpTBEQwa6vzUI3Eltqb
- 9aZ0xbZV8V/8pnuU7rqM7Z+nJgldibFk4gFG2bHCG1C5aEH/FmcOMvTKDhJSFQUx
- uhgxttMArXm2c22OSy1hpsnVG68G32Nag/QFEJ++3hNnbyGZpHnPiYgej3FrerQJ
- zv456wIsxRDMvJ1NZQB3twoCqwapC6FJE2hukSdWB5yCYpWlZJXBKzlYz/gwD/Fr
- GL578WrLhKw3UvnJmlpqQaDKwmV2s7MsoZogC6wkHE92kGPG2GmoRD3ALjmCvN1E
- PsIsQGnwpcXsRpYVCoW7e2nW4wUf7IkFZ94yOCmUq6WreWI4NggRcFC5ABEBAAGJ
- AR8EGAECAAkFAlOpvpgCGwwACgkQDgihSd5Xv74/NggA08kEdBkiWWwJZUZEy7cK
- WWcgjnRuOHd4rPeT+vQbOWGu6x4bxuVf9aTiYkf7ZjVF2lPn97EXOEGFWPZeZbH4
- vdRFH9jMtP+rrLt6+3c9j0M8SIJYwBL1+CNpEC/BuHj/Ra/cmnG5ZNhYebm76h5f
- T9iPW9fFww36FzFka4VPlvA4oB7ebBtquFg3sdQNU/MmTVV4jPFWXxh4oRDDR+8N
- 1bcPnbB11b5ary99F/mqr7RgQ+YFF0uKRE3SKa7a+6cIuHEZ7Za+zhPaQlzAOZlx
+ .....
fuBmScum8uQTrEF5+Um5zkwC7EXTdH1co/+/V/fpOtxIg4XO4kcugZefVm5ERfVS
MA==
=dtMN
@@ -269,7 +257,17 @@
- cmd: maas_login_admin
...
-List of avaibled `req_status` defined in global variable:
+List of available `req_status` defined in global variable:
+
+.. code-block:: python
+
+ STATUS_NAME_DICT = dict([
+ (0, 'New'), (1, 'Commissioning'), (2, 'Failed commissioning'),
+ (3, 'Missing'), (4, 'Ready'), (5, 'Reserved'), (10, 'Allocated'),
+ (9, 'Deploying'), (6, 'Deployed'), (7, 'Retired'), (8, 'Broken'),
+ (11, 'Failed deployment'), (12, 'Releasing'),
+ (13, 'Releasing failed'), (14, 'Disk erasing'),
+ (15, 'Failed disk erasing')])
Read more
diff --git a/_modules/maas.py b/_modules/maas.py
index 1df4698..ee110c8 100644
--- a/_modules/maas.py
+++ b/_modules/maas.py
@@ -100,6 +100,9 @@
None, **data).read()
def process(self, objects_name=None):
+ # FIXME: probably, should be extended with "skipped" return.
+ # For example, currently "DEPLOYED" nodes are skipped, and no changes
+ # applied - but they fall into 'updated' list.
ret = {
'success': [],
'errors': {},
@@ -151,6 +154,8 @@
self.send(data)
ret['success'].append(name)
except urllib2.HTTPError as e:
+ # FIXME add exception's for response:
+ # '{"mode": ["Interface is already set to DHCP."]}
etxt = e.read()
LOG.error('Failed for object %s reason %s', name, etxt)
ret['errors'][name] = str(etxt)
@@ -368,10 +373,19 @@
def fill_data(self, name, machine_data):
power_data = machine_data['power_parameters']
+ machine_pxe_mac = machine_data.get('pxe_interface_mac', None)
+ if machine_data.get("interface", None):
+ LOG.warning(
+ "Old machine-describe detected! "
+ "Please read documentation for "
+ "'salt-formulas/maas' for migration!")
+ machine_pxe_mac = machine_data['interface'].get('mac', None)
+ if not machine_pxe_mac:
+ raise Exception("PXE MAC for machine:{} not defined".format(name))
data = {
'hostname': name,
'architecture': machine_data.get('architecture', 'amd64/generic'),
- 'mac_addresses': machine_data['interface']['mac'],
+ 'mac_addresses': machine_pxe_mac,
'power_type': machine_data.get('power_type', 'ipmi'),
'power_parameters_power_address': power_data['power_address'],
}
@@ -399,6 +413,7 @@
class AssignMachinesIP(MaasObject):
+ # FIXME
READY = 4
DEPLOYED = 6
@@ -414,27 +429,153 @@
self._extra_data_urls = {'machines': (u'api/2.0/machines/',
None, 'hostname')}
- def fill_data(self, name, data, machines):
- interface = data['interface']
- machine = machines[name]
- if machine['status'] == self.DEPLOYED:
- return
- if machine['status'] != self.READY:
- raise Exception('Machine:{} not in READY state'.format(name))
- if 'ip' not in interface:
- return
+ def _data_old(self, _interface, _machine):
+ """
+ _interface = {
+ "mac": "11:22:33:44:55:77",
+ "mode": "STATIC",
+ "ip": "2.2.3.15",
+ "subnet": "subnet1",
+ "gateway": "2.2.3.2",
+ }
+ :param data:
+ :return:
+ """
data = {
'mode': 'STATIC',
- 'subnet': str(interface.get('subnet')),
- 'ip_address': str(interface.get('ip')),
+ 'subnet': str(_interface.get('subnet')),
+ 'ip_address': str(_interface.get('ip')),
}
- if 'default_gateway' in interface:
- data['default_gateway'] = interface.get('gateway')
+ if 'gateway' in _interface:
+ data['default_gateway'] = _interface.get('gateway')
data['force'] = '1'
- data['system_id'] = str(machine['system_id'])
- data['interface_id'] = str(machine['interface_set'][0]['id'])
+ data['system_id'] = str(_machine['system_id'])
+ data['interface_id'] = str(_machine['interface_set'][0]['id'])
return data
+ def _get_nic_id_by_mac(self, machine, req_mac=None):
+ data = {}
+ for nic in machine['interface_set']:
+ data[nic['mac_address']] = nic['id']
+ if req_mac:
+ if req_mac in data.keys():
+ return data[req_mac]
+ else:
+ raise Exception('NIC with mac:{} not found at '
+ 'node:{}'.format(req_mac, machine['fqdn']))
+ return data
+
+ def _disconnect_all_nic(self, machine):
+ """
+ Maas will fail, in case same config's will be to apply
+ on different interfaces. In same time - not possible to push
+ whole network schema at once. Before configuring - need to clean-up
+ everything
+ :param machine:
+ :return:
+ """
+ for nic in machine['interface_set']:
+ LOG.debug("Disconnecting interface:{}".format(nic['mac_address']))
+ try:
+ self._maas.post(
+ u'/api/2.0/nodes/{}/interfaces/{}/'.format(
+ machine['system_id'], nic['id']), 'disconnect')
+ except Exception as e:
+ LOG.error("Failed to disconnect interface:{} on node:{}".format(
+ nic['mac_address'], machine['fqdn']))
+ raise Exception(str(e))
+
+ def _process_interface(self, nic_data, machine):
+ """
+ Process exactly one interface:
+ - update interface
+ - link to network
+ These functions are self-complementary, and do not require an
+ external "process" method. Those broke old-MaasObject logic,
+ though make functions more simple in case iterable tasks.
+ """
+ nic_id = self._get_nic_id_by_mac(machine, nic_data['mac'])
+
+ # Process op=link_subnet
+ link_data = {}
+ _mode = nic_data.get('mode', 'AUTO').upper()
+ if _mode == 'STATIC':
+ link_data = {
+ 'mode': 'STATIC',
+ 'subnet': str(nic_data.get('subnet')),
+ 'ip_address': str(nic_data.get('ip')),
+ 'default_gateway': str(nic_data.get('gateway', "")),
+ }
+ elif _mode == 'DHCP':
+ link_data = {
+ 'mode': 'DHCP',
+ 'subnet': str(nic_data.get('subnet')),
+ }
+ elif _mode == 'AUTO':
+ link_data = {'mode': 'AUTO',
+ 'default_gateway': str(nic_data.get('gateway', "")), }
+ elif _mode in ('LINK_UP', 'UNCONFIGURED'):
+ link_data = {'mode': 'LINK_UP'}
+ else:
+ raise Exception('Wrong IP mode:{}'
+ ' for node:{}'.format(_mode, machine['fqdn']))
+ link_data['force'] = str(1)
+
+ physical_data = {"name": nic_data.get("name", ""),
+ "tags": nic_data.get('tags', ""),
+ "vlan": nic_data.get('vlan', "")}
+
+ try:
+ # Cleanup-old definition
+ LOG.debug("Processing {}:{},{}".format(nic_data['mac'], link_data,
+ physical_data))
+ # "link_subnet" and "fill all other data" - its 2 different
+ # operations. So, first we update NIC:
+ self._maas.put(
+ u'/api/2.0/nodes/{}/interfaces/{}/'.format(machine['system_id'],
+ nic_id),
+ **physical_data)
+ # And then, link subnet configuration:
+ self._maas.post(
+ u'/api/2.0/nodes/{}/interfaces/{}/'.format(machine['system_id'],
+ nic_id),
+ 'link_subnet', **link_data)
+ except Exception as e:
+ LOG.error("Failed to process interface:{} on node:{}".format(
+ nic_data['mac'], machine['fqdn']))
+ raise Exception(str(e))
+
+ def fill_data(self, name, data, machines):
+ machine = machines[name]
+ if machine['status'] == self.DEPLOYED:
+ LOG.debug("Skipping node:{} "
+ "since it in status:DEPLOYED".format(name))
+ return
+ if machine['status'] != self.READY:
+ raise Exception('Machine:{} not in status:READY'.format(name))
+ # backward comparability, for old schema
+ if data.get("interface", None):
+ if 'ip' not in data["interface"]:
+ LOG.info("No IP NIC definition for:{}".format(name))
+ return
+ LOG.warning(
+ "Old machine-describe detected! "
+ "Please read documentation "
+ "'salt-formulas/maas' for migration!")
+ return self._data_old(data['interface'], machines[name])
+ # NewSchema processing:
+ # Warning: old-style MaasObject.process still be called, but
+ # with empty data for process.
+ interfaces = data.get('interfaces', {})
+ if len(interfaces.keys()) == 0:
+ LOG.info("No IP NIC definition for:{}".format(name))
+ return
+ LOG.info('%s for %s', self.__class__.__name__.lower(),
+ machine['fqdn'])
+ self._disconnect_all_nic(machine)
+ for key, value in sorted(interfaces.iteritems()):
+ self._process_interface(value, machine)
+
class DeployMachines(MaasObject):
# FIXME
@@ -773,6 +914,10 @@
def process_assign_machines_ip(*args):
+ """
+ Manage interface configurations.
+ See readme.rst for more info
+ """
return AssignMachinesIP().process(*args)