blob: 43d735b01fa2b7764390bd2aa9e2dd5e85b4143c [file] [log] [blame]
Scott Baker7581c252016-05-27 13:12:47 -07001import os
2import base64
3import string
4import sys
Scott Bakerb0eb23e2016-06-01 16:08:04 -07005import urllib2
6import urlparse
Scott Baker7581c252016-05-27 13:12:47 -07007import xmlrpclib
8
Scott Baker7581c252016-05-27 13:12:47 -07009from xos.config import Config
10from core.models import Service, ServiceController, ServiceControllerResource
11from xos.logger import Logger, logging
12
13logger = Logger(level=logging.INFO)
14
15class XOSBuilder(object):
Scott Baker037f6792016-06-02 16:47:45 -070016 UI_KINDS=["models", "admin", "django_library", "rest", "tosca_custom_types", "tosca_resource","public_key"]
Scott Baker18c89172016-06-02 16:40:25 -070017 SYNC_CONTROLLER_KINDS=["synchronizer", "private_key", "public_key"]
Scott Baker513ea452016-06-02 16:03:26 -070018 SYNC_ALLCONTROLLER_KINDS=["models", "django_library"]
Scott Bakerb0eb23e2016-06-01 16:08:04 -070019
Scott Baker7581c252016-05-27 13:12:47 -070020 def __init__(self):
Scott Bakerb0eb23e2016-06-01 16:08:04 -070021 self.source_ui_image = "xosproject/xos"
22 self.source_sync_image = "xosproject/xos-synchronizer-openstack"
23 self.build_dir = "/opt/xos/BUILD/"
24
25 # stuff that has to do with downloading
26
27 def get_dest_dir(self, scr):
28 xos_base = "opt/xos"
29 service_name = scr.service_controller.name
30 base_dirs = {"models": "%s/services/%s/" % (xos_base, service_name),
31 "admin": "%s/services/%s/" % (xos_base, service_name),
32 "django_library": "%s/services/%s/" % (xos_base, service_name),
33 "synchronizer": "%s/synchronizers/%s/" % (xos_base, service_name),
34 "tosca_custom_types": "%s/tosca/custom_types/" % (xos_base),
Scott Baker18c89172016-06-02 16:40:25 -070035 "tosca_resource": "%s/tosca/resources/" % (xos_base),
36 "private_key": "%s/services/%s/keys" % (xos_base, service_name),
37 "public_key": "%s/services/%s/keys/" % (xos_base, service_name)}
Scott Bakerb0eb23e2016-06-01 16:08:04 -070038 return base_dirs[scr.kind]
39
40 def get_build_fn(self, scr):
41 dest_dir = self.get_dest_dir(scr)
42 dest_fn = os.path.split(urlparse.urlsplit(scr.full_url).path)[-1]
43 return os.path.join(dest_dir, dest_fn)
44
45 def get_download_fn(self, scr):
46 dest_fn = self.get_build_fn(scr)
47 return os.path.join(self.build_dir, dest_fn)
48
49 def read_manifest(self, scr, fn):
50 manifest = []
51 manifest_lines = file(fn).readlines()
52 manifest_lines = [x.strip() for x in manifest_lines]
Scott Bakerc2a2fe92016-06-02 13:19:10 -070053 manifest_lines = [x for x in manifest_lines if x]
Scott Bakerb0eb23e2016-06-01 16:08:04 -070054 for line in manifest_lines:
Scott Bakerc2a2fe92016-06-02 13:19:10 -070055 url_parts = urlparse.urlsplit(scr.full_url)
56 new_path = os.path.join(os.path.join(*os.path.split(url_parts.path)[:-1]),line)
57 url = urlparse.urlunsplit( (url_parts.scheme, url_parts.netloc, new_path, url_parts.query, url_parts.fragment) )
Scott Bakerb0eb23e2016-06-01 16:08:04 -070058
59 build_fn = os.path.join(self.get_dest_dir(scr), line)
Scott Bakerc2a2fe92016-06-02 13:19:10 -070060 download_fn = os.path.join(self.build_dir, build_fn)
Scott Bakerb0eb23e2016-06-01 16:08:04 -070061
62 manifest.append( (url, download_fn, build_fn) )
63 return manifest
64
65 def download_file(self, url, dest_fn):
66 logger.info("Download %s to %s" % (url, dest_fn))
67 if not os.path.exists(os.path.dirname(dest_fn)):
68 os.makedirs(os.path.dirname(dest_fn))
69 obj = urllib2.urlopen(url)
70 file(dest_fn,"w").write(obj.read())
71
Scott Bakerc2a2fe92016-06-02 13:19:10 -070072 # make python files executable
73 if dest_fn.endswith(".py"): # and contents.startswith("#!"):
74 os.chmod(dest_fn, 0755)
75
Scott Bakerb0eb23e2016-06-01 16:08:04 -070076 def download_resource(self, scr):
77 if scr.format == "manifest":
78 manifest_fn = self.get_download_fn(scr)
79 self.download_file(scr.full_url, manifest_fn)
Scott Bakerc2a2fe92016-06-02 13:19:10 -070080 manifest = self.read_manifest(scr, manifest_fn)
Scott Bakerb0eb23e2016-06-01 16:08:04 -070081 for (url, download_fn, build_fn) in manifest:
82 self.download_file(url, download_fn)
83 else:
84 self.download_file(scr.full_url, self.get_download_fn(scr))
85
86 def get_docker_lines(self, scr):
87 if scr.format == "manifest":
88 manifest_fn = self.get_download_fn(scr)
89 manifest = self.read_manifest(scr, manifest_fn)
90 lines = []
91 for (url, download_fn, build_fn) in manifest:
92 lines.append("ADD %s /%s" % (build_fn, build_fn))
93 return lines
94 else:
95 build_fn = self.get_build_fn(scr)
96 return ["ADD %s /%s" % (build_fn, build_fn)]
97
98 def get_controller_docker_lines(self, controller, kinds):
99 dockerfile=[]
100 for scr in controller.service_controller_resources.all():
101 if scr.kind in kinds:
102 lines = self.get_docker_lines(scr)
103 dockerfile = dockerfile + lines
104 return dockerfile
105
106 # stuff that has to do with building
107
Scott Baker513ea452016-06-02 16:03:26 -0700108 def create_xos_app_data(self, name, dockerfile, app_list, migration_list):
Scott Bakerae196c32016-06-01 23:29:22 -0700109 if not os.path.exists(os.path.join(self.build_dir,"opt/xos/xos")):
110 os.makedirs(os.path.join(self.build_dir,"opt/xos/xos"))
111
112 if app_list:
Scott Baker513ea452016-06-02 16:03:26 -0700113 dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_app_list /opt/xos/xos/xosbuilder_app_list" % name)
114 file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_app_list") % name, "w").write("\n".join(app_list)+"\n")
Scott Bakerae196c32016-06-01 23:29:22 -0700115
116 if migration_list:
Scott Baker513ea452016-06-02 16:03:26 -0700117 dockerfile.append("COPY opt/xos/xos/%s_xosbuilder_migration_list /opt/xos/xos/xosbuilder_migration_list" % name)
118 file(os.path.join(self.build_dir, "opt/xos/xos/%s_xosbuilder_migration_list") % name, "w").write("\n".join(migration_list)+"\n")
Scott Bakerae196c32016-06-01 23:29:22 -0700119
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700120 def create_ui_dockerfile(self):
121 dockerfile_fn = "Dockerfile.UI"
122
Scott Bakerae196c32016-06-01 23:29:22 -0700123 app_list = []
124 migration_list = []
125
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700126 dockerfile = ["FROM %s" % self.source_ui_image]
127 for controller in ServiceController.objects.all():
128 dockerfile = dockerfile + self.get_controller_docker_lines(controller, self.UI_KINDS)
Scott Bakerae196c32016-06-01 23:29:22 -0700129 if controller.service_controller_resources.filter(kind="models").exists():
130 app_list.append("services." + controller.name)
131 migration_list.append(controller.name)
132
Scott Baker513ea452016-06-02 16:03:26 -0700133 self.create_xos_app_data("ui", dockerfile, app_list, migration_list)
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700134
135 file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
136
Scott Baker8d252b62016-06-01 23:08:04 -0700137 return {"dockerfile_fn": dockerfile_fn,
138 "docker_image_name": "xosproject/xos-ui"}
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700139
140 def create_synchronizer_dockerfile(self, controller):
Scott Baker513ea452016-06-02 16:03:26 -0700141 # bake in the synchronizer from this controller
142 sync_lines = self.get_controller_docker_lines(controller, self.SYNC_CONTROLLER_KINDS)
143 if not sync_lines:
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700144 return []
145
146 dockerfile_fn = "Dockerfile.%s" % controller.name
147 dockerfile = ["FROM %s" % self.source_sync_image]
Scott Baker513ea452016-06-02 16:03:26 -0700148
149 # Now bake in models from this controller as well as the others
150 # It's important to bake all services in, because some services'
151 # synchronizers may depend on models from another service.
152 app_list = []
153 for c in ServiceController.objects.all():
154 dockerfile = dockerfile + self.get_controller_docker_lines(c, self.SYNC_ALLCONTROLLER_KINDS)
155 if controller.service_controller_resources.filter(kind="models").exists():
156 app_list.append("services." + controller.name)
157
158 self.create_xos_app_data(controller.name, dockerfile, app_list, None)
159
160 dockerfile = dockerfile + sync_lines
Scott Bakerc2a2fe92016-06-02 13:19:10 -0700161 file(os.path.join(self.build_dir, dockerfile_fn), "w").write("\n".join(dockerfile)+"\n")
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700162
Scott Baker8d252b62016-06-01 23:08:04 -0700163 return {"dockerfile_fn": dockerfile_fn,
164 "docker_image_name": "xosproject/xos-synchronizer-%s" % controller.name}
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700165
Scott Baker8d252b62016-06-01 23:08:04 -0700166# def build_xos(self):
167# dockerfiles=[]
168# dockerfiles.append(self.create_ui_dockerfile())
169#
170# for controller in ServiceController.objects.all():
171# dockerfiles.append(self.create_synchronizer_dockerfile(controller))
Scott Bakerb0eb23e2016-06-01 16:08:04 -0700172
173
174