blob: e70cfa99faf5898cf114c6e4af9d4c9b4f0e8060 [file] [log] [blame]
Scott Baker35a99532015-08-31 16:18:08 -07001import os
Scott Baker714d5242015-08-05 08:20:12 -07002import pdb
Scott Baker35a99532015-08-31 16:18:08 -07003import json
Scott Bakerf65591f2015-09-28 16:01:21 -07004import subprocess
Scott Baker714d5242015-08-05 08:20:12 -07005
Scott Baker07c71fc2015-09-24 15:37:16 -07006from core.models import User
7
Scott Baker3841b372015-08-03 14:20:31 -07008class XOSResource(object):
9 xos_base_class = "XOSResource"
Scott Baker9fdb39f2015-08-04 16:44:18 -070010 xos_model = None
Scott Baker2142bd72015-08-10 17:08:02 -070011 name_field = "name"
12 copyin_props = []
Scott Baker3841b372015-08-03 14:20:31 -070013 provides = None
14
Scott Baker5d432142015-08-07 17:06:47 -070015 def __init__(self, user, nodetemplate, engine):
Scott Baker9fce62e2015-08-03 15:43:54 -070016 self.dirty = False
Scott Baker404c46d2015-08-24 15:50:03 -070017 self.deferred_sync = []
Scott Baker3841b372015-08-03 14:20:31 -070018 self.user = user
19 self.nodetemplate = nodetemplate
Scott Baker5d432142015-08-07 17:06:47 -070020 self.engine = engine
Scott Baker3841b372015-08-03 14:20:31 -070021
Scott Baker642dbb52016-04-25 14:55:22 -070022 @property
23 def full_name(self):
24 return self.nodetemplate.name
25
26 @property
27 def obj_name(self):
28 if "#" in self.nodetemplate.name:
Scott Baker38265222016-04-25 15:19:03 -070029 return self.nodetemplate.name.split("#",1)[1]
Scott Baker642dbb52016-04-25 14:55:22 -070030 else:
31 return self.nodetemplate.name
32
Scott Baker32795252015-08-04 23:53:07 -070033 def get_all_required_node_names(self):
34 results = []
35 for reqs in self.nodetemplate.requirements:
36 for (k,v) in reqs.items():
37 results.append(v["node"])
38 return results
39
Scott Baker14152942015-08-04 10:59:29 -070040 def get_requirements(self, relationship_name, throw_exception=False):
Scott Baker9fce62e2015-08-03 15:43:54 -070041 """ helper to search the list of requirements for a particular relationship
42 type.
43 """
Scott Baker14152942015-08-04 10:59:29 -070044
45 results = []
Scott Baker9fce62e2015-08-03 15:43:54 -070046 for reqs in self.nodetemplate.requirements:
47 for (k,v) in reqs.items():
48 if (v["relationship"] == relationship_name):
Scott Baker14152942015-08-04 10:59:29 -070049 results.append(v["node"])
Scott Baker9fce62e2015-08-03 15:43:54 -070050
Scott Baker14152942015-08-04 10:59:29 -070051 if (not results) and throw_exception:
Scott Baker642dbb52016-04-25 14:55:22 -070052 raise Exception("Failed to find requirement in %s using relationship %s" % (self.full_name, relationship_name))
Scott Baker9fce62e2015-08-03 15:43:54 -070053
Scott Baker14152942015-08-04 10:59:29 -070054 return results
55
56 def get_requirement(self, relationship_name, throw_exception=False):
57 reqs = self.get_requirements(relationship_name, throw_exception)
58 if not reqs:
59 return None
60 return reqs[0]
Scott Baker9fce62e2015-08-03 15:43:54 -070061
Scott Baker714d5242015-08-05 08:20:12 -070062 def get_scalable(self):
Scott Baker502400a2015-08-05 10:41:51 -070063 scalable = self.nodetemplate.get_capabilities().get("scalable", None)
64 if scalable:
65 return {"min_instances": scalable.get_property_value("min_instances"),
66 "max_instances": scalable.get_property_value("max_instances"),
67 "default_instances": scalable.get_property_value("default_instances")}
Scott Baker714d5242015-08-05 08:20:12 -070068 else:
69 return {}
70
Scott Baker35a99532015-08-31 16:18:08 -070071 def get_property(self, name):
72 return self.nodetemplate.get_property_value(name)
Scott Baker068b1182015-08-05 18:34:23 -070073
Scott Baker33142872015-10-08 16:51:34 -070074 def get_property_default(self, name, default=None):
75 props = self.nodetemplate.get_properties()
Sapan Bhatia16be1432016-01-14 11:41:38 -050076 if props and name in props.keys():
Scott Baker33142872015-10-08 16:51:34 -070077 return props[name].value
78 return default
79
Scott Baker5fcce042015-08-24 16:25:46 -070080 def get_xos_object(self, cls, throw_exception=True, **kwargs):
Scott Baker9fce62e2015-08-03 15:43:54 -070081 objs = cls.objects.filter(**kwargs)
82 if not objs:
Scott Baker5fcce042015-08-24 16:25:46 -070083 if throw_exception:
84 raise Exception("Failed to find %s filtered by %s" % (cls.__name__, str(kwargs)))
85 return None
Scott Baker9fce62e2015-08-03 15:43:54 -070086 return objs[0]
87
Scott Baker9fdb39f2015-08-04 16:44:18 -070088 def get_existing_objs(self):
Scott Baker642dbb52016-04-25 14:55:22 -070089 return self.xos_model.objects.filter(**{self.name_field: self.obj_name})
Scott Baker9fdb39f2015-08-04 16:44:18 -070090
Scott Bakerc0581502015-09-01 22:57:46 -070091 def get_model_class_name(self):
92 return self.xos_model.__name__
93
Scott Baker9fdb39f2015-08-04 16:44:18 -070094 def create_or_update(self):
95 existing_objs = self.get_existing_objs()
96 if existing_objs:
Scott Baker33142872015-10-08 16:51:34 -070097 if self.get_property_default("no-update", False):
Scott Baker642dbb52016-04-25 14:55:22 -070098 self.info("%s:%s (%s) already exists. Skipping update due to 'no-update' property" % (self.get_model_class_name(), self.obj_name, self.full_name))
Scott Baker33142872015-10-08 16:51:34 -070099 else:
Scott Baker642dbb52016-04-25 14:55:22 -0700100 self.info("%s:%s (%s) already exists" % (self.get_model_class_name(), self.obj_name, self.full_name))
Scott Baker33142872015-10-08 16:51:34 -0700101 self.update(existing_objs[0])
Scott Baker9fdb39f2015-08-04 16:44:18 -0700102 else:
Scott Baker33142872015-10-08 16:51:34 -0700103 if self.get_property_default("no-create", False):
Scott Baker642dbb52016-04-25 14:55:22 -0700104 self.info("%s:%s (%s) does not exist, but 'no-create' is specified" % (self.get_model_class_name(), self.obj_name, self.full_name))
Scott Baker33142872015-10-08 16:51:34 -0700105 else:
106 self.create()
Scott Baker9fdb39f2015-08-04 16:44:18 -0700107
Scott Baker61c43112015-08-12 19:06:16 -0700108 def can_delete(self, obj):
Scott Baker33142872015-10-08 16:51:34 -0700109 if self.get_property_default("no-delete",False):
Scott Baker642dbb52016-04-25 14:55:22 -0700110 self.info("%s:%s %s is marked 'no-delete'. Skipping delete." % (self.get_model_class_name(), self.obj_name, self.full_name))
Scott Baker33142872015-10-08 16:51:34 -0700111 return False
Scott Baker61c43112015-08-12 19:06:16 -0700112 return True
Scott Baker2142bd72015-08-10 17:08:02 -0700113
Scott Baker07c71fc2015-09-24 15:37:16 -0700114 def postprocess_privileges(self, roleclass, privclass, rolemap, obj, toFieldName):
Scott Baker92362bc2015-09-24 15:22:46 -0700115 for (rel, role) in rolemap:
116 for email in self.get_requirements(rel):
Scott Baker688c4dd2016-01-27 19:00:06 -0800117 role_obj = self.get_xos_object(roleclass, throw_exception=False, role=role)
118 if not role_obj:
119 # if the role doesn't exist, make it
120 self.info("Creating %s %s" % (roleclass.__name__, role))
121 role_obj = roleclass(role=role)
122 role_obj.save()
123
Scott Baker92362bc2015-09-24 15:22:46 -0700124 user = self.get_xos_object(User, email=email)
Scott Baker688c4dd2016-01-27 19:00:06 -0800125 if not privclass.objects.filter(user=user, role=role_obj, **{toFieldName: obj}):
126 sp = privclass(user=user, role=role_obj, **{toFieldName: obj})
Scott Baker92362bc2015-09-24 15:22:46 -0700127 sp.save()
128 self.info("Added privilege on %s role %s for %s" % (str(obj), str(role), str(user)))
129
Scott Baker2142bd72015-08-10 17:08:02 -0700130 def postprocess(self, obj):
131 pass
132
Scott Baker35a99532015-08-31 16:18:08 -0700133 def intrinsic_get_artifact(self, obj=None, name=None, method=None):
134 if obj!="SELF":
135 raise Exception("only SELF is supported for get_artifact first arg")
136 if method!="LOCAL_FILE":
137 raise Exception("only LOCAL_FILE is supported for get_artifact third arg")
138
139 for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items():
140 if k == name:
141 if not os.path.exists(v):
142 raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k))
143 return open(v).read()
144
145 raise Exception("artifact %s not found" % name)
146
Scott Bakerf65591f2015-09-28 16:01:21 -0700147 def intrinsic_get_script_env(self, obj=None, name=None, varname=None, method=None):
148 if obj!="SELF":
149 raise Exception("only SELF is supported for get_artifact first arg")
150 if method!="LOCAL_FILE":
151 raise Exception("only LOCAL_FILE is supported for get_artifact fourth arg")
152
153 for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items():
154 if k == name:
155 if not os.path.exists(v):
156 raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k))
157 return subprocess.Popen('/bin/bash -c "source %s &> /dev/null; echo \\$%s"' % (v, varname), shell=True, stdout=subprocess.PIPE).stdout.read().strip()
158
159 raise Exception("artifact %s not found" % name)
160
Scott Baker35a99532015-08-31 16:18:08 -0700161 def try_intrinsic_function(self, v):
162 try:
163 jsv = v.replace("'", '"')
164 jsv = json.loads(jsv)
165 except:
166 #import traceback
167 #traceback.print_exc()
168 return v
169
170 if type(jsv)!=dict:
171 return v
172
173 if "get_artifact" in jsv:
174 return self.intrinsic_get_artifact(*jsv["get_artifact"])
Scott Bakerf65591f2015-09-28 16:01:21 -0700175 elif "get_script_env" in jsv:
176 return self.intrinsic_get_script_env(*jsv["get_script_env"])
Scott Baker35a99532015-08-31 16:18:08 -0700177
178 return v
179
Scott Baker2142bd72015-08-10 17:08:02 -0700180 def get_xos_args(self):
181 args = {}
182
183 if self.name_field:
Scott Baker642dbb52016-04-25 14:55:22 -0700184 args[self.name_field] = self.obj_name
Scott Baker2142bd72015-08-10 17:08:02 -0700185
186 # copy simple string properties from the template into the arguments
187 for prop in self.copyin_props:
188 v = self.get_property(prop)
Scott Baker35a99532015-08-31 16:18:08 -0700189
190 v = self.try_intrinsic_function(v)
191
Scott Baker744f9a12015-09-02 16:29:16 -0700192 if v is not None:
Scott Baker2142bd72015-08-10 17:08:02 -0700193 args[prop] = v
194
195 return args
196
Scott Baker9fdb39f2015-08-04 16:44:18 -0700197 def create(self):
Scott Baker2142bd72015-08-10 17:08:02 -0700198 xos_args = self.get_xos_args()
199 xos_obj = self.xos_model(**xos_args)
Scott Baker4ce7d4f2016-04-22 09:26:18 -0700200 if self.user:
201 xos_obj.caller = self.user
Scott Baker2142bd72015-08-10 17:08:02 -0700202 xos_obj.save()
203
Scott Baker2142bd72015-08-10 17:08:02 -0700204 self.info("Created %s '%s'" % (self.xos_model.__name__,str(xos_obj)))
Scott Baker9fdb39f2015-08-04 16:44:18 -0700205
Scott Baker37937722015-08-14 12:41:18 -0700206 self.postprocess(xos_obj)
207
Scott Baker9fdb39f2015-08-04 16:44:18 -0700208 def update(self, obj):
Scott Baker744f9a12015-09-02 16:29:16 -0700209 xos_args = self.get_xos_args()
Scott Baker41916c92015-09-03 12:15:50 -0700210 for (k,v) in xos_args.items():
211 setattr(obj, k, v)
Scott Bakereb2aa3c2015-09-03 14:52:22 -0700212 self.postprocess(obj)
Scott Baker744f9a12015-09-02 16:29:16 -0700213 obj.save()
Scott Baker3841b372015-08-03 14:20:31 -0700214
Scott Baker13399c02015-08-05 16:35:09 -0700215 def delete(self, obj):
Scott Baker61c43112015-08-12 19:06:16 -0700216 if (self.can_delete(obj)):
217 self.info("destroying object %s" % str(obj))
218 obj.delete(purge=True) # XXX TODO: turn off purge before production
Scott Baker13399c02015-08-05 16:35:09 -0700219
Scott Baker9fce62e2015-08-03 15:43:54 -0700220 def info(self, s):
Scott Bakere08b4562015-08-11 17:23:52 -0700221 self.engine.log(s)
Scott Baker9fce62e2015-08-03 15:43:54 -0700222