~ubuntu-branches/ubuntu/trusty/quantum/trusty

2.1.16 by Chuck Short
Import upstream version 2013.1~g1
1
#!/usr/bin/env python
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
#
4
# Copyright 2011 Cisco Systems, Inc.  All rights reserved.
5
#
6
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
7
#    not use this file except in compliance with the License. You may obtain
8
#    a copy of the License at
9
#
10
#         http://www.apache.org/licenses/LICENSE-2.0
11
#
12
#    Unless required by applicable law or agreed to in writing, software
13
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
#    License for the specific language governing permissions and limitations
16
#    under the License.
17
#
18
#    @author: Edgar Magana, Cisco Systems
19
#
20
"""
21
Network Library to insert services using Quantum APIs
22
Currently has four functionalities:
23
1. insert_inpath_service <tenant_id> <service_image_id>
24
    <management_net_name> <northbound_net_name> <southbound_net_name>
25
2. delete_service <tenant_id> <service_instance_id>
26
3. connect_vm <tenant_id> <vm_image_id> <service_instance_id>
27
4. disconnect_vm <vm_instance_id>
28
"""
29
30
import logging
31
import logging.handlers
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
32
from optparse import OptionParser
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
33
import os
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
34
import re
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
35
import subprocess
36
import sys
37
2.1.11 by Chuck Short
Import upstream version 2012.2~rc1~20120907.1154
38
from quantum.common import constants
2.1.16 by Chuck Short
Import upstream version 2013.1~g1
39
from quantum.common import utils
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
40
from quantum.plugins.cisco.common import cisco_constants as const
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
41
from quantum.plugins.cisco.db import api as db
42
from quantum.plugins.cisco.db import l2network_db as l2db
43
from quantum.plugins.cisco.db import services_db as sdb
44
from quantum.plugins.cisco.services import services_constants as servconts
45
from quantum.plugins.cisco.services import services_logistics as servlogcs
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
46
from quantumclient import Client
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
47
48
49
LOG = logging.getLogger(__name__)
50
51
52
def insert_inpath_service(tenant_id, service_image_id,
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
53
                          management_net_name, northbound_net_name,
54
                          southbound_net_name, *args):
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
55
    """Inserting a network service between two networks"""
56
    print ("Creating Network for Services and Servers")
57
    service_logic = servlogcs.ServicesLogistics()
58
    net_list = {}
59
    multiport_net_list = []
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
60
    networks_name_list = [management_net_name, northbound_net_name,
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
61
                          southbound_net_name]
62
    client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id)
63
    for net in networks_name_list:
64
        data = {servconts.NETWORK: {servconts.NAME: net}}
65
        net_list[net] = client.create_network(data)
66
        net_list[net][servconts.PORTS] = []
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
67
        LOG.debug("Network %s Created with ID: %s " % (
68
            net, net_list[net][servconts.NETWORK][servconts.ID]))
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
69
    print "Completed"
70
    print ("Creating Ports on Services and Server Networks")
71
    LOG.debug("Operation 'create_port' executed.")
72
    if not service_logic.verify_plugin(const.UCS_PLUGIN):
73
        for net in networks_name_list:
74
            net_list[net][servconts.PORTS].append
75
            (client.create_port
76
            (net_list[net][servconts.NETWORK][servconts.ID]))
77
        LOG.debug("Operation 'create_port' executed.")
78
    else:
79
        for net in networks_name_list:
80
            nets = net_list[net][servconts.NETWORK][servconts.ID]
81
            multiport_net_list.append(nets)
82
        data = create_multiport(tenant_id, multiport_net_list)
83
        net_idx = 0
84
        for net in networks_name_list:
85
            port_id = data[servconts.PORTS][net_idx][servconts.ID]
86
            net_list[net][servconts.PORTS].append(port_id)
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
87
            LOG.debug("Port UUID: %s on network: %s" %
88
                      (data[servconts.PORTS][net_idx][servconts.ID], net))
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
89
            net_idx = net_idx + 1
90
    print "Completed"
91
    try:
92
        create_vm_args = []
93
        create_vm_args.append(servconts.CREATE_VM_CMD)
94
        create_vm_args.append(service_image_id)
95
        print ("Creating VM with image: %s" % (service_image_id))
2.1.16 by Chuck Short
Import upstream version 2013.1~g1
96
        process = utils.subprocess_popen(create_vm_args,
97
                                         stdout=subprocess.PIPE)
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
98
        result = process.stdout.readlines()
99
        tokens = re.search("i-[a-f0-9]*", str(result[1]))
100
        service_vm_name = tokens.group(0)
101
        print ("Image: %s instantiated successfully" % (service_vm_name))
102
103
    except Exception as exc:
104
        print exc
105
106
    service_logic.image_status(service_vm_name)
107
    print "Completed"
108
    print "Attaching Ports To VM Service interfaces"
109
    try:
110
        idx = 0
111
        for net in networks_name_list:
112
            network_id = net_list[net][servconts.NETWORK][servconts.ID]
113
            port_id = net_list[net][servconts.PORTS][idx]
114
            attachment = client.show_port_attachment(network_id, port_id)
115
            attachment = attachment[servconts.ATTACHMENT][servconts.ID][:36]
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
116
            LOG.debug(("Plugging virtual interface: %s of VM %s"
117
                       "into port: %s on network: %s") %
118
                      (attachment, service_vm_name, port_id, net))
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
119
            attach_data = {servconts.ATTACHMENT: {servconts.ID: '%s' %
120
                                                  attachment}}
121
            client.attach_resource(network_id, port_id, attach_data)
122
    except Exception as exc:
123
        print exc
124
    print "Completed"
125
    try:
126
        LOG.debug("Registering Service in DB")
127
        l2db.initialize()
128
        for uuid_net in db.network_id(networks_name_list[0]):
129
            mngnet_id = str(uuid_net.uuid)
130
        for uuid_net in db.network_id(networks_name_list[1]):
131
            nbnet_id = str(uuid_net.uuid)
132
        for uuid_net in db.network_id(networks_name_list[2]):
133
            sbnet_id = str(uuid_net.uuid)
134
        sdb.add_services_binding(service_vm_name, mngnet_id, nbnet_id,
135
                                 sbnet_id)
136
    except Exception as exc:
137
        print exc
138
139
140
def delete_service(tenant_id, service_instance_id, *args):
141
    """
142
    Removes a service and all the network configuration
143
    """
144
    l2db.initialize()
145
    print ("Terminating Service VM")
146
    service_logic = servlogcs.ServicesLogistics()
147
    vms_list = []
148
    vms_list.append(servconts.DELETE_VM_CMD)
149
    vms_list.append(service_instance_id)
150
151
    if not service_logic.image_exist(service_instance_id):
152
        print ("Service VM does not exist")
153
        sys.exit()
154
155
    result = subprocess.call(vms_list)
156
    service_logic.image_shutdown_verification(service_instance_id)
157
158
    client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id)
159
    service_nets = sdb.get_service_bindings(service_instance_id)
160
    print ("Terminating Ports and Networks")
161
    network_name = db.network_get(service_nets.mngnet_id)
162
    port_id_net = db.port_list(service_nets.mngnet_id)
163
    for ports_uuid in port_id_net:
164
        client.delete_port(service_nets.mngnet_id, ports_uuid.uuid)
165
    client.delete_network(service_nets.mngnet_id)
166
    network_name = db.network_get(service_nets.nbnet_id)
167
    port_id_net = db.port_list(service_nets.nbnet_id)
168
    for ports_uuid in port_id_net:
169
        client.delete_port(service_nets.nbnet_id, ports_uuid.uuid)
170
    client.delete_network(service_nets.nbnet_id)
171
    network_name = db.network_get(service_nets.sbnet_id)
172
    port_id_net = db.port_list(service_nets.sbnet_id)
173
    for ports_uuid in port_id_net:
174
        client.delete_port(service_nets.sbnet_id, ports_uuid.uuid)
175
    client.delete_network(service_nets.sbnet_id)
176
    service_list = sdb.remove_services_binding(service_instance_id)
177
    print ("Configuration Removed Successfully")
178
179
180
def disconnect_vm(vm_instance_id, *args):
181
    """
182
    Deletes VMs and Port connection
183
    """
184
    l2db.initialize()
185
    print ("Terminating Service VM")
186
    service_logic = servlogcs.ServicesLogistics()
187
    vms_list = []
188
    vms_list.append(servconts.DELETE_VM_CMD)
189
    vms_list.append(vm_instance_id)
190
    result = subprocess.call(vms_list)
191
    service_logic.image_shutdown_verification(vm_instance_id)
192
    print ("VM Server Off")
193
194
195
def connect_vm(tenant_id, vm_image_id, service_instance_id, *args):
196
    """
197
    Starts a VMs and is connected to southbound network
198
    """
199
    l2db.initialize()
200
    client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id)
201
    print ("Connecting %s to Service %s " % (vm_image_id, service_instance_id))
202
    service_logic = servlogcs.ServicesLogistics()
203
    service_nets = sdb.get_service_bindings(service_instance_id)
204
    client.create_port(service_nets.mngnet_id)
205
    client.create_port(service_nets.nbnet_id)
206
    sb_port_id = client.create_port(service_nets.sbnet_id)
207
    LOG.debug("Operation 'create_port' executed.")
208
    new_port_id = sb_port_id[servconts.PORT][servconts.ID]
209
    try:
210
        create_vm_args = []
211
        create_vm_args.append(servconts.CREATE_VM_CMD)
212
        create_vm_args.append(vm_image_id)
213
        print ("Creating VM with image: %s" % (vm_image_id))
2.1.16 by Chuck Short
Import upstream version 2013.1~g1
214
        process = utils.subprocess_popen(create_vm_args,
215
                                         stdout=subprocess.PIPE)
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
216
        result = process.stdout.readlines()
217
        tokens = re.search("i-[a-f0-9]*", str(result[1]))
218
        vm_name = tokens.group(0)
219
        print ("Image: %s instantiated successfully" % (vm_name))
220
    except Exception as exc:
221
        print exc
222
223
    service_logic.image_status(vm_name)
224
    print "Completed"
225
    print "Attaching Ports To VM Service interfaces"
226
    south_net = service_nets.sbnet_id
227
    attachment = client.show_port_attachment(south_net, new_port_id)
228
    attachment = attachment[servconts.ATTACHMENT][servconts.ID][:36]
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
229
    LOG.debug(("Plugging virtual interface: %s of VM %s "
230
               "into port: %s on network: %s") %
231
              (attachment, vm_name, new_port_id, service_nets.sbnet_id))
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
232
    attach_data = {servconts.ATTACHMENT: {servconts.ID: '%s' % attachment}}
233
    client.attach_resource(service_nets.sbnet_id, new_port_id, attach_data)
234
    print ("Connect VM Ended")
235
236
237
def create_multiport(tenant_id, networks_list, *args):
238
    """Creates ports on a single host"""
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
239
    ports_info = {'multiport':
2.1.11 by Chuck Short
Import upstream version 2012.2~rc1~20120907.1154
240
                  {'status': constants.PORT_STATUS_ACTIVE,
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
241
                   'net_id_list': networks_list,
242
                   'ports_desc': {'key': 'value'}}}
243
    request_url = "/multiport"
244
    client = Client(HOST, PORT, USE_SSL, format='json', tenant=tenant_id,
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
245
                    action_prefix=servconts.ACTION_PREFIX_CSCO)
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
246
    data = client.do_request('POST', request_url, body=ports_info)
247
    return data
248
249
250
def build_args(cmd, cmdargs, arglist):
251
    """Building the list of args for a particular CLI"""
252
    args = []
253
    orig_arglist = arglist[:]
254
    try:
255
        for cmdarg in cmdargs:
256
            args.append(arglist[0])
257
            del arglist[0]
258
    except:
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
259
        LOG.debug("Not enough arguments for \"%s\" (expected: %d, got: %d)" %
260
                  (cmd, len(cmdargs), len(orig_arglist)))
261
        print "Service Insertion Usage:\n    %s %s" % (
262
            cmd, " ".join(["<%s>" % y for y in SERVICE_COMMANDS[cmd]["args"]]))
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
263
        sys.exit()
264
    if len(arglist) > 0:
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
265
        LOG.debug("Too many arguments for \"%s\" (expected: %d, got: %d)"
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
266
                  % (cmd, len(cmdargs), len(orig_arglist)))
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
267
        print "Service Insertion Usage:\n    %s %s" % (
268
            cmd, " ".join(["<%s>" % y for y in SERVICE_COMMANDS[cmd]["args"]]))
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
269
        sys.exit()
270
    return args
271
272
273
SERVICE_COMMANDS = {
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
274
    "insert_inpath_service": {
275
        "func": insert_inpath_service,
276
        "args": ["tenant_id", "service_image_id", "management_net_name",
277
                 "northbound_net_name", "southbound_net_name"],
278
    },
279
    "delete_service": {
280
        "func": delete_service,
281
        "args": ["tenant_id", "service_instance_id"],
282
    },
283
    "connect_vm": {
284
        "func": connect_vm,
285
        "args": ["tenant_id", "vm_image_id", "service_instance_id"],
286
    },
287
    "disconnect_vm": {
288
        "func": disconnect_vm,
289
        "args": ["vm_instance_id"],
290
    },
291
}
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
292
293
294
if __name__ == "__main__":
295
    os.system("clear")
296
    usagestr = "Usage: %prog [OPTIONS] <command> [args]"
297
    PARSER = OptionParser(usage=usagestr)
298
    PARSER.add_option("-H", "--host", dest="host",
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
299
                      type="string", default="127.0.0.1",
300
                      help="ip address of api host")
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
301
    PARSER.add_option("-p", "--port", dest="port",
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
302
                      type="int", default=9696, help="api port")
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
303
    PARSER.add_option("-s", "--ssl", dest="ssl",
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
304
                      action="store_true", default=False, help="use ssl")
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
305
    PARSER.add_option("-v", "--verbose", dest="verbose",
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
306
                      action="store_true", default=False,
307
                      help="turn on verbose logging")
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
308
    PARSER.add_option("-f", "--logfile", dest="logfile",
2.1.8 by Chuck Short
Import upstream version 2012.2~f2~20120621.868
309
                      type="string", default="syslog", help="log file path")
2.1.2 by Chuck Short
Import upstream version 2012.1~e2
310
    options, args = PARSER.parse_args()
311
    if options.verbose:
312
        LOG.setLevel(logging.DEBUG)
313
    else:
314
        LOG.setLevel(logging.WARN)
315
    if options.logfile == "syslog":
316
        LOG.addHandler(logging.handlers.SysLogHandler(address='/dev/log'))
317
    else:
318
        LOG.addHandler(logging.handlers.WatchedFileHandler(options.logfile))
319
        os.chmod(options.logfile, 0644)
320
    service_logic = servlogcs.ServicesLogistics()
321
    HOST = options.host
322
    PORT = options.port
323
    USE_SSL = options.ssl
324
    CMD = args[0]
325
    args = build_args(CMD, SERVICE_COMMANDS[CMD]["args"], args[1:])
326
    SERVICE_COMMANDS[CMD]["func"](*args)
327
    sys.exit(0)