| |
| # Copyright 2017-present Open Networking Foundation |
| # |
| # 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. |
| |
| |
| import os |
| import base64 |
| import struct |
| import socket |
| from netaddr import IPAddress, IPNetwork |
| from synchronizers.openstack.openstacksyncstep import OpenStackSyncStep |
| from synchronizers.new_base.syncstep import * |
| from xos.logger import observer_logger as logger |
| from synchronizers.new_base.ansible_helper import * |
| from synchronizers.new_base.modelaccessor import * |
| |
| class SyncControllerNetworks(OpenStackSyncStep): |
| requested_interval = 0 |
| provides=[Network] |
| observes=ControllerNetwork |
| playbook='sync_controller_networks.yaml' |
| |
| def alloc_subnet(self, uuid): |
| # 16 bits only |
| uuid_masked = uuid & 0xffff |
| a = 10 |
| b = uuid_masked >> 8 |
| c = uuid_masked & 0xff |
| d = 0 |
| |
| cidr = '%d.%d.%d.%d/24'%(a,b,c,d) |
| return cidr |
| |
| def alloc_gateway(self, subnet): |
| # given a CIDR, allocate a default gateway using the .1 address within |
| # the subnet. |
| # 10.123.0.0/24 --> 10.123.0.1 |
| # 207.141.192.128/28 --> 207.141.192.129 |
| (network, bits) = subnet.split("/") |
| network=network.strip() |
| bits=int(bits.strip()) |
| netmask = (~(pow(2,32-bits)-1) & 0xFFFFFFFF) |
| ip = struct.unpack("!L", socket.inet_aton(network))[0] |
| ip = ip & netmask | 1 |
| return socket.inet_ntoa(struct.pack("!L", ip)) |
| |
| def get_segmentation_id(self, controller_network): |
| driver = self.driver.admin_driver(controller = controller_network.controller) |
| neutron_network = driver.shell.neutron.list_networks(controller_network.network_id)["networks"][0] |
| if "provider:segmentation_id" in neutron_network: |
| return neutron_network["provider:segmentation_id"] |
| else: |
| return None |
| |
| def save_controller_network(self, controller_network): |
| network_name = controller_network.network.name |
| subnet_name = '%s-%d'%(network_name,controller_network.pk) |
| if controller_network.subnet and controller_network.subnet.strip(): |
| # If a subnet is already specified (pass in by the creator), then |
| # use that rather than auto-generating one. |
| cidr = controller_network.subnet.strip() |
| print "CIDR_MS", cidr |
| else: |
| cidr = self.alloc_subnet(controller_network.pk) |
| print "CIDR_AMS", cidr |
| |
| if controller_network.network.start_ip and controller_network.network.start_ip.strip(): |
| start_ip = controller_network.network.start_ip.strip() |
| else: |
| start_ip = None |
| |
| if controller_network.network.end_ip and controller_network.network.end_ip.strip(): |
| end_ip = controller_network.network.end_ip.strip() |
| else: |
| end_ip = None |
| |
| slice = controller_network.network.owner |
| controller_network.subnet = cidr |
| |
| controller_network.gateway = self.alloc_gateway(cidr) |
| |
| network_fields = { |
| 'name':network_name, |
| 'subnet_name':subnet_name, |
| 'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name), |
| 'cidr':cidr, |
| 'gateway': controller_network.gateway, |
| 'start_ip':start_ip, |
| 'end_ip':end_ip, |
| 'use_vtn':True, |
| 'delete':False |
| } |
| |
| if slice.trust_domain is not None: |
| # New Openstack modeling |
| # TODO(smbaker): Should use slice credentials rather than admin credentials |
| os_service = slice.trust_domain.owner.leaf_model |
| network_fields["endpoint"] = os_service.auth_url |
| network_fields["admin_user"] = os_service.admin_user |
| network_fields["admin_password"] = os_service.admin_password |
| network_fields["admin_project"] = "admin" |
| network_fields["domain"] = "Default" |
| else: |
| # Old OpenStack modeling |
| network_fields['endpoint'] = controller_network.controller.auth_url |
| network_fields['admin_user'] = slice.creator.email |
| network_fields['admin_password'] = slice.creator.remote_password |
| network_fields['admin_project'] = slice.name |
| network_fields['domain'] = controller_network.controller.domain |
| |
| return network_fields |
| |
| def map_sync_outputs(self, controller_network,res): |
| network_id = res[0]['network']['id'] |
| subnet_id = res[1]['subnet']['id'] |
| controller_network.net_id = network_id |
| controller_network.subnet_id = subnet_id |
| controller_network.backend_status = 'OK' |
| controller_network.backend_code = 1 |
| if not controller_network.segmentation_id: |
| controller_network.segmentation_id = str(self.get_segmentation_id(controller_network)) |
| controller_network.save() |
| |
| |
| def map_sync_inputs(self, controller_network): |
| # make sure to not sync a shared network |
| if (controller_network.network.template.shared_network_name or controller_network.network.template.shared_network_id): |
| return SyncStep.SYNC_WITHOUT_RUNNING |
| |
| if not controller_network.controller.admin_user: |
| logger.info("controller %r has no admin_user, skipping" % controller_network.controller) |
| return |
| |
| if controller_network.network.owner and controller_network.network.owner.creator: |
| return self.save_controller_network(controller_network) |
| else: |
| raise Exception('Could not save network controller %s'%controller_network) |
| |
| def map_delete_inputs(self, controller_network): |
| # make sure to not delete a shared network |
| if (controller_network.network.template.shared_network_name or controller_network.network.template.shared_network_id): |
| return |
| |
| try: |
| slice = controller_network.network.owner # XXX: FIXME!! |
| except: |
| raise Exception('Could not get slice for Network %s'%controller_network.network.name) |
| |
| network_name = controller_network.network.name |
| subnet_name = '%s-%d'%(network_name,controller_network.pk) |
| cidr = controller_network.subnet |
| network_fields = { |
| 'name':network_name, |
| 'subnet_name':subnet_name, |
| 'ansible_tag':'%s-%s@%s'%(network_name,slice.slicename,controller_network.controller.name), |
| 'cidr':cidr, |
| 'delete':True |
| } |
| |
| if slice.trust_domain is not None: |
| # New Openstack modeling |
| # TODO(smbaker): Should use slice credentials rather than admin credentials |
| os_service = slice.trust_domain.owner.leaf_model |
| network_fields["endpoint"] = os_service.auth_url |
| network_fields["admin_user"] = os_service.admin_user |
| network_fields["admin_password"] = os_service.admin_password |
| network_fields["admin_project"] = "admin" |
| network_fields["domain"] = "Default" |
| else: |
| # Old OpenStack modeling |
| network_fields['endpoint'] = controller_network.controller.auth_url |
| network_fields['admin_user'] = slice.creator.email |
| network_fields['admin_password'] = slice.creator.remote_password |
| network_fields['admin_project'] = slice.name |
| network_fields['domain'] = controller_network.controller.domain |
| |
| return network_fields |
| |