Scott Baker | f5d7917 | 2015-08-31 16:18:08 -0700 | [diff] [blame^] | 1 | import os |
Scott Baker | f92533a | 2015-08-05 08:20:12 -0700 | [diff] [blame] | 2 | import pdb |
Scott Baker | f5d7917 | 2015-08-31 16:18:08 -0700 | [diff] [blame^] | 3 | import json |
Scott Baker | f92533a | 2015-08-05 08:20:12 -0700 | [diff] [blame] | 4 | |
Scott Baker | dcd865b | 2015-08-03 14:20:31 -0700 | [diff] [blame] | 5 | class XOSResource(object): |
| 6 | xos_base_class = "XOSResource" |
Scott Baker | e4f9c2c | 2015-08-04 16:44:18 -0700 | [diff] [blame] | 7 | xos_model = None |
Scott Baker | 874960b | 2015-08-10 17:08:02 -0700 | [diff] [blame] | 8 | name_field = "name" |
| 9 | copyin_props = [] |
Scott Baker | dcd865b | 2015-08-03 14:20:31 -0700 | [diff] [blame] | 10 | provides = None |
| 11 | |
Scott Baker | b31659b | 2015-08-07 17:06:47 -0700 | [diff] [blame] | 12 | def __init__(self, user, nodetemplate, engine): |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 13 | self.dirty = False |
Scott Baker | 395bf52 | 2015-08-24 15:50:03 -0700 | [diff] [blame] | 14 | self.deferred_sync = [] |
Scott Baker | dcd865b | 2015-08-03 14:20:31 -0700 | [diff] [blame] | 15 | self.user = user |
| 16 | self.nodetemplate = nodetemplate |
Scott Baker | b31659b | 2015-08-07 17:06:47 -0700 | [diff] [blame] | 17 | self.engine = engine |
Scott Baker | dcd865b | 2015-08-03 14:20:31 -0700 | [diff] [blame] | 18 | |
Scott Baker | a705892 | 2015-08-04 23:53:07 -0700 | [diff] [blame] | 19 | def get_all_required_node_names(self): |
| 20 | results = [] |
| 21 | for reqs in self.nodetemplate.requirements: |
| 22 | for (k,v) in reqs.items(): |
| 23 | results.append(v["node"]) |
| 24 | return results |
| 25 | |
Scott Baker | 1a60952 | 2015-08-04 10:59:29 -0700 | [diff] [blame] | 26 | def get_requirements(self, relationship_name, throw_exception=False): |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 27 | """ helper to search the list of requirements for a particular relationship |
| 28 | type. |
| 29 | """ |
Scott Baker | 1a60952 | 2015-08-04 10:59:29 -0700 | [diff] [blame] | 30 | |
| 31 | results = [] |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 32 | for reqs in self.nodetemplate.requirements: |
| 33 | for (k,v) in reqs.items(): |
| 34 | if (v["relationship"] == relationship_name): |
Scott Baker | 1a60952 | 2015-08-04 10:59:29 -0700 | [diff] [blame] | 35 | results.append(v["node"]) |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 36 | |
Scott Baker | 1a60952 | 2015-08-04 10:59:29 -0700 | [diff] [blame] | 37 | if (not results) and throw_exception: |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 38 | raise Exception("Failed to find requirement in %s using relationship %s" % (self.nodetemplate.name, relationship_name)) |
| 39 | |
Scott Baker | 1a60952 | 2015-08-04 10:59:29 -0700 | [diff] [blame] | 40 | return results |
| 41 | |
| 42 | def get_requirement(self, relationship_name, throw_exception=False): |
| 43 | reqs = self.get_requirements(relationship_name, throw_exception) |
| 44 | if not reqs: |
| 45 | return None |
| 46 | return reqs[0] |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 47 | |
Scott Baker | f92533a | 2015-08-05 08:20:12 -0700 | [diff] [blame] | 48 | def get_scalable(self): |
Scott Baker | b9fec93 | 2015-08-05 10:41:51 -0700 | [diff] [blame] | 49 | scalable = self.nodetemplate.get_capabilities().get("scalable", None) |
| 50 | if scalable: |
| 51 | return {"min_instances": scalable.get_property_value("min_instances"), |
| 52 | "max_instances": scalable.get_property_value("max_instances"), |
| 53 | "default_instances": scalable.get_property_value("default_instances")} |
Scott Baker | f92533a | 2015-08-05 08:20:12 -0700 | [diff] [blame] | 54 | else: |
| 55 | return {} |
| 56 | |
Scott Baker | f5d7917 | 2015-08-31 16:18:08 -0700 | [diff] [blame^] | 57 | def get_property(self, name): |
| 58 | return self.nodetemplate.get_property_value(name) |
Scott Baker | 6382db2 | 2015-08-05 18:34:23 -0700 | [diff] [blame] | 59 | |
Scott Baker | bf81136 | 2015-08-24 16:25:46 -0700 | [diff] [blame] | 60 | def get_xos_object(self, cls, throw_exception=True, **kwargs): |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 61 | objs = cls.objects.filter(**kwargs) |
| 62 | if not objs: |
Scott Baker | bf81136 | 2015-08-24 16:25:46 -0700 | [diff] [blame] | 63 | if throw_exception: |
| 64 | raise Exception("Failed to find %s filtered by %s" % (cls.__name__, str(kwargs))) |
| 65 | return None |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 66 | return objs[0] |
| 67 | |
Scott Baker | e4f9c2c | 2015-08-04 16:44:18 -0700 | [diff] [blame] | 68 | def get_existing_objs(self): |
Scott Baker | 9d2d012 | 2015-08-12 19:06:16 -0700 | [diff] [blame] | 69 | return self.xos_model.objects.filter(**{self.name_field: self.nodetemplate.name}) |
Scott Baker | e4f9c2c | 2015-08-04 16:44:18 -0700 | [diff] [blame] | 70 | |
| 71 | def get_xos_args(self): |
| 72 | return {} |
| 73 | |
| 74 | def create_or_update(self): |
| 75 | existing_objs = self.get_existing_objs() |
| 76 | if existing_objs: |
| 77 | self.info("%s %s already exists" % (self.xos_model.__name__, self.nodetemplate.name)) |
| 78 | self.update(existing_objs[0]) |
| 79 | else: |
| 80 | self.create() |
| 81 | |
Scott Baker | 9d2d012 | 2015-08-12 19:06:16 -0700 | [diff] [blame] | 82 | def can_delete(self, obj): |
| 83 | return True |
Scott Baker | 874960b | 2015-08-10 17:08:02 -0700 | [diff] [blame] | 84 | |
| 85 | def postprocess(self, obj): |
| 86 | pass |
| 87 | |
Scott Baker | f5d7917 | 2015-08-31 16:18:08 -0700 | [diff] [blame^] | 88 | def intrinsic_get_artifact(self, obj=None, name=None, method=None): |
| 89 | if obj!="SELF": |
| 90 | raise Exception("only SELF is supported for get_artifact first arg") |
| 91 | if method!="LOCAL_FILE": |
| 92 | raise Exception("only LOCAL_FILE is supported for get_artifact third arg") |
| 93 | |
| 94 | for (k,v) in self.nodetemplate.entity_tpl.get("artifacts", {}).items(): |
| 95 | if k == name: |
| 96 | if not os.path.exists(v): |
| 97 | raise Exception("Artifact local file %s for artifact %s does not exist" % (v, k)) |
| 98 | return open(v).read() |
| 99 | |
| 100 | raise Exception("artifact %s not found" % name) |
| 101 | |
| 102 | def try_intrinsic_function(self, v): |
| 103 | try: |
| 104 | jsv = v.replace("'", '"') |
| 105 | jsv = json.loads(jsv) |
| 106 | except: |
| 107 | #import traceback |
| 108 | #traceback.print_exc() |
| 109 | return v |
| 110 | |
| 111 | if type(jsv)!=dict: |
| 112 | return v |
| 113 | |
| 114 | if "get_artifact" in jsv: |
| 115 | return self.intrinsic_get_artifact(*jsv["get_artifact"]) |
| 116 | |
| 117 | return v |
| 118 | |
Scott Baker | 874960b | 2015-08-10 17:08:02 -0700 | [diff] [blame] | 119 | def get_xos_args(self): |
| 120 | args = {} |
| 121 | |
| 122 | if self.name_field: |
| 123 | args[self.name_field] = self.nodetemplate.name |
| 124 | |
| 125 | # copy simple string properties from the template into the arguments |
| 126 | for prop in self.copyin_props: |
| 127 | v = self.get_property(prop) |
Scott Baker | f5d7917 | 2015-08-31 16:18:08 -0700 | [diff] [blame^] | 128 | |
| 129 | v = self.try_intrinsic_function(v) |
| 130 | |
Scott Baker | 874960b | 2015-08-10 17:08:02 -0700 | [diff] [blame] | 131 | if v: |
| 132 | args[prop] = v |
| 133 | |
| 134 | return args |
| 135 | |
Scott Baker | e4f9c2c | 2015-08-04 16:44:18 -0700 | [diff] [blame] | 136 | def create(self): |
Scott Baker | 874960b | 2015-08-10 17:08:02 -0700 | [diff] [blame] | 137 | xos_args = self.get_xos_args() |
| 138 | xos_obj = self.xos_model(**xos_args) |
| 139 | xos_obj.caller = self.user |
| 140 | xos_obj.save() |
| 141 | |
Scott Baker | 874960b | 2015-08-10 17:08:02 -0700 | [diff] [blame] | 142 | self.info("Created %s '%s'" % (self.xos_model.__name__,str(xos_obj))) |
Scott Baker | e4f9c2c | 2015-08-04 16:44:18 -0700 | [diff] [blame] | 143 | |
Scott Baker | 2edd4f3 | 2015-08-14 12:41:18 -0700 | [diff] [blame] | 144 | self.postprocess(xos_obj) |
| 145 | |
Scott Baker | e4f9c2c | 2015-08-04 16:44:18 -0700 | [diff] [blame] | 146 | def update(self, obj): |
Scott Baker | dcd865b | 2015-08-03 14:20:31 -0700 | [diff] [blame] | 147 | pass |
| 148 | |
Scott Baker | 4ee562b | 2015-08-05 16:35:09 -0700 | [diff] [blame] | 149 | def delete(self, obj): |
Scott Baker | 9d2d012 | 2015-08-12 19:06:16 -0700 | [diff] [blame] | 150 | if (self.can_delete(obj)): |
| 151 | self.info("destroying object %s" % str(obj)) |
| 152 | obj.delete(purge=True) # XXX TODO: turn off purge before production |
Scott Baker | 4ee562b | 2015-08-05 16:35:09 -0700 | [diff] [blame] | 153 | |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 154 | def info(self, s): |
Scott Baker | a9022e3 | 2015-08-11 17:23:52 -0700 | [diff] [blame] | 155 | self.engine.log(s) |
Scott Baker | 3fb4931 | 2015-08-03 15:43:54 -0700 | [diff] [blame] | 156 | |