Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 1 | import os |
| 2 | import pdb |
| 3 | import sys |
| 4 | import tempfile |
Scott Baker | e08b456 | 2015-08-11 17:23:52 -0700 | [diff] [blame] | 5 | import traceback |
| 6 | |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 7 | sys.path.append("/opt/tosca") |
| 8 | from translator.toscalib.tosca_template import ToscaTemplate |
| 9 | |
Tony Mack | d851547 | 2015-08-19 11:58:18 -0400 | [diff] [blame] | 10 | from core.models import Slice,Instance,User,Flavor,Node,Image |
Scott Baker | efa6ea4 | 2015-07-31 11:48:45 -0700 | [diff] [blame] | 11 | from nodeselect import XOSNodeSelector |
Scott Baker | 1f9d451 | 2015-08-03 09:56:35 -0700 | [diff] [blame] | 12 | from imageselect import XOSImageSelector |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 13 | |
Scott Baker | 3841b37 | 2015-08-03 14:20:31 -0700 | [diff] [blame] | 14 | import resources |
| 15 | |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 16 | class XOSTosca(object): |
Scott Baker | e08b456 | 2015-08-11 17:23:52 -0700 | [diff] [blame] | 17 | def __init__(self, tosca_yaml, parent_dir=None, log_to_console = False): |
Scott Baker | 7e472dd | 2015-07-31 12:30:28 -0700 | [diff] [blame] | 18 | # TOSCA will look for imports using a relative path from where the |
| 19 | # template file is located, so we have to put the template file |
| 20 | # in a specific place. |
| 21 | if not parent_dir: |
| 22 | parent_dir = os.getcwd() |
| 23 | |
Scott Baker | e08b456 | 2015-08-11 17:23:52 -0700 | [diff] [blame] | 24 | tmp_pathname = None |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 25 | try: |
Scott Baker | 7e472dd | 2015-07-31 12:30:28 -0700 | [diff] [blame] | 26 | (tmp_handle, tmp_pathname) = tempfile.mkstemp(dir=parent_dir) |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 27 | os.write(tmp_handle, tosca_yaml) |
| 28 | os.close(tmp_handle) |
| 29 | |
| 30 | self.template = ToscaTemplate(tmp_pathname) |
Scott Baker | e08b456 | 2015-08-11 17:23:52 -0700 | [diff] [blame] | 31 | except: |
| 32 | traceback.print_exc() |
| 33 | raise |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 34 | finally: |
Scott Baker | e08b456 | 2015-08-11 17:23:52 -0700 | [diff] [blame] | 35 | if tmp_pathname: |
| 36 | os.remove(tmp_pathname) |
| 37 | |
| 38 | self.log_to_console = log_to_console |
| 39 | self.log_msgs = [] |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 40 | |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 41 | self.compute_dependencies() |
| 42 | |
Scott Baker | 404c46d | 2015-08-24 15:50:03 -0700 | [diff] [blame] | 43 | self.deferred_sync = [] |
| 44 | |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 45 | self.ordered_nodetemplates = [] |
| 46 | self.ordered_names = self.topsort_dependencies() |
Scott Baker | 9d17886 | 2015-09-03 14:32:48 -0700 | [diff] [blame] | 47 | self.log("ordered_names: %s" % self.ordered_names) |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 48 | for name in self.ordered_names: |
| 49 | if name in self.nodetemplates_by_name: |
| 50 | self.ordered_nodetemplates.append(self.nodetemplates_by_name[name]) |
| 51 | |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 52 | #pdb.set_trace() |
| 53 | |
Scott Baker | e08b456 | 2015-08-11 17:23:52 -0700 | [diff] [blame] | 54 | def log(self, msg): |
| 55 | if self.log_to_console: |
| 56 | print msg |
| 57 | self.log_msgs.append(msg) |
| 58 | |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 59 | def compute_dependencies(self): |
| 60 | nodetemplates_by_name = {} |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 61 | for nodetemplate in self.template.nodetemplates: |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 62 | nodetemplates_by_name[nodetemplate.name] = nodetemplate |
| 63 | |
| 64 | self.nodetemplates_by_name = nodetemplates_by_name |
| 65 | |
| 66 | for nodetemplate in self.template.nodetemplates: |
| 67 | nodetemplate.dependencies = [] |
| 68 | nodetemplate.dependencies_names = [] |
| 69 | for reqs in nodetemplate.requirements: |
| 70 | for (k,v) in reqs.items(): |
| 71 | name = v["node"] |
| 72 | if (name in nodetemplates_by_name): |
| 73 | nodetemplate.dependencies.append(nodetemplates_by_name[name]) |
| 74 | nodetemplate.dependencies_names.append(name) |
| 75 | |
Scott Baker | f828c3e | 2015-08-05 18:23:14 -0700 | [diff] [blame] | 76 | # go another level deep, as our requirements can have requirements... |
| 77 | for sd_req in v.get("requirements",[]): |
| 78 | for (sd_req_k, sd_req_v) in sd_req.items(): |
| 79 | name = sd_req_v["node"] |
| 80 | if (name in nodetemplates_by_name): |
| 81 | nodetemplate.dependencies.append(nodetemplates_by_name[name]) |
| 82 | nodetemplate.dependencies_names.append(name) |
| 83 | |
| 84 | |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 85 | def topsort_dependencies(self): |
| 86 | # stolen from observer |
| 87 | g = self.nodetemplates_by_name |
| 88 | |
| 89 | # Get set of all nodes, including those without outgoing edges |
| 90 | keys = set(g.keys()) |
| 91 | values = set({}) |
| 92 | for v in g.values(): |
| 93 | values=values | set(v.dependencies_names) |
| 94 | |
| 95 | all_nodes=list(keys|values) |
| 96 | steps = all_nodes |
| 97 | |
| 98 | # Final order |
| 99 | order = [] |
| 100 | |
| 101 | # DFS stack, not using recursion |
| 102 | stack = [] |
| 103 | |
| 104 | # Unmarked set |
| 105 | unmarked = all_nodes |
| 106 | |
| 107 | # visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small |
| 108 | |
| 109 | while unmarked: |
| 110 | stack.insert(0,unmarked[0]) # push first unmarked |
| 111 | |
| 112 | while (stack): |
| 113 | n = stack[0] |
| 114 | add = True |
| 115 | try: |
| 116 | for m in g[n].dependencies_names: |
| 117 | if (m in unmarked): |
| 118 | add = False |
| 119 | stack.insert(0,m) |
| 120 | except KeyError: |
| 121 | pass |
| 122 | if (add): |
| 123 | if (n in steps and n not in order): |
| 124 | order.append(n) |
| 125 | item = stack.pop(0) |
| 126 | try: |
| 127 | unmarked.remove(item) |
| 128 | except ValueError: |
| 129 | pass |
| 130 | |
| 131 | noorder = list(set(steps) - set(order)) |
| 132 | return order + noorder |
| 133 | |
| 134 | def execute(self, user): |
Scott Baker | 13399c0 | 2015-08-05 16:35:09 -0700 | [diff] [blame] | 135 | for nodetemplate in self.ordered_nodetemplates: |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 136 | self.execute_nodetemplate(user, nodetemplate) |
| 137 | |
Scott Baker | 404c46d | 2015-08-24 15:50:03 -0700 | [diff] [blame] | 138 | for obj in self.deferred_sync: |
| 139 | self.log("Saving deferred sync obj %s" % obj) |
| 140 | obj.no_sync = False |
| 141 | obj.save() |
| 142 | |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 143 | def execute_nodetemplate(self, user, nodetemplate): |
Scott Baker | 3841b37 | 2015-08-03 14:20:31 -0700 | [diff] [blame] | 144 | if nodetemplate.type in resources.resources: |
| 145 | cls = resources.resources[nodetemplate.type] |
Scott Baker | c4005d0 | 2015-08-06 17:21:34 -0700 | [diff] [blame] | 146 | #print "work on", cls.__name__, nodetemplate.name |
Scott Baker | 5d43214 | 2015-08-07 17:06:47 -0700 | [diff] [blame] | 147 | obj = cls(user, nodetemplate, self) |
Scott Baker | 9fdb39f | 2015-08-04 16:44:18 -0700 | [diff] [blame] | 148 | obj.create_or_update() |
Scott Baker | 404c46d | 2015-08-24 15:50:03 -0700 | [diff] [blame] | 149 | self.deferred_sync = self.deferred_sync + obj.deferred_sync |
Scott Baker | 7e472dd | 2015-07-31 12:30:28 -0700 | [diff] [blame] | 150 | |
Scott Baker | 8899be9 | 2015-08-04 17:02:29 -0700 | [diff] [blame] | 151 | def destroy(self, user): |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 152 | nodetemplates = self.ordered_nodetemplates |
Scott Baker | 8899be9 | 2015-08-04 17:02:29 -0700 | [diff] [blame] | 153 | models = [] |
Scott Baker | 9fdffff | 2015-08-04 23:52:18 -0700 | [diff] [blame] | 154 | for nodetemplate in nodetemplates: |
Scott Baker | 8899be9 | 2015-08-04 17:02:29 -0700 | [diff] [blame] | 155 | if nodetemplate.type in resources.resources: |
| 156 | cls = resources.resources[nodetemplate.type] |
Scott Baker | 5d43214 | 2015-08-07 17:06:47 -0700 | [diff] [blame] | 157 | obj = cls(user, nodetemplate, self) |
Scott Baker | 13399c0 | 2015-08-05 16:35:09 -0700 | [diff] [blame] | 158 | for model in obj.get_existing_objs(): |
| 159 | models.append( (obj, model) ) |
Scott Baker | 8899be9 | 2015-08-04 17:02:29 -0700 | [diff] [blame] | 160 | models.reverse() |
Scott Baker | 13399c0 | 2015-08-05 16:35:09 -0700 | [diff] [blame] | 161 | for (resource,model) in models: |
Scott Baker | 13399c0 | 2015-08-05 16:35:09 -0700 | [diff] [blame] | 162 | resource.delete(model) |
Scott Baker | 6656672 | 2015-07-27 17:42:39 -0700 | [diff] [blame] | 163 | |
Scott Baker | 5d43214 | 2015-08-07 17:06:47 -0700 | [diff] [blame] | 164 | def name_to_xos_class(self, user, name): |
| 165 | nt = self.nodetemplates_by_name.get(name) |
| 166 | if not nt: |
| 167 | raise Exception("failed to find nodetemplate %s" % name) |
| 168 | |
| 169 | cls = resources.resources.get(nt.type) |
| 170 | if not cls: |
| 171 | raise Exception("nodetemplate %s's type does not resolve to a known resource type" % name) |
| 172 | |
| 173 | return (nt, cls, cls.xos_model) |
| 174 | |
| 175 | def name_to_xos_model(self, user, name): |
| 176 | (nt, cls, model_class) = self.name_to_xos_class(user, name) |
| 177 | obj = cls(user, nt, self) |
| 178 | existing_objs = obj.get_existing_objs() |
| 179 | if not existing_objs: |
| 180 | raise Exception("failed to find xos %s %s" % (cls.__name__, name)) |
| 181 | return existing_objs[0] |
| 182 | |