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 if "floating_ip" in attrs:
149 self.floating_ip = {}
151 if self.floating_ip is not None:
152 ext_net = Network.find_external_network()
153 assert ext_net is not None
154 self.floating_ip["external_network"] = ext_net
158 self._image = attrs["image"]
161 if "flavor" in attrs:
162 self._flavor = attrs["flavor"]
164 Server.list.append(self)
168 '''returns a server's image name'''
172 return self._context.image
176 '''returns a server's flavor name'''
180 return self._context.flavor
182 def _add_instance(self, template, server_name, networks, scheduler_hints):
183 '''adds to the template one server and corresponding resources'''
185 for network in networks:
186 port_name = server_name + "-" + network.name + "-port"
187 self.ports[network.name] = {"stack_name": port_name}
188 template.add_port(port_name, network.stack_name,
189 network.subnet_stack_name,
190 sec_group_id=self.secgroup_name)
191 port_name_list.append(port_name)
194 external_network = self.floating_ip["external_network"]
195 if network.has_route_to(external_network):
196 self.floating_ip["stack_name"] = server_name + "-fip"
197 template.add_floating_ip(self.floating_ip["stack_name"],
200 network.router.stack_if_name,
203 template.add_server(server_name, self.image, self.flavor,
204 ports=port_name_list,
206 key_name=self.keypair_name,
207 scheduler_hints=scheduler_hints)
209 def add_to_template(self, template, networks, scheduler_hints=None):
210 '''adds to the template one or more servers (instances)'''
211 if self.instances == 1:
212 server_name = self.stack_name
213 self._add_instance(template, server_name, networks,
214 scheduler_hints=scheduler_hints)
216 # TODO(hafe) fix or remove, no test/sample for this
217 for i in range(self.instances):
218 server_name = "%s-%d" % (self.stack_name, i)
219 self._add_instance(template, server_name, networks,
220 scheduler_hints=scheduler_hints)
223 def update_scheduler_hints(scheduler_hints, added_servers, placement_group):
224 ''' update scheduler hints from server's placement configuration
225 TODO: this code is openstack specific and should move somewhere else
227 if placement_group.policy == "affinity":
228 if "same_host" in scheduler_hints:
229 host_list = scheduler_hints["same_host"]
231 host_list = scheduler_hints["same_host"] = []
233 if "different_host" in scheduler_hints:
234 host_list = scheduler_hints["different_host"]
236 host_list = scheduler_hints["different_host"] = []
238 for name in added_servers:
239 if name in placement_group.members:
240 host_list.append({'get_resource': name})