def test_resolve_provider(self): for p in list_providers(self.config["upload"]): print(p) info = resolve_provider(self.config["upload"], p) self.assertTrue("display" in info) self.assertTrue("supported_types" in info) self.assertTrue("settings-info" in info)
def v1_compose_start(): """Start a compose The body of the post should have these fields: blueprint_name - The blueprint name from /blueprints/list/ compose_type - The type of output to create, from /compose/types branch - Optional, defaults to master, selects the git branch to use for the blueprint. **POST /api/v1/compose** Start a compose. The content type should be 'application/json' and the body of the POST should look like this. The "upload" object is optional. The upload object can specify either a pre-existing profile to use (as returned by `/uploads/providers`) or one-time use settings for the provider. Example with upload profile:: { "blueprint_name": "http-server", "compose_type": "tar", "branch": "master", "upload": { "image_name": "My Image", "provider": "azure", "profile": "production-azure-settings" } } Example with upload settings:: { "blueprint_name": "http-server", "compose_type": "tar", "branch": "master", "upload": { "image_name": "My Image", "provider": "azure", "settings": { "resource_group": "SOMEBODY", "storage_account_name": "ONCE", "storage_container": "TOLD", "location": "ME", "subscription_id": "THE", "client_id": "WORLD", "secret": "IS", "tenant": "GONNA" } } } Pass it the name of the blueprint, the type of output (from '/api/v1/compose/types'), and the blueprint branch to use. 'branch' is optional and will default to master. It will create a new build and add it to the queue. It returns the build uuid and a status if it succeeds. If an "upload" is given, it will schedule an upload to run when the build finishes. Example response:: { "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf", "upload_id": "572eb0d0-5348-4600-9666-14526ba628bb", "status": true } """ # Passing ?test=1 will generate a fake FAILED compose. # Passing ?test=2 will generate a fake FINISHED compose. try: test_mode = int(request.args.get("test", "0")) except ValueError: test_mode = 0 compose = request.get_json(cache=False) errors = [] if not compose: return jsonify(status=False, errors=[{ "id": MISSING_POST, "msg": "Missing POST body" }]), 400 if "blueprint_name" not in compose: errors.append({ "id": UNKNOWN_BLUEPRINT, "msg": "No 'blueprint_name' in the JSON request" }) else: blueprint_name = compose["blueprint_name"] if "branch" not in compose or not compose["branch"]: branch = "master" else: branch = compose["branch"] if "compose_type" not in compose: errors.append({ "id": BAD_COMPOSE_TYPE, "msg": "No 'compose_type' in the JSON request" }) else: compose_type = compose["compose_type"] if VALID_BLUEPRINT_NAME.match(blueprint_name) is None: errors.append({ "id": INVALID_CHARS, "msg": "Invalid characters in API path" }) if not blueprint_exists(api, branch, blueprint_name): errors.append({ "id": UNKNOWN_BLUEPRINT, "msg": "Unknown blueprint name: %s" % blueprint_name }) if "upload" in compose: try: image_name = compose["upload"]["image_name"] if "profile" in compose["upload"]: # Load a specific profile for this provider profile = compose["upload"]["profile"] provider_name = compose["upload"]["provider"] settings = load_settings(api.config["COMPOSER_CFG"]["upload"], provider_name, profile) else: provider_name = compose["upload"]["provider"] settings = compose["upload"]["settings"] except KeyError as e: errors.append({ "id": UPLOAD_ERROR, "msg": f'Missing parameter {str(e)}!' }) try: provider = resolve_provider(api.config["COMPOSER_CFG"]["upload"], provider_name) if "supported_types" in provider and compose_type not in provider[ "supported_types"]: raise RuntimeError( f'Type "{compose_type}" is not supported by provider "{provider_name}"!' ) validate_settings(api.config["COMPOSER_CFG"]["upload"], provider_name, settings, image_name) except Exception as e: errors.append({"id": UPLOAD_ERROR, "msg": str(e)}) if errors: return jsonify(status=False, errors=errors), 400 try: build_id = start_build(api.config["COMPOSER_CFG"], api.config["DNFLOCK"], api.config["GITLOCK"], branch, blueprint_name, compose_type, test_mode) except Exception as e: if "Invalid compose type" in str(e): return jsonify(status=False, errors=[{ "id": BAD_COMPOSE_TYPE, "msg": str(e) }]), 400 else: return jsonify(status=False, errors=[{ "id": BUILD_FAILED, "msg": str(e) }]), 400 if "upload" in compose: upload_id = uuid_schedule_upload(api.config["COMPOSER_CFG"], build_id, provider_name, image_name, settings) else: upload_id = "" return jsonify(status=True, build_id=build_id, upload_id=upload_id)
def v1_compose_uploads_schedule(compose_uuid): """Schedule an upload of a compose to a given cloud provider **POST /api/v1/uploads/schedule/<compose_uuid>** The body can specify either a pre-existing profile to use (as returned by `/uploads/providers`) or one-time use settings for the provider. Example with upload profile:: { "image_name": "My Image", "provider": "azure", "profile": "production-azure-settings" } Example with upload settings:: { "image_name": "My Image", "provider": "azure", "settings": { "resource_group": "SOMEBODY", "storage_account_name": "ONCE", "storage_container": "TOLD", "location": "ME", "subscription_id": "THE", "client_id": "WORLD", "secret": "IS", "tenant": "GONNA" } } Example response:: { "status": true, "upload_id": "572eb0d0-5348-4600-9666-14526ba628bb" } """ if VALID_API_STRING.match(compose_uuid) is None: error = {"id": INVALID_CHARS, "msg": "Invalid characters in API path"} return jsonify(status=False, errors=[error]), 400 parsed = request.get_json(cache=False) if not parsed: return jsonify(status=False, errors=[{ "id": MISSING_POST, "msg": "Missing POST body" }]), 400 try: image_name = parsed["image_name"] provider_name = parsed["provider"] if "profile" in parsed: # Load a specific profile for this provider profile = parsed["profile"] settings = load_settings(api.config["COMPOSER_CFG"]["upload"], provider_name, profile) else: settings = parsed["settings"] except KeyError as e: error = {"id": UPLOAD_ERROR, "msg": f'Missing parameter {str(e)}!'} return jsonify(status=False, errors=[error]), 400 try: compose_type = uuid_status(api.config["COMPOSER_CFG"], compose_uuid)["compose_type"] provider = resolve_provider(api.config["COMPOSER_CFG"]["upload"], provider_name) if "supported_types" in provider and compose_type not in provider[ "supported_types"]: raise RuntimeError( f'Type "{compose_type}" is not supported by provider "{provider_name}"!' ) except Exception as e: return jsonify(status=False, errors=[{ "id": UPLOAD_ERROR, "msg": str(e) }]), 400 try: upload_id = uuid_schedule_upload(api.config["COMPOSER_CFG"], compose_uuid, provider_name, image_name, settings) except RuntimeError as e: return jsonify(status=False, errors=[{ "id": UPLOAD_ERROR, "msg": str(e) }]), 400 return jsonify(status=True, upload_id=upload_id)
def get_provider_info(provider_name): provider = resolve_provider(ucfg, provider_name) provider["profiles"] = load_profiles(ucfg, provider_name) return provider