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 ##############################################################################
16 '''Base class for classes in the logical model
17 Contains common attributes and methods
19 def __init__(self, name, context):
20 # model identities and reference
22 self._context = context
25 self.stack_name = None
30 '''returns distinguished name for object'''
31 return self.name + "." + self._context.name
34 class PlacementGroup(Object):
35 '''Class that represents a placement group in the logical model
36 Concept comes from the OVF specification. Policy should be one of
37 "availability" or "affinity (there are more but they are not supported)"
41 def __init__(self, name, context, policy):
42 if policy not in ["affinity", "availability"]:
43 raise ValueError("placement group '%s', policy '%s' is not valid" %
47 self.stack_name = context.name + "-" + name
49 PlacementGroup.map[name] = self
51 def add_member(self, name):
52 self.members.add(name)
56 if name in PlacementGroup.map:
57 return PlacementGroup.map[name]
63 '''Class that represents a router in the logical model'''
64 def __init__(self, name, network_name, context, external_gateway_info):
65 super(self.__class__, self).__init__(name, context)
67 self.stack_name = context.name + "-" + network_name + "-" + self.name
68 self.stack_if_name = self.stack_name + "-if0"
69 self.external_gateway_info = external_gateway_info
72 class Network(Object):
73 '''Class that represents a network in the logical model'''
76 def __init__(self, name, context, attrs):
77 super(self.__class__, self).__init__(name, context)
78 self.stack_name = context.name + "-" + self.name
79 self.subnet_stack_name = self.stack_name + "-subnet"
80 self.subnet_cidr = attrs.get('cidr', '10.0.1.0/24')
83 if "external_network" in attrs:
84 self.router = Router("router", self.name,
85 context, attrs["external_network"])
87 Network.list.append(self)
89 def has_route_to(self, network_name):
90 '''determines if this network has a route to the named network'''
91 if self.router and self.router.external_gateway_info == network_name:
96 def find_by_route_to(external_network):
97 '''finds a network that has a route to the specified network'''
98 for network in Network.list:
99 if network.has_route_to(external_network):
103 def find_external_network():
104 '''return the name of an external network some network in this
105 context has a route to'''
106 for network in Network.list:
108 return network.router.external_gateway_info
112 class Server(Object):
113 '''Class that represents a server in the logical model'''
116 def __init__(self, name, context, attrs):
117 super(self.__class__, self).__init__(name, context)
118 self.stack_name = self.name + "." + context.name
119 self.keypair_name = context.keypair_name
120 self.secgroup_name = context.secgroup_name
121 self.user = context.user
122 self.context = context
123 self.public_ip = None
124 self.private_ip = None
129 self.placement_groups = []
130 placement = attrs.get("placement", [])
131 placement = placement if type(placement) is list else [placement]
133 pg = PlacementGroup.get(p)
135 raise ValueError("server '%s', placement '%s' is invalid" %
137 self.placement_groups.append(pg)
138 pg.add_member(self.stack_name)
141 if "instances" in attrs:
142 self.instances = attrs["instances"]
144 # dict with key network name, each item is a dict with port name and ip
147 self.floating_ip = None
148 self.floating_ip_assoc = None
149 if "floating_ip" in attrs:
150 self.floating_ip = {}
151 self.floating_ip_assoc = {}
153 if self.floating_ip is not None:
154 ext_net = Network.find_external_network()
155 assert ext_net is not None
156 self.floating_ip["external_network"] = ext_net
160 self._image = attrs["image"]
163 if "flavor" in attrs:
164 self._flavor = attrs["flavor"]
166 Server.list.append(self)
170 '''returns a server's image name'''
174 return self._context.image
178 '''returns a server's flavor name'''
182 return self._context.flavor
184 def _add_instance(self, template, server_name, networks, scheduler_hints):
185 '''adds to the template one server and corresponding resources'''
187 for network in networks:
188 port_name = server_name + "-" + network.name + "-port"
189 self.ports[network.name] = {"stack_name": port_name}
190 template.add_port(port_name, network.stack_name,
191 network.subnet_stack_name,
192 sec_group_id=self.secgroup_name)
193 port_name_list.append(port_name)
196 external_network = self.floating_ip["external_network"]
197 if network.has_route_to(external_network):
198 self.floating_ip["stack_name"] = server_name + "-fip"
199 template.add_floating_ip(self.floating_ip["stack_name"],
202 network.router.stack_if_name,
204 self.floating_ip_assoc["stack_name"] = \
205 server_name + "-fip-assoc"
206 template.add_floating_ip_association(
207 self.floating_ip_assoc["stack_name"],
208 self.floating_ip["stack_name"],
211 template.add_server(server_name, self.image, self.flavor,
212 ports=port_name_list,
214 key_name=self.keypair_name,
215 scheduler_hints=scheduler_hints)
217 def add_to_template(self, template, networks, scheduler_hints=None):
218 '''adds to the template one or more servers (instances)'''
219 if self.instances == 1:
220 server_name = self.stack_name
221 self._add_instance(template, server_name, networks,
222 scheduler_hints=scheduler_hints)
224 # TODO(hafe) fix or remove, no test/sample for this
225 for i in range(self.instances):
226 server_name = "%s-%d" % (self.stack_name, i)
227 self._add_instance(template, server_name, networks,
228 scheduler_hints=scheduler_hints)
231 def update_scheduler_hints(scheduler_hints, added_servers, placement_group):
232 ''' update scheduler hints from server's placement configuration
233 TODO: this code is openstack specific and should move somewhere else
235 if placement_group.policy == "affinity":
236 if "same_host" in scheduler_hints:
237 host_list = scheduler_hints["same_host"]
239 host_list = scheduler_hints["same_host"] = []
241 if "different_host" in scheduler_hints:
242 host_list = scheduler_hints["different_host"]
244 host_list = scheduler_hints["different_host"] = []
246 for name in added_servers:
247 if name in placement_group.members:
248 host_list.append({'get_resource': name})