blob: 3553ab13b09cd373120dea417faea0cc1242e4ae [file] [log] [blame]
Scott Bakerf5d79172015-08-31 16:18:08 -07001import os
Scott Bakerf92533a2015-08-05 08:20:12 -07002import pdb
Scott Bakerf5d79172015-08-31 16:18:08 -07003import json
Scott Baker04abc4e2015-09-28 16:01:21 -07004import subprocess
Scott Bakerf92533a2015-08-05 08:20:12 -07005
Scott Baker5329d3a2015-09-24 15:37:16 -07006from core.models import User
7
Scott Bakerdcd865b2015-08-03 14:20:31 -07008class XOSResource(object):
9 xos_base_class = "XOSResource"
Scott Bakere4f9c2c2015-08-04 16:44:18 -070010 xos_model = None
Scott Baker874960b2015-08-10 17:08:02 -070011 name_field = "name"
12 copyin_props = []
Scott Bakerdcd865b2015-08-03 14:20:31 -070013 provides = None
14
Scott Bakerb31659b2015-08-07 17:06:47 -070015 def __init__(self, user, nodetemplate, engine):
Scott Baker3fb49312015-08-03 15:43:54 -070016 self.dirty = False
Scott Baker395bf522015-08-24 15:50:03 -070017 self.deferred_sync = []
Scott Bakerdcd865b2015-08-03 14:20:31 -070018 self.user = user
19 self.nodetemplate = nodetemplate
Scott Bakerb31659b2015-08-07 17:06:47 -070020 self.engine = engine
Scott Bakerdcd865b2015-08-03 14:20:31 -070021
Scott Bakera7058922015-08-04 23:53:07 -070022 def get_all_required_node_names(self):
23 results = []
24 for reqs in self.nodetemplate.requirements:
25 for (k,v) in reqs.items():
26 results.append(v["node"])
27 return results
28
Scott Baker1a609522015-08-04 10:59:29 -070029 def get_requirements(self, relationship_name, throw_exception=False):
Scott Baker3fb49312015-08-03 15:43:54 -070030 """ helper to search the list of requirements for a particular relationship
31 type.
32 """
Scott Baker1a609522015-08-04 10:59:29 -070033
34 results = []
Scott Baker3fb49312015-08-03 15:43:54 -070035 for reqs in self.nodetemplate.requirements:
36 for (k,v) in reqs.items():
37 if (v["relationship"] == relationship_name):
Scott Baker1a609522015-08-04 10:59:29 -070038 results.append(v["node"])
Scott Baker3fb49312015-08-03 15:43:54 -070039
Scott Baker1a609522015-08-04 10:59:29 -070040 if (not results) and throw_exception:
Scott Baker3fb49312015-08-03 15:43:54 -070041 raise Exception("Failed to find requirement in %s using relationship %s" % (self.nodetemplate.name, relationship_name))
42
Scott Baker1a609522015-08-04 10:59:29 -070043 return results
44
45 def get_requirement(self, relationship_name, throw_exception=False):
46 reqs = self.get_requirements(relationship_name, throw_exception)
47 if not reqs:
48 return None
49 return reqs[0]
Scott Baker3fb49312015-08-03 15:43:54 -070050
Scott Bakerf92533a2015-08-05 08:20:12 -070051 def get_scalable(self):
Scott Bakerb9fec932015-08-05 10:41:51 -070052 scalable = self.nodetemplate.get_capabilities().get("scalable", None)
53 if scalable:
54 return {"min_instances": scalable.get_property_value("min_instances"),
55 "max_instances": scalable.get_property_value("max_instances"),
56 "default_instances": scalable.get_property_value("default_instances")}
Scott Bakerf92533a2015-08-05 08:20:12 -070057 else:
58 return {}
59
Scott Bakerf5d79172015-08-31 16:18:08 -070060 def get_property(self, name):
61 return self.nodetemplate.get_property_value(name)
Scott Baker6382db22015-08-05 18:34:23 -070062
Scott Bakerfe0ce732015-10-08 16:51:34 -070063 def get_property_default(self, name, default=None):
64 props = self.nodetemplate.get_properties()
65 if props and name in props.keys():
66 return props[name].value
67 return default
68
Scott Bakerbf811362015-08-24 16:25:46 -070069 def get_xos_object(self, cls, throw_exception=True, **kwargs):
Scott Baker3fb49312015-08-03 15:43:54 -070070 objs = cls.objects.filter(**kwargs)
71 if not objs:
Scott Bakerbf811362015-08-24 16:25:46 -070072 if throw_exception:
73 raise Exception("Failed to find %s filtered by %s" % (cls.__name__, str(kwargs)))
74 return None
Scott Baker3fb49312015-08-03 15:43:54 -070075 return objs[0]
76
Scott Bakere4f9c2c2015-08-04 16:44:18 -070077 def get_existing_objs(self):
Scott Baker9d2d0122015-08-12 19:06:16 -070078 return self.xos_model.objects.filter(**{self.name_field: self.nodetemplate.name})
Scott Bakere4f9c2c2015-08-04 16:44:18 -070079
80 def get_xos_args(self):
81 return {}
82
Scott Baker0601cde2015-09-01 22:57:46 -070083 def get_model_class_name(self):
84 return self.xos_model.__name__
85
Scott Bakere4f9c2c2015-08-04 16:44:18 -070086 def create_or_update(self):
87 existing_objs = self.get_existing_objs()
88 if existing_objs:
Scott Bakerfe0ce732015-10-08 16:51:34 -070089 if self.get_property_default("no-update", False):
90 self.info("%s %s already exists. Skipping update due to 'no-update' property" % (self.get_model_class_name(), self.nodetemplate.name))
91 else:
92 self.info("%s %s already exists" % (self.get_model_class_name(), self.nodetemplate.name))
93 self.update(existing_objs[0])
Scott Bakere4f9c2c2015-08-04 16:44:18 -070094 else:
Scott Bakerfe0ce732015-10-08 16:51:34 -070095 if self.get_property_default("no-create", False):
96 self.info("%s %s does not exist, but 'no-create' is specified" % (self.get_model_class_name(), self.nodetemplate.name))
97 else:
98 self.create()
Scott Bakere4f9c2c2015-08-04 16:44:18 -070099
Scott Baker9d2d0122015-08-12 19:06:16 -0700100 def can_delete(self, obj):
Scott Bakerfe0ce732015-10-08 16:51:34 -0700101 if self.get_property_default("no-delete",False):
102 self.info("%s %s is marked 'no-delete'. Skipping delete." % (self.get_model_class_name(), self.nodetemplate.name))
103 return False
Scott Baker9d2d0122015-08-12 19:06:16 -0700104 return True
Scott Baker874960b2015-08-10 17:08:02 -0700105
Scott Baker5329d3a2015-09-24 15:37:16 -0700106 def postprocess_privileges(self, roleclass, privclass, rolemap, obj, toFieldName):
Scott Bakerb2e44172015-09-24 15:22:46 -0700107 for (rel, role) in rolemap:
108 for email in self.get_requirements(rel):
109 role = self.get_xos_object(roleclass, role=role)
110 user = self.get_xos_object(User, email=email)
Scott Baker5329d3a2015-09-24 15:37:16 -0700111 if not privclass.objects.filter(user=user, role=role, **{toFieldName: obj}):
112 sp = privclass(user=user, role=role, **{toFieldName: obj})
Scott Bakerb2e44172015-09-24 15:22:46 -0700113 sp.save()
114 self.info("Added privilege on %s role %s for %s" % (str(obj), str(role), str(user)))
115
Scott Baker874960b2015-08-10 17:08:02 -0700116 def postprocess(self, obj):
117 pass
118
Scott Bakerf5d79172015-08-31 16:18:08 -0700119 def intrinsic_get_artifact(self, obj=None, name=None, method=None):
120 if obj!="SELF":
121 raise Exception("only SELF is supported for get_artifact first arg")
122 if method!="LOCAL_FILE":
123 raise Exception("only LOCAL_FILE is supported for get_artifact third arg")
124
125 for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items():
126 if k == name:
127 if not os.path.exists(v):
128 raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k))
129 return open(v).read()
130
131 raise Exception("artifact %s not found" % name)
132
Scott Baker04abc4e2015-09-28 16:01:21 -0700133 def intrinsic_get_script_env(self, obj=None, name=None, varname=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 fourth 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 subprocess.Popen('/bin/bash -c "source %s &> /dev/null; echo \\$%s"' % (v, varname), shell=True, stdout=subprocess.PIPE).stdout.read().strip()
144
145 raise Exception("artifact %s not found" % name)
146
Scott Bakerf5d79172015-08-31 16:18:08 -0700147 def try_intrinsic_function(self, v):
148 try:
149 jsv = v.replace("'", '"')
150 jsv = json.loads(jsv)
151 except:
152 #import traceback
153 #traceback.print_exc()
154 return v
155
156 if type(jsv)!=dict:
157 return v
158
159 if "get_artifact" in jsv:
160 return self.intrinsic_get_artifact(*jsv["get_artifact"])
Scott Baker04abc4e2015-09-28 16:01:21 -0700161 elif "get_script_env" in jsv:
162 return self.intrinsic_get_script_env(*jsv["get_script_env"])
Scott Bakerf5d79172015-08-31 16:18:08 -0700163
164 return v
165
Scott Baker874960b2015-08-10 17:08:02 -0700166 def get_xos_args(self):
167 args = {}
168
169 if self.name_field:
170 args[self.name_field] = self.nodetemplate.name
171
172 # copy simple string properties from the template into the arguments
173 for prop in self.copyin_props:
174 v = self.get_property(prop)
Scott Bakerf5d79172015-08-31 16:18:08 -0700175
176 v = self.try_intrinsic_function(v)
177
Scott Baker5b1ff4c2015-09-02 16:29:16 -0700178 if v is not None:
Scott Baker874960b2015-08-10 17:08:02 -0700179 args[prop] = v
180
181 return args
182
Scott Bakere4f9c2c2015-08-04 16:44:18 -0700183 def create(self):
Scott Baker874960b2015-08-10 17:08:02 -0700184 xos_args = self.get_xos_args()
185 xos_obj = self.xos_model(**xos_args)
186 xos_obj.caller = self.user
187 xos_obj.save()
188
Scott Baker874960b2015-08-10 17:08:02 -0700189 self.info("Created %s '%s'" % (self.xos_model.__name__,str(xos_obj)))
Scott Bakere4f9c2c2015-08-04 16:44:18 -0700190
Scott Baker2edd4f32015-08-14 12:41:18 -0700191 self.postprocess(xos_obj)
192
Scott Bakere4f9c2c2015-08-04 16:44:18 -0700193 def update(self, obj):
Scott Baker5b1ff4c2015-09-02 16:29:16 -0700194 xos_args = self.get_xos_args()
Scott Baker91073872015-09-03 12:15:50 -0700195 for (k,v) in xos_args.items():
196 setattr(obj, k, v)
Scott Baker327269f2015-09-03 14:52:22 -0700197 self.postprocess(obj)
Scott Baker5b1ff4c2015-09-02 16:29:16 -0700198 obj.save()
Scott Bakerdcd865b2015-08-03 14:20:31 -0700199
Scott Baker4ee562b2015-08-05 16:35:09 -0700200 def delete(self, obj):
Scott Baker9d2d0122015-08-12 19:06:16 -0700201 if (self.can_delete(obj)):
202 self.info("destroying object %s" % str(obj))
203 obj.delete(purge=True) # XXX TODO: turn off purge before production
Scott Baker4ee562b2015-08-05 16:35:09 -0700204
Scott Baker3fb49312015-08-03 15:43:54 -0700205 def info(self, s):
Scott Bakera9022e32015-08-11 17:23:52 -0700206 self.engine.log(s)
Scott Baker3fb49312015-08-03 15:43:54 -0700207