def inner(namespace, *args, **kwargs): """ :param namespace: :class:`argparse.Namespace` instance. This is the only required/expected parameter for a command function. """ LOG.setLevel(zpmlib.LOG_LEVEL_MAP.get(namespace.log_level)) return func(namespace, *args, **kwargs)
def bundle_project(root): """ Bundle the project under root. """ zapp_yaml = os.path.join(root, 'zapp.yaml') zapp = yaml.safe_load(open(zapp_yaml)) zapp_name = zapp['meta']['name'] + '.zapp' tar = tarfile.open(zapp_name, 'w:gz') job = _generate_job_desc(zapp) job_json = json.dumps(job) info = tarfile.TarInfo(name='%s.json' % zapp['meta']['name']) # This size is only correct because json.dumps uses # ensure_ascii=True by default and we thus have a 1-1 # correspondence between Unicode characters and bytes. info.size = len(job_json) LOG.info('adding %s' % info.name) # In Python 3, we cannot use a str or bytes object with addfile, # we need a BytesIO object. In Python 2, BytesIO is just StringIO. # Since json.dumps produces an ASCII-only Unicode string in Python # 3, it is safe to encode it to ASCII. tar.addfile(info, BytesIO(job_json.encode('ascii'))) _add_file_to_tar(root, 'zapp.yaml', tar) sections = ('bundling', 'ui') # Keep track of the files we add, given the configuration in the zapp.yaml. file_add_count = 0 for section in sections: for pattern in zapp.get(section, []): paths = glob.glob(os.path.join(root, pattern)) if len(paths) == 0: LOG.warning( "pattern '%(pat)s' in section '%(sec)s' matched no files", dict(pat=pattern, sec=section) ) else: for path in paths: _add_file_to_tar(root, path, tar) file_add_count += len(paths) if file_add_count == 0: # None of the files specified in the "bundling" or "ui" sections were # found. Something is wrong. raise zpmlib.ZPMException( "None of the files specified in the 'bundling' or 'ui' sections of" " the zapp.yaml matched anything." ) if not zapp.get('ui'): _add_ui(tar, zapp) tar.close() print('created %s' % zapp_name)
def _add_file_to_tar(root, path, tar): """ :param root: Root working directory. :param path: File path. :param tar: Open :class:`tarfile.TarFile` object to add the ``files`` to. """ LOG.info('adding %s' % path) relpath = os.path.relpath(path, root) info = tarfile.TarInfo(name=relpath) info.size = os.path.getsize(path) tar.addfile(info, open(path, 'rb'))
def _add_ui(tar, zapp): loader = jinja2.PackageLoader('zpmlib', 'templates') env = jinja2.Environment(loader=loader) for path in _DEFAULT_UI_TEMPLATES: tmpl = env.get_template(path) output = tmpl.render(zapp=zapp) # NOTE(larsbutler): Python 2.7.2 has a bug related to unicode and # cStringIO. To work around this, we need the following explicit # encoding. See http://bugs.python.org/issue1548891. output = output.encode('utf-8') info = tarfile.TarInfo(name=path) info.size = len(output) LOG.info('adding %s' % path) tar.addfile(info, BytesIO(output))
def deploy(args): """Deploy a ZeroVM application This deploys a zapp onto Swift. The zapp can be one you have downloaded or produced yourself with "zpm bundle". You will need to know the Swift authentication URL, username, password, and tenant name. These can be supplied with command line flags (see below) or you can set the corresponding environment variables. The environment variables are the same as the ones used by the Swift command line tool, so if you're already using that to upload files to Swift, you will be ready to go. """ LOG.info('deploying %s' % args.zapp) zpm.deploy_project(args)
def deploy_project(args): version = args.auth_version conn = _get_zerocloud_conn(args) conn.authenticate() # We can now reset the auth for the web UI, if needed if args.no_ui_auth: version = '0.0' auth = _prepare_auth(version, args, conn) auth_opts = jinja2.Markup(json.dumps(auth)) _deploy_zapp(conn, args.target, args.zapp, auth_opts) if args.execute: # for compatibility with the option name in 'zpm execute' args.container = args.target execute(args) LOG.info('app deployed to\n %s/%s/' % (conn.url, args.target))
def _post_job(url, token, json_data, http_conn=None, response_dict=None): # Modelled after swiftclient.client.post_account. headers = {'X-Auth-Token': token, 'Accept': 'application/json', 'X-Zerovm-Execute': '1.0', 'Content-Type': 'application/json'} if http_conn: parsed, conn = http_conn else: parsed, conn = swiftclient.http_connection(url) conn.request('POST', parsed.path, json_data, headers) resp = conn.getresponse() body = resp.read() swiftclient.http_log((url, 'POST'), {'headers': headers}, resp, body) swiftclient.store_response(resp, response_dict) LOG.debug('response status: %s' % resp.status) print(body)
def deploy_project(args): version = args.auth_version conn = _get_zerocloud_conn(args) # We can now reset the auth for the web UI, if needed if args.no_ui_auth: version = '0.0' tar = tarfile.open(args.zapp) zapp = yaml.safe_load(tar.extractfile('zapp.yaml')) path = '%s/%s' % (args.target, os.path.basename(args.zapp)) container, obj = path.split('/', 1) conn.put_object(container, obj, gzip.open(args.zapp).read()) swift_url = _get_swift_zapp_url(conn.url, path) job = _prepare_job(tar, zapp, swift_url) path = '%s/%s.json' % (args.target, zapp['meta']['name']) container, obj = path.split('/', 1) conn.put_object(container, obj, json.dumps(job)) deploy = {'version': version} if version == '0.0': deploy['swiftUrl'] = conn.url elif version == '1.0': deploy['authUrl'] = args.auth deploy['username'] = args.user deploy['password'] = args.key else: # TODO(mg): inserting the username and password in the # uploaded file makes testing easy, but should not be done in # production. See issue #44. deploy['authUrl'] = args.os_auth_url deploy['tenant'] = args.os_tenant_name deploy['username'] = args.os_username deploy['password'] = args.os_password auth_opts = jinja2.Markup(json.dumps(deploy)) for path in _find_ui_uploads(zapp, tar): # Upload UI files after expanding deployment parameters tmpl = jinja2.Template(tar.extractfile(path).read()) output = tmpl.render(auth_opts=auth_opts) container, obj = ('%s/%s' % (args.target, path)).split('/', 1) conn.put_object(container, obj, output) if args.execute: job_details = BytesIO() pprint.pprint(job, stream=job_details) job_details.seek(0) LOG.debug('job template:\n%s' % job_details.read()) LOG.info('executing') conn.post_job(job) LOG.info('app deployed to\n %s/%s/' % (conn.url, args.target))