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.context = context
122 self.public_ip = None
123 self.private_ip = None
128 self.placement_groups = []
129 placement = attrs.get("placement", [])
130 placement = placement if type(placement) is list else [placement]
132 pg = PlacementGroup.get(p)
134 raise ValueError("server '%s', placement '%s' is invalid" %
136 self.placement_groups.append(pg)
137 pg.add_member(self.stack_name)
140 if "instances" in attrs:
141 self.instances = attrs["instances"]
143 # dict with key network name, each item is a dict with port name and ip
146 self.floating_ip = None
147 if "floating_ip" in attrs:
148 self.floating_ip = {}
150 if self.floating_ip is not None:
151 ext_net = Network.find_external_network()
152 assert ext_net is not None
153 self.floating_ip["external_network"] = ext_net
157 self._image = attrs["image"]
160 if "flavor" in attrs:
161 self._flavor = attrs["flavor"]
163 Server.list.append(self)
167 '''returns a server's image name'''
171 return self._context.image
175 '''returns a server's flavor name'''
179 return self._context.flavor
181 def _add_instance(self, template, server_name, networks, scheduler_hints):
182 '''adds to the template one server and corresponding resources'''
184 for network in networks:
185 port_name = server_name + "-" + network.name + "-port"
186 self.ports[network.name] = {"stack_name": port_name}
187 template.add_port(port_name, network.stack_name,
188 network.subnet_stack_name,
189 sec_group_id=self.secgroup_name)
190 port_name_list.append(port_name)
193 external_network = self.floating_ip["external_network"]
194 if network.has_route_to(external_network):
195 self.floating_ip["stack_name"] = server_name + "-fip"
196 template.add_floating_ip(self.floating_ip["stack_name"],
199 network.router.stack_if_name,
202 template.add_server(server_name, self.image, self.flavor,
203 ports=port_name_list,
204 key_name=self.keypair_name,
205 scheduler_hints=scheduler_hints)
207 def add_to_template(self, template, networks, scheduler_hints=None):
208 '''adds to the template one or more servers (instances)'''
209 if self.instances == 1:
210 server_name = self.stack_name
211 self._add_instance(template, server_name, networks,
212 scheduler_hints=scheduler_hints)
214 # TODO(hafe) fix or remove, no test/sample for this
215 for i in range(self.instances):
216 server_name = "%s-%d" % (self.stack_name, i)
217 self._add_instance(template, server_name, networks,
218 scheduler_hints=scheduler_hints)
221 def update_scheduler_hints(scheduler_hints, added_servers, placement_group):
222 ''' update scheduler hints from server's placement configuration
223 TODO: this code is openstack specific and should move somewhere else
225 if placement_group.policy == "affinity":
226 if "same_host" in scheduler_hints:
227 host_list = scheduler_hints["same_host"]
229 host_list = scheduler_hints["same_host"] = []
231 if "different_host" in scheduler_hints:
232 host_list = scheduler_hints["different_host"]
234 host_list = scheduler_hints["different_host"] = []
236 for name in added_servers:
237 if name in placement_group.members:
238 host_list.append({'get_resource': name})