1 ##############################################################################
2 # Copyright (c) 2015 Ericsson AB and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
13 from __future__ import absolute_import
14 from six.moves import range
18 '''Base class for classes in the logical model
19 Contains common attributes and methods
22 def __init__(self, name, context):
23 # model identities and reference
25 self._context = context
28 self.stack_name = None
33 '''returns distinguished name for object'''
34 return self.name + "." + self._context.name
37 class PlacementGroup(Object):
38 '''Class that represents a placement group in the logical model
39 Concept comes from the OVF specification. Policy should be one of
40 "availability" or "affinity (there are more but they are not supported)"
44 def __init__(self, name, context, policy):
45 if policy not in ["affinity", "availability"]:
46 raise ValueError("placement group '%s', policy '%s' is not valid" %
50 self.stack_name = context.name + "-" + name
52 PlacementGroup.map[name] = self
54 def add_member(self, name):
55 self.members.add(name)
59 if name in PlacementGroup.map:
60 return PlacementGroup.map[name]
66 '''Class that represents a router in the logical model'''
68 def __init__(self, name, network_name, context, external_gateway_info):
69 super(self.__class__, self).__init__(name, context)
71 self.stack_name = context.name + "-" + network_name + "-" + self.name
72 self.stack_if_name = self.stack_name + "-if0"
73 self.external_gateway_info = external_gateway_info
76 class Network(Object):
77 '''Class that represents a network in the logical model'''
80 def __init__(self, name, context, attrs):
81 super(self.__class__, self).__init__(name, context)
82 self.stack_name = context.name + "-" + self.name
83 self.subnet_stack_name = self.stack_name + "-subnet"
84 self.subnet_cidr = attrs.get('cidr', '10.0.1.0/24')
87 if "external_network" in attrs:
88 self.router = Router("router", self.name,
89 context, attrs["external_network"])
91 Network.list.append(self)
93 def has_route_to(self, network_name):
94 '''determines if this network has a route to the named network'''
95 if self.router and self.router.external_gateway_info == network_name:
100 def find_by_route_to(external_network):
101 '''finds a network that has a route to the specified network'''
102 for network in Network.list:
103 if network.has_route_to(external_network):
107 def find_external_network():
108 '''return the name of an external network some network in this
109 context has a route to'''
110 for network in Network.list:
112 return network.router.external_gateway_info
116 class Server(Object):
117 '''Class that represents a server in the logical model'''
120 def __init__(self, name, context, attrs):
121 super(self.__class__, self).__init__(name, context)
122 self.stack_name = self.name + "." + context.name
123 self.keypair_name = context.keypair_name
124 self.secgroup_name = context.secgroup_name
125 self.user = context.user
126 self.context = context
127 self.public_ip = None
128 self.private_ip = None
133 self.placement_groups = []
134 placement = attrs.get("placement", [])
135 placement = placement if type(placement) is list else [placement]
137 pg = PlacementGroup.get(p)
139 raise ValueError("server '%s', placement '%s' is invalid" %
141 self.placement_groups.append(pg)
142 pg.add_member(self.stack_name)
145 if "instances" in attrs:
146 self.instances = attrs["instances"]
148 # dict with key network name, each item is a dict with port name and ip
151 self.floating_ip = None
152 self.floating_ip_assoc = None
153 if "floating_ip" in attrs:
154 self.floating_ip = {}
155 self.floating_ip_assoc = {}
157 if self.floating_ip is not None:
158 ext_net = Network.find_external_network()
159 assert ext_net is not None
160 self.floating_ip["external_network"] = ext_net
164 self._image = attrs["image"]
167 if "flavor" in attrs:
168 self._flavor = attrs["flavor"]
170 Server.list.append(self)
174 '''returns a server's image name'''
178 return self._context.image
182 '''returns a server's flavor name'''
186 return self._context.flavor
188 def _add_instance(self, template, server_name, networks, scheduler_hints):
189 '''adds to the template one server and corresponding resources'''
191 for network in networks:
192 port_name = server_name + "-" + network.name + "-port"
193 self.ports[network.name] = {"stack_name": port_name}
194 template.add_port(port_name, network.stack_name,
195 network.subnet_stack_name,
196 sec_group_id=self.secgroup_name)
197 port_name_list.append(port_name)
200 external_network = self.floating_ip["external_network"]
201 if network.has_route_to(external_network):
202 self.floating_ip["stack_name"] = server_name + "-fip"
203 template.add_floating_ip(self.floating_ip["stack_name"],
206 network.router.stack_if_name,
208 self.floating_ip_assoc["stack_name"] = \
209 server_name + "-fip-assoc"
210 template.add_floating_ip_association(
211 self.floating_ip_assoc["stack_name"],
212 self.floating_ip["stack_name"],
215 template.add_server(server_name, self.image, self.flavor,
216 ports=port_name_list,
218 key_name=self.keypair_name,
219 scheduler_hints=scheduler_hints)
221 def add_to_template(self, template, networks, scheduler_hints=None):
222 '''adds to the template one or more servers (instances)'''
223 if self.instances == 1:
224 server_name = self.stack_name
225 self._add_instance(template, server_name, networks,
226 scheduler_hints=scheduler_hints)
228 # TODO(hafe) fix or remove, no test/sample for this
229 for i in range(self.instances):
230 server_name = "%s-%d" % (self.stack_name, i)
231 self._add_instance(template, server_name, networks,
232 scheduler_hints=scheduler_hints)
235 def update_scheduler_hints(scheduler_hints, added_servers, placement_group):
236 ''' update scheduler hints from server's placement configuration
237 TODO: this code is openstack specific and should move somewhere else
239 if placement_group.policy == "affinity":
240 if "same_host" in scheduler_hints:
241 host_list = scheduler_hints["same_host"]
243 host_list = scheduler_hints["same_host"] = []
245 if "different_host" in scheduler_hints:
246 host_list = scheduler_hints["different_host"]
248 host_list = scheduler_hints["different_host"] = []
250 for name in added_servers:
251 if name in placement_group.members:
252 host_list.append({'get_resource': name})