drydock/python/drydock_provisioner/drivers/node/maasdriver/models/vlan.py

166 lines
5.3 KiB
Python

# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Models representing MaaS VLAN resources."""
import drydock_provisioner.drivers.node.maasdriver.models.base as model_base
from drydock_provisioner.drivers.node.maasdriver.errors import RackControllerConflict
class Vlan(model_base.ResourceBase):
resource_url = 'fabrics/{fabric_id}/vlans/{api_id}/'
fields = [
'resource_id',
'name',
'description',
'vid',
'fabric_id',
'dhcp_on',
'mtu',
'primary_rack',
'secondary_rack',
'relay_vlan',
]
json_fields = [
'name',
'description',
'vid',
'dhcp_on',
'mtu',
'primary_rack',
'secondary_rack',
'relay_vlan',
]
def __init__(self, api_client, **kwargs):
super(Vlan, self).__init__(api_client, **kwargs)
if self.vid is None:
self.vid = 0
# the MaaS API decided that the URL endpoint for VLANs should use
# the VLAN tag (vid) rather than the resource ID. So to update the
# vid, we have to keep two copies so that the resource_url
# is accurate for updates
self.api_id = self.vid
def update(self):
super(Vlan, self).update()
self.api_id = self.vid
def set_vid(self, new_vid):
if new_vid is None:
self.vid = 0
else:
self.vid = int(new_vid)
def add_rack_controller(self, rack_id):
"""Add a rack controller that manages DHCP on this VLAN.
Whichever of primary_rack or secondary_rack, in that order,
is not set - set to ``rack_id``. If both are already set
raise RackControllerConflict exception.
"""
if not self.primary_rack or self.primary_rack == rack_id:
self.logger.debug("Setting primary DHCP controller %s on VLAN %s", rack_id, self.resource_id)
self.primary_rack = rack_id
elif not self.secondary_rack or self.secondary_rack == rack_id:
self.logger.debug("Setting secondary DHCP controller %s on VLAN %s.", rack_id, self.resource_id)
self.secondary_rack = rack_id
else:
raise RackControllerConflict(
"Both primary and secondary rack controllers already set.")
def reset_dhcp_mgmt(self, commit=False):
"""Reset the DHCP control for this VLAN.
Reset the settings in the model impacting DHCP control on this
VLAN. Only commit these changes to the MAAS API if ``commit`` is
True.
:param bool commit: Whether to commit reset to MAAS API
"""
self.logger.debug("Resetting DHCP control on VLAN %s.", self.resource_id)
self.relay_vlan = None
self.dhcp_on = False
self.primary_rack = None
self.secondary_rack = None
if commit:
self.update()
def set_dhcp_relay(self, relay_vlan_id):
self.relay_vlan = relay_vlan_id
self.update()
@classmethod
def from_dict(cls, api_client, obj_dict):
"""
Because MaaS decides to replace the relay_vlan id with the
representation of the VLAN, we must reverse it for a true
representation of the resource
"""
refined_dict = {k: obj_dict.get(k, None) for k in cls.fields}
if 'id' in obj_dict.keys():
refined_dict['resource_id'] = obj_dict.get('id')
if isinstance(refined_dict.get('relay_vlan', None), dict):
refined_dict['relay_vlan'] = refined_dict['relay_vlan']['id']
i = cls(api_client, **refined_dict)
return i
class Vlans(model_base.ResourceCollectionBase):
collection_url = 'fabrics/{fabric_id}/vlans/'
collection_resource = Vlan
def __init__(self, api_client, **kwargs):
super(Vlans, self).__init__(api_client)
self.fabric_id = kwargs.get('fabric_id', None)
"""
Create a new resource in this collection in MaaS
def add(self, res):
#MAAS API doesn't support all attributes in POST, so create and
# then promptly update via PUT
min_fields = {
'name': res.name,
'description': getattr(res, 'description', None),
}
if getattr(res, 'vid', None) is None:
min_fields['vid'] = 0
else:
min_fields['vid'] = res.vid
url = self.interpolate_url()
resp = self.api_client.post(url, files=min_fields)
# Check on initial POST creation
if resp.status_code == 200:
resp_json = resp.json()
res.id = resp_json.get('id')
# Submit PUT for additonal fields
res.update()
return res
raise errors.DriverError("Failed updating MAAS url %s - return code %s\n%s"
% (url, resp.status_code, resp.text))
"""