blob: 62f18dbebf2ae41f64d30df0668fe5f057b19f23 [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 Bakerbf811362015-08-24 16:25:46 -070063 def get_xos_object(self, cls, throw_exception=True, **kwargs):
Scott Baker3fb49312015-08-03 15:43:54 -070064 objs = cls.objects.filter(**kwargs)
65 if not objs:
Scott Bakerbf811362015-08-24 16:25:46 -070066 if throw_exception:
67 raise Exception("Failed to find %s filtered by %s" % (cls.__name__, str(kwargs)))
68 return None
Scott Baker3fb49312015-08-03 15:43:54 -070069 return objs[0]
70
Scott Bakere4f9c2c2015-08-04 16:44:18 -070071 def get_existing_objs(self):
Scott Baker9d2d0122015-08-12 19:06:16 -070072 return self.xos_model.objects.filter(**{self.name_field: self.nodetemplate.name})
Scott Bakere4f9c2c2015-08-04 16:44:18 -070073
74 def get_xos_args(self):
75 return {}
76
Scott Baker0601cde2015-09-01 22:57:46 -070077 def get_model_class_name(self):
78 return self.xos_model.__name__
79
Scott Bakere4f9c2c2015-08-04 16:44:18 -070080 def create_or_update(self):
81 existing_objs = self.get_existing_objs()
82 if existing_objs:
Scott Baker0601cde2015-09-01 22:57:46 -070083 self.info("%s %s already exists" % (self.get_model_class_name(), self.nodetemplate.name))
Scott Bakere4f9c2c2015-08-04 16:44:18 -070084 self.update(existing_objs[0])
85 else:
86 self.create()
87
Scott Baker9d2d0122015-08-12 19:06:16 -070088 def can_delete(self, obj):
89 return True
Scott Baker874960b2015-08-10 17:08:02 -070090
Scott Baker5329d3a2015-09-24 15:37:16 -070091 def postprocess_privileges(self, roleclass, privclass, rolemap, obj, toFieldName):
Scott Bakerb2e44172015-09-24 15:22:46 -070092 for (rel, role) in rolemap:
93 for email in self.get_requirements(rel):
94 role = self.get_xos_object(roleclass, role=role)
95 user = self.get_xos_object(User, email=email)
Scott Baker5329d3a2015-09-24 15:37:16 -070096 if not privclass.objects.filter(user=user, role=role, **{toFieldName: obj}):
97 sp = privclass(user=user, role=role, **{toFieldName: obj})
Scott Bakerb2e44172015-09-24 15:22:46 -070098 sp.save()
99 self.info("Added privilege on %s role %s for %s" % (str(obj), str(role), str(user)))
100
Scott Baker874960b2015-08-10 17:08:02 -0700101 def postprocess(self, obj):
102 pass
103
Scott Bakerf5d79172015-08-31 16:18:08 -0700104 def intrinsic_get_artifact(self, obj=None, name=None, method=None):
105 if obj!="SELF":
106 raise Exception("only SELF is supported for get_artifact first arg")
107 if method!="LOCAL_FILE":
108 raise Exception("only LOCAL_FILE is supported for get_artifact third arg")
109
110 for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items():
111 if k == name:
112 if not os.path.exists(v):
113 raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k))
114 return open(v).read()
115
116 raise Exception("artifact %s not found" % name)
117
Scott Baker04abc4e2015-09-28 16:01:21 -0700118 def intrinsic_get_script_env(self, obj=None, name=None, varname=None, method=None):
119 if obj!="SELF":
120 raise Exception("only SELF is supported for get_artifact first arg")
121 if method!="LOCAL_FILE":
122 raise Exception("only LOCAL_FILE is supported for get_artifact fourth arg")
123
124 for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items():
125 if k == name:
126 if not os.path.exists(v):
127 raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k))
128 return subprocess.Popen('/bin/bash -c "source %s &> /dev/null; echo \\$%s"' % (v, varname), shell=True, stdout=subprocess.PIPE).stdout.read().strip()
129
130 raise Exception("artifact %s not found" % name)
131
Scott Bakerf5d79172015-08-31 16:18:08 -0700132 def try_intrinsic_function(self, v):
133 try:
134 jsv = v.replace("'", '"')
135 jsv = json.loads(jsv)
136 except:
137 #import traceback
138 #traceback.print_exc()
139 return v
140
141 if type(jsv)!=dict:
142 return v
143
144 if "get_artifact" in jsv:
145 return self.intrinsic_get_artifact(*jsv["get_artifact"])
Scott Baker04abc4e2015-09-28 16:01:21 -0700146 elif "get_script_env" in jsv:
147 return self.intrinsic_get_script_env(*jsv["get_script_env"])
Scott Bakerf5d79172015-08-31 16:18:08 -0700148
149 return v
150
Scott Baker874960b2015-08-10 17:08:02 -0700151 def get_xos_args(self):
152 args = {}
153
154 if self.name_field:
155 args[self.name_field] = self.nodetemplate.name
156
157 # copy simple string properties from the template into the arguments
158 for prop in self.copyin_props:
159 v = self.get_property(prop)
Scott Bakerf5d79172015-08-31 16:18:08 -0700160
161 v = self.try_intrinsic_function(v)
162
Scott Baker5b1ff4c2015-09-02 16:29:16 -0700163 if v is not None:
Scott Baker874960b2015-08-10 17:08:02 -0700164 args[prop] = v
165
166 return args
167
Scott Bakere4f9c2c2015-08-04 16:44:18 -0700168 def create(self):
Scott Baker874960b2015-08-10 17:08:02 -0700169 xos_args = self.get_xos_args()
170 xos_obj = self.xos_model(**xos_args)
171 xos_obj.caller = self.user
172 xos_obj.save()
173
Scott Baker874960b2015-08-10 17:08:02 -0700174 self.info("Created %s '%s'" % (self.xos_model.__name__,str(xos_obj)))
Scott Bakere4f9c2c2015-08-04 16:44:18 -0700175
Scott Baker2edd4f32015-08-14 12:41:18 -0700176 self.postprocess(xos_obj)
177
Scott Bakere4f9c2c2015-08-04 16:44:18 -0700178 def update(self, obj):
Scott Baker5b1ff4c2015-09-02 16:29:16 -0700179 xos_args = self.get_xos_args()
Scott Baker91073872015-09-03 12:15:50 -0700180 for (k,v) in xos_args.items():
181 setattr(obj, k, v)
Scott Baker327269f2015-09-03 14:52:22 -0700182 self.postprocess(obj)
Scott Baker5b1ff4c2015-09-02 16:29:16 -0700183 obj.save()
Scott Bakerdcd865b2015-08-03 14:20:31 -0700184
Scott Baker4ee562b2015-08-05 16:35:09 -0700185 def delete(self, obj):
Scott Baker9d2d0122015-08-12 19:06:16 -0700186 if (self.can_delete(obj)):
187 self.info("destroying object %s" % str(obj))
188 obj.delete(purge=True) # XXX TODO: turn off purge before production
Scott Baker4ee562b2015-08-05 16:35:09 -0700189
Scott Baker3fb49312015-08-03 15:43:54 -0700190 def info(self, s):
Scott Bakera9022e32015-08-11 17:23:52 -0700191 self.engine.log(s)
Scott Baker3fb49312015-08-03 15:43:54 -0700192