Merge "Add missing licences in requirements.txt"
[snaps.git] / snaps / config / vm_inst.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
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 from snaps.config.network import PortConfig
16
17
18 class VmInstanceConfig(object):
19     """
20     Class responsible for holding configuration setting for a VM Instance
21     """
22
23     def __init__(self, **kwargs):
24         """
25         Constructor
26         :param name: the name of the VM
27         :param flavor: the VM's flavor name
28         :param port_settings: the port configuration settings (required)
29         :param security_group_names: a set of names of the security groups to
30                                      add to the VM
31         :param floating_ip_settings: the floating IP configuration settings
32         :param sudo_user: the sudo user of the VM that will override the
33                           instance_settings.image_user when trying to
34                           connect to the VM
35         :param vm_boot_timeout: the amount of time a thread will wait
36                                 for an instance to boot
37         :param vm_delete_timeout: the amount of time a thread will wait
38                                   for an instance to be deleted
39         :param ssh_connect_timeout: the amount of time a thread will wait
40                                     to obtain an SSH connection to a VM
41         :param cloud_init_timeout: the amount of time a thread will wait for
42                                    cloud-init to complete
43         :param availability_zone: the name of the compute server on which to
44                                   deploy the VM (optional)
45         :param volume_names: a list of the names of the volume to attach
46                              (optional)
47         :param userdata: the string contents of any optional cloud-init script
48                          to execute after the VM has been activated.
49                          This value may also contain a dict who's key value
50                          must contain the key 'cloud-init_file' which denotes
51                          the location of some file containing the cloud-init
52                          script
53         """
54         self.name = kwargs.get('name')
55         self.flavor = kwargs.get('flavor')
56         self.sudo_user = kwargs.get('sudo_user')
57         self.userdata = kwargs.get('userdata')
58
59         self.port_settings = list()
60         port_settings = kwargs.get('ports')
61         if not port_settings:
62             port_settings = kwargs.get('port_settings')
63         if port_settings:
64             for port_setting in port_settings:
65                 if isinstance(port_setting, dict):
66                     self.port_settings.append(PortConfig(**port_setting))
67                 elif isinstance(port_setting, PortConfig):
68                     self.port_settings.append(port_setting)
69
70         if kwargs.get('security_group_names'):
71             if isinstance(kwargs['security_group_names'], list):
72                 self.security_group_names = kwargs['security_group_names']
73             elif isinstance(kwargs['security_group_names'], set):
74                 self.security_group_names = kwargs['security_group_names']
75             elif isinstance(kwargs['security_group_names'], str):
76                 self.security_group_names = [kwargs['security_group_names']]
77             else:
78                 raise VmInstanceConfigError(
79                     'Invalid data type for security_group_names attribute')
80         else:
81             self.security_group_names = set()
82
83         self.floating_ip_settings = list()
84         floating_ip_settings = kwargs.get('floating_ips')
85         if not floating_ip_settings:
86             floating_ip_settings = kwargs.get('floating_ip_settings')
87         if floating_ip_settings:
88             for floating_ip_config in floating_ip_settings:
89                 if isinstance(floating_ip_config, FloatingIpConfig):
90                     self.floating_ip_settings.append(floating_ip_config)
91                 else:
92                     self.floating_ip_settings.append(FloatingIpConfig(
93                         **floating_ip_config['floating_ip']))
94
95         self.vm_boot_timeout = kwargs.get('vm_boot_timeout', 900)
96         self.vm_delete_timeout = kwargs.get('vm_delete_timeout', 300)
97         self.ssh_connect_timeout = kwargs.get('ssh_connect_timeout', 180)
98         self.cloud_init_timeout = kwargs.get('cloud_init_timeout', 300)
99         self.availability_zone = kwargs.get('availability_zone')
100         self.volume_names = kwargs.get('volume_names')
101
102         if self.volume_names and not isinstance(self.volume_names, list):
103             raise VmInstanceConfigError('volume_names must be a list')
104
105         if not self.name or not self.flavor:
106             raise VmInstanceConfigError(
107                 'Instance configuration requires the attributes: name, flavor')
108
109         if len(self.port_settings) == 0:
110             raise VmInstanceConfigError(
111                 'Instance configuration requires port settings (aka. NICS)')
112
113
114 class FloatingIpConfig(object):
115     """
116     Class responsible for holding configuration settings for a floating IP
117     """
118
119     def __init__(self, **kwargs):
120         """
121         Constructor
122         :param name: the name of the floating IP
123         :param port_name: the name of the router to the external network
124         :param router_name: the name of the router to the external network
125         :param subnet_name: the name of the subnet on which to attach the
126                             floating IP
127         :param provisioning: when true, this floating IP can be used for
128                              provisioning
129
130         TODO - provisioning flag is a hack as I have only observed a single
131         Floating IPs that actually works on an instance. Multiple floating IPs
132         placed on different subnets from the same port are especially
133         troublesome as you cannot predict which one will actually connect.
134         For now, it is recommended not to setup multiple floating IPs on an
135         instance unless absolutely necessary.
136         """
137         self.name = kwargs.get('name')
138         self.port_name = kwargs.get('port_name')
139         self.port_id = kwargs.get('port_id')
140         self.router_name = kwargs.get('router_name')
141         self.subnet_name = kwargs.get('subnet_name')
142         if kwargs.get('provisioning') is not None:
143             self.provisioning = kwargs['provisioning']
144         else:
145             self.provisioning = True
146
147         # if not self.name or not self.port_name or not self.router_name:
148         if not self.name or not self.router_name:
149             raise FloatingIpConfigError(
150                 'The attributes name, port_name and router_name are required')
151
152         if not self.port_name and not self.port_id:
153             raise FloatingIpConfigError(
154                 'The attributes port_name or port_id are required')
155
156
157 class VmInstanceConfigError(Exception):
158     """
159     Exception to be thrown when an VM instance settings are incorrect
160     """
161
162
163 class FloatingIpConfigError(Exception):
164     """
165     Exception to be thrown when an VM instance settings are incorrect
166     """