boyoung | f42f2bf | 2017-10-16 19:06:30 +0900 | [diff] [blame^] | 1 | |
| 2 | # Copyright 2017-present Open Networking Foundation |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | |
| 17 | import os |
| 18 | import base64 |
| 19 | import struct |
| 20 | import socket |
| 21 | from netaddr import IPAddress, IPNetwork |
| 22 | from synchronizers.swarm.swarmsyncstep import SwarmSyncStep |
| 23 | from synchronizers.new_base.syncstep import * |
| 24 | from xos.logger import observer_logger as logger |
| 25 | from synchronizers.new_base.ansible_helper import * |
| 26 | from synchronizers.new_base.modelaccessor import * |
| 27 | |
| 28 | import synchronizers.swarm.swarmlog as slog |
| 29 | |
| 30 | |
| 31 | class SyncControllerNetworks(SwarmSyncStep): |
| 32 | requested_interval = 0 |
| 33 | provides=[Network] |
| 34 | observes=ControllerNetwork |
| 35 | playbook='sync_controller_networks.yaml' |
| 36 | |
| 37 | def alloc_subnet(self, uuid): |
| 38 | slog.debug("uuid: %s" % str(uuid)) |
| 39 | # use 16 bits only |
| 40 | uuid_masked = uuid & 0xffff |
| 41 | a = 10 |
| 42 | b = uuid_masked >> 8 |
| 43 | c = uuid_masked & 0xff |
| 44 | d = 0 |
| 45 | |
| 46 | cidr = '%d.%d.%d.%d/24'%(a,b,c,d) |
| 47 | slog.debug("subnet cidr: %s" % str(cidr)) |
| 48 | |
| 49 | return cidr |
| 50 | |
| 51 | def alloc_gateway(self, subnet): |
| 52 | # given a CIDR, allocate a default gateway using the .1 address within the subnet. |
| 53 | # 10.123.0.0/24 --> 10.123.0.1 |
| 54 | # 207.141.192.128/28 --> 207.141.192.129 |
| 55 | (network, bits) = subnet.split("/") |
| 56 | network=network.strip() |
| 57 | bits=int(bits.strip()) |
| 58 | netmask = (~(pow(2,32-bits)-1) & 0xFFFFFFFF) |
| 59 | ip = struct.unpack("!L", socket.inet_aton(network))[0] |
| 60 | ip = ip & netmask | 1 |
| 61 | slog.debug("subnet: %s gateway: %s" % (subnet,ip)) |
| 62 | return socket.inet_ntoa(struct.pack("!L", ip)) |
| 63 | |
| 64 | def chk_net_exist(self, controller_network, swarm_manager_address): |
| 65 | duplicated_flag = False |
| 66 | try: |
| 67 | slog.debug("network_name to check: %s" % controller_network.network.name) |
| 68 | |
| 69 | import docker |
| 70 | docker_api_base_url = "tcp://%s:4243" % swarm_manager_address |
| 71 | slog.info("Docker API Base URL: %s" % docker_api_base_url) |
| 72 | my_client = docker.DockerClient(base_url=docker_api_base_url) |
| 73 | net = my_client.networks.get(controller_network.network.name) |
| 74 | slog.debug("network.id : %s" % net.id) |
| 75 | slog.debug("network.name : %s" % net.name) |
| 76 | slog.debug("network.attrs[IPAM][Config] : %s" % net.attrs['IPAM']['Config']) |
| 77 | slog.debug("network.attrs : %s" % net.attrs) |
| 78 | except Exception as ex: |
| 79 | slog.info("Exception: %s" % str(ex.args)) |
| 80 | slog.info("Exception: %s" % str(ex)) |
| 81 | duplicated_flag = False # There is no same network. |
| 82 | else: |
| 83 | duplicated_flag = True # There is same network. |
| 84 | slog.debug("network duplicated_flag: %s" % duplicated_flag) |
| 85 | return duplicated_flag |
| 86 | |
| 87 | def save_controller_network(self, controller_network): |
| 88 | network_name = controller_network.network.name |
| 89 | if controller_network.subnet and controller_network.subnet.strip(): |
| 90 | # If a subnet is already specified (pass in by the creator), then |
| 91 | # use that rather than auto-generating one. |
| 92 | cidr = controller_network.subnet.strip() |
| 93 | slog.info("subnet CIDR : %s" % cidr) |
| 94 | else: |
| 95 | cidr = self.alloc_subnet(controller_network.pk) |
| 96 | slog.info("subnet CIDR (Auto generated by XOS): %s" % cidr) |
| 97 | |
| 98 | if controller_network.network.start_ip and controller_network.network.start_ip.strip(): |
| 99 | start_ip = controller_network.network.start_ip.strip() |
| 100 | controller_network.gateway = start_ip |
| 101 | else: |
| 102 | start_ip = None |
| 103 | controller_network.gateway = self.alloc_gateway(cidr) |
| 104 | |
| 105 | if controller_network.network.end_ip and controller_network.network.end_ip.strip(): |
| 106 | end_ip = controller_network.network.end_ip.strip() |
| 107 | else: |
| 108 | end_ip = None |
| 109 | slog.info("Start IP Address: %s End IP Address: %s" % (start_ip, end_ip)) |
| 110 | |
| 111 | self.cidr=cidr |
| 112 | slice = controller_network.network.owner |
| 113 | |
| 114 | # "overlay" is default network driver for swarm |
| 115 | opt_driver = "--driver=overlay" |
| 116 | opt_ipam_driver = " " |
| 117 | opt_ipam_neutron_opt = " " |
| 118 | if controller_network.network.template.shared_network_name is not None: |
| 119 | if controller_network.network.template.shared_network_name.__contains__("kuryr"): |
| 120 | # update network driver for swarm |
| 121 | opt_driver = "--driver=%s" % controller_network.network.template.shared_network_name |
| 122 | opt_ipam_driver = "--ipam-driver=%s" % controller_network.network.template.shared_network_name |
| 123 | opt_ipam_neutron_opt = "--ipam-opt=neutron.pool.uuid=%s -o neutron.pool.uuid=%s -o neutron.net.name=%s" % ( |
| 124 | controller_network.network.labels, |
| 125 | controller_network.network.labels, |
| 126 | controller_network.network.name) |
| 127 | |
| 128 | swarm_manager_url = controller_network.controller.auth_url |
| 129 | (swarm_manager_address, docker_registry_port) = swarm_manager_url.split(':') |
| 130 | slog.info("swarm_manager_address: %s docker_registry_port: %s" |
| 131 | % (swarm_manager_address, docker_registry_port)) |
| 132 | |
| 133 | # check if this controller network is created already on swarm cluster. |
| 134 | duplicated_flag = self.chk_net_exist(controller_network, swarm_manager_address) |
| 135 | |
| 136 | network_fields = { |
| 137 | 'swarm_manager_address' : swarm_manager_address, |
| 138 | 'network_name' : network_name, |
| 139 | 'ansible_tag' : '%s-%s@%s' % ( |
| 140 | network_name, |
| 141 | slice.slicename, |
| 142 | controller_network.controller.name), |
| 143 | 'opt_driver' : opt_driver, |
| 144 | 'opt_ipam_driver' : opt_ipam_driver, |
| 145 | 'opt_ipam_neutron_opt' : opt_ipam_neutron_opt, |
| 146 | 'opt_subnet' : "--subnet=%s" % cidr, |
| 147 | 'opt_gateway' : "--gateway=%s" % controller_network.gateway, |
| 148 | 'start_ip' : start_ip, |
| 149 | 'end_ip' : end_ip, |
| 150 | 'duplicated' : duplicated_flag, |
| 151 | 'delete' : False |
| 152 | } |
| 153 | slog.info("network_fields: %s" % network_fields) |
| 154 | return network_fields |
| 155 | |
| 156 | def map_sync_inputs(self, controller_network): |
| 157 | slog.debug("controller_network.subnet: %s" % controller_network.subnet) |
| 158 | slog.debug("controller_network.network.name: %s" % controller_network.network.name) |
| 159 | if controller_network.network.owner and controller_network.network.owner.creator: |
| 160 | return self.save_controller_network(controller_network) |
| 161 | else: |
| 162 | slog.info("I could not create network controller information %s" % controller_network) |
| 163 | raise Exception('I could not create network controller %s'%controller_network) |
| 164 | |
| 165 | def map_sync_outputs(self, controller_network, res): |
| 166 | slog.debug("ansible playbook ressult: %s" % str(res)) |
| 167 | slog.debug("ansible playbook ressult[1][stdout]: %s" % str(res[1]['stdout'])) |
| 168 | |
| 169 | res_stdout = res[1]['stdout'] |
| 170 | json_content = json.loads(res_stdout) |
| 171 | slog.debug("json_content: %s" % str(json_content)) |
| 172 | network_id = json_content[0]['Id'] |
| 173 | slog.debug("network_id: %s" % str(network_id)) |
| 174 | subnet_id = "%s-subnet-%s" % (network_id, self.cidr) |
| 175 | slog.debug("subnet_id: %s" % str(subnet_id)) |
| 176 | |
| 177 | controller_network.net_id = network_id |
| 178 | controller_network.subnet = self.cidr |
| 179 | controller_network.subnet_id = subnet_id |
| 180 | controller_network.backend_status = '1 - OK' |
| 181 | controller_network.save() |
| 182 | |
| 183 | def map_delete_inputs(self, controller_network): |
| 184 | # make sure to not delete a shared network |
| 185 | swarm_manager_url = controller_network.controller.auth_url |
| 186 | (swarm_manager_address, docker_registry_port) = swarm_manager_url.split(':') |
| 187 | slog.info("swarm_manager_address: %s docker_registry_port: %s" |
| 188 | % (swarm_manager_address, docker_registry_port)) |
| 189 | |
| 190 | try: |
| 191 | slice = controller_network.network.owner |
| 192 | except: |
| 193 | raise Exception('Could not get slice for Network %s' % controller_network.network.name) |
| 194 | |
| 195 | network_name = controller_network.network.name |
| 196 | cidr = controller_network.subnet |
| 197 | network_fields = { |
| 198 | 'swarm_manager_address' : swarm_manager_address, |
| 199 | 'network_name' :network_name, |
| 200 | 'ansible_tag' :'%s-%s@%s'%( |
| 201 | network_name, |
| 202 | slice.slicename, |
| 203 | controller_network.controller.name), |
| 204 | 'delete':True |
| 205 | } |
| 206 | return network_fields |