def parse_env_param(module, param_name, key=None): if key is None: key = launchdarkly_api.Environment.attribute_map[param_name] path = "/" + key return launchdarkly_api.PatchOperation(path=path, op="replace", value=module[param_name])
def _parse_webhook_param(module, param_name, key=None): if key is None: key = launchdarkly_api.Webhook.attribute_map[param_name] path = "/" + key patch = dict(path=path, op="replace", value=module.params[param_name]) print(patch) return launchdarkly_api.PatchOperation(**patch)
def _patch_variations(module, variations, patches): # subtract 1 for zero indexing oldVariations = len(variations) - 1 newVariations = len(module.params["variations"]) newIndex = newVariations - 1 i = 0 if newIndex < oldVariations: # iterating over variations for range to be inclusive for i in range(newVariations, len(variations)): patches.append( launchdarkly_api.PatchOperation(op="remove", path="/variations/%d" % i, value="needed_for_call")) else: for i in range(newVariations): if i <= oldVariations: patches.append( launchdarkly_api.PatchOperation( op="replace", path="/variations/%d/name" % i, value=module.params["variations"][i]["name"], )) patches.append( launchdarkly_api.PatchOperation( op="replace", path="/variations/%d/description" % i, value=module.params["variations"][i]["description"], )) patches.append( launchdarkly_api.PatchOperation( op="replace", path="/variations/%d/value" % i, value=module.params["variations"][i]["value"], )) else: variation = launchdarkly_api.Variation( name=module.params["variations"][i]["name"], description=module.params["variations"][i]["description"], value=module.params["variations"][i]["value"], ) patches.append( launchdarkly_api.PatchOperation(op="add", path="/variations/%d" % i, value=variation)) return patches return patches
def _parse_custom_role_param(module, param_name, key=None): if key is None: key = launchdarkly_api.CustomRole.attribute_map[param_name] path = "/" + key if param_name == "policy": policies = _parse_policies(module.params["policy"]) patch = dict(path=path, op="replace", value=policies) else: patch = dict(path=path, op="replace", value=module.params[param_name]) return launchdarkly_api.PatchOperation(**patch)
def _configure_webhook(module, api_instance, webhook=None): patches = [] if webhook: if webhook.name == module.params["name"] or module.params["name"] is None: del module.params["name"] if webhook.url == module.params["url"] or module.params["url"] is None: del module.params["url"] if set(webhook.tags) == set(module.params["tags"]): del module.params["tags"] # Loop over statements comparing if module.params["statements"] is not None: if len(module.params["statements"]) < len(webhook.statements): oldStatements = len(webhook.statements) - 1 newStatements = len(module.params["statements"]) newIndex = newStatements - 1 i = 0 if newIndex < oldStatements: # iterating over statements for range to be inclusive for i in range(newStatements, len(webhook.statements)): patches.append( launchdarkly_api.PatchOperation( op="remove", path="/statements/%d" % i, value="needed_for_call", ) ) for idx, statement in enumerate(module.params["statements"]): if idx > len(webhook.statements) - 1: tmp_results = ["break"] break tmp_results = diff(statement, webhook.statements[idx]) statement_results = list(tmp_results) if len(statement_results) == 0: del module.params["statements"] for key in module.params: if key not in ["state", "api_key", "sign", "webhook_id"]: if module.params[key] is not None: patches.append(_parse_webhook_param(module, key)) if len(patches) > 0: try: api_response = api_instance.patch_webhook( module.params["webhook_id"], patch_delta=patches ) except ApiException as e: if e.status == 404: module.exit_json(failed=True, msg="webhook id not found") else: fail_exit(module, e) module.exit_json( msg="webhook successfully configured", webhook=api_response.to_dict() )
def _parse_project_param(module, param_name, key=None): if key is None: key = launchdarkly_api.Project.attribute_map[param_name] path = "/" + key if param_name == "environments": value = env_ld_builder(module.params["environments"]) else: value = module.params[param_name] return launchdarkly_api.PatchOperation(path=path, op="replace", value=value)
def _toggle_flag(module, patches, feature_flag): if module.params["state"] == "enabled": value = True elif module.params["state"] == "disabled": value = False else: value = feature_flag.on if feature_flag.on != value: path = _patch_path(module, "on") patches.append( launchdarkly_api.PatchOperation(path=path, op="replace", value=value) ) return patches
def _toggle_flag(state, patches, feature_flag, env): if state == "enabled": value = True elif state == "disabled": value = False else: value = feature_flag.on if feature_flag.on != value: path = _patch_path(env, "on") patches.append( launchdarkly_api.PatchOperation(path=path, op="replace", value=value) ) return patches
def _parse_flag_param(module, key, op="replace"): path = _patch_path(module, launchdarkly_api.FeatureFlagConfig.attribute_map[key]) return launchdarkly_api.PatchOperation(path=path, op=op, value=module.params[key])
def _parse_flag_param(module, param_name, key, op="replace"): path = "/" + launchdarkly_api.FeatureFlagBody.attribute_map[key] return launchdarkly_api.PatchOperation(path=path, op=op, value=module.params[param_name])
def parse_user_param(module, param_name, key=None): if key is None: key = launchdarkly_api.UserSegment.attribute_map[param_name] path = "/" + key patch = dict(path=path, op="replace", value=module[param_name]) return launchdarkly_api.PatchOperation(**patch)
def _patch_op(op, path, value): return launchdarkly_api.PatchOperation(op=op, path=path, value=value)
def _configure_user_sync(module, api_instance): user_segment = api_instance.get_user_segment( module.params["project_key"], module.params["environment_key"], module.params["user_segment_key"], ) new_segment = launchdarkly_api.UserSegmentBody( name=user_segment.name, key=user_segment.key, description=user_segment.description, tags=user_segment.tags, ) for idx, env in enumerate(module.params["environment_targets"]): patches = [] try: response, status, headers = api_instance.post_user_segment_with_http_info( module.params["project_key"], env, new_segment) except ApiException as e: if e.status == 409: ( response, status, headers, ) = api_instance.get_user_segment_with_http_info( module.params["project_key"], env, module.params["user_segment_key"]) if user_segment.name is not None and user_segment.name != response.name: patches.append( _patch_op("replace", "/name", user_segment.name)) if (user_segment.description is not None and user_segment.description != response.description): patches.append( _patch_op("replace", "/description", user_segment.description)) if user_segment.tags is not None and set( user_segment.tags) != set(response.tags): patches.append( _patch_op("replace", "/tags", user_segment.tags)) else: fail_exit(module, e) if (module.params["included_actions"] is None or ("updateTargets" in module.params["included_actions"] or "updateTargets" not in module.params["excluded_actions"]) and (set(response.included) != set(user_segment.included) or set(response.excluded) != set(user_segment.excluded))): patches.append( _patch_op("replace", "/included", user_segment.included)) patches.append( _patch_op("replace", "/excluded", user_segment.excluded)) if module.params["included_actions"] is None or ( "updateRules" in module.params["included_actions"] or "updateRules" not in module.params["excluded_actions"]): for rule in user_segment.rules: patches.append( launchdarkly_api.PatchOperation(op="add", path="/rules", value=user_segment.rules)) try: response, status, headers = api_instance.patch_user_segment_with_http_info( module.params["project_key"], env, user_segment.key, patches) except ApiException as e: if e.status == 404: module.exit_json( failed=True, msg="user segment key: %s not found" % module.params["user_segment_key"], ) else: fail_exit(module, e) module.exit_json(changed=True, msg="feature flags synced", user_segment=response.to_dict())
def _project_sync( module, src_proj, dest_proj, dest_env_api, src_user_sgmt, dest_user_sgmt, src_fflags, dest_fflags, ): src_project = src_proj.get_project(module.params["project_key"]).to_dict() name = module.params.get("name", src_project["name"]) dest_proj_body = dict(name=name, key=module.params["project_key_dest"], tags=src_project["tags"]) patch_envs = [] # Build the Environments inside of Project Body if module.params["environments_copy"]: dest_proj_body["environments"] = [] for env in src_project["environments"]: dest_proj_body["environments"].append( dict( name=env["name"], key=env["key"], color=env["color"], default_ttl=env["default_ttl"], )) patch_env = dict(key=env["key"]) if env["tags"]: patch_env["tags"] = env["tags"] if env["secure_mode"] is not False: patch_env["secure_mode"] = env["secure_mode"] if env["default_track_events"] is not False: patch_env["default_track_events"] = env["default_track_events"] if env["require_comments"] is not False: patch_env["require_comments"] = env["require_comments"] if env["confirm_changes"] is not False: patch_env["confirm_changes"] = env["confirm_changes"] patch_envs.append(patch_env) ld_proj = launchdarkly_api.ProjectBody(**dest_proj_body) try: response, status, headers = dest_proj.post_project_with_http_info( project_body=ld_proj) except ApiException as e: fail_exit(module, e) # Project Environment Processing patches = [] for env in patch_envs: for key in env: if key not in ["key"] and env[key] is not None: patches.append(parse_env_param(env, key)) if len(patches) > 0: try: api_response = dest_env_api.patch_environment( module.params["project_key_dest"], env["key"], patch_delta=patches) except ApiException as e: if status == 429: time.sleep(reset_rate(headers["X-RateLimit-Reset"])) # Retry dest_env_api.patch_environment( module.params["project_key_dest"], env["key"], patch_delta=patches, ) else: fail_exit(module, e) # Reset patches patches = [] # User Segment Processing if module.params["environments_copy"]: for env in src_project["environments"]: get_segments = src_user_sgmt.get_user_segments( module.params["project_key"], env["key"]).to_dict() patch_sgmts = [] for segment in get_segments["items"]: new_segment_body = dict(key=segment["key"], name=segment["name"]) if segment["description"]: new_segment_body["description"] = segment["description"] if segment["tags"]: new_segment_body["tags"] = segment["tags"] try: dest_user_sgmt.post_user_segment( module.params["project_key_dest"], env["key"], new_segment_body) except ApiException as e: if status == 429: time.sleep(reset_rate(headers["X-RateLimit-Reset"])) # Retry dest_user_sgmt.post_user_segment( module.params["project_key_dest"], env["key"], new_segment_body, ) else: fail_exit(module, e) patch_sgmt = dict(key=segment["key"]) if segment["included"] is not None: patch_sgmt["included"] = segment["included"] if segment["excluded"] is not None: patch_sgmt["excluded"] = segment["excluded"] if segment["rules"] is not None: patch_sgmt["rules"] = segment["rules"] patch_sgmts.append(patch_sgmt) for sgmt in patch_sgmts: patches = [] for key in sgmt: if key not in ["key"] and len(sgmt[key]) > 0: if key == "rules": for rule in sgmt["rules"]: patch = dict( path="/rules/-", op="add", value=launchdarkly_api.UserSegmentRule( **rule), ) patches.append( launchdarkly_api.PatchOperation(**patch)) del patch else: patches.append(parse_user_param(sgmt, key)) if len(patches) > 0: try: ( response, status, headers, ) = dest_user_sgmt.patch_user_segment_with_http_info( module.params["project_key_dest"], env["key"], sgmt["key"], patch_only=patches, ) except ApiException as e: if status == 429: time.sleep(reset_rate( headers["X-RateLimit-Reset"])) # Retry dest_user_sgmt.patch_user_segment_with_http_info( module.params["project_key_dest"], env["key"], sgmt["key"], patch_only=patches, ) else: fail_exit(module, e) # Reset patches del patches tag = module.params.get("flag_tag", None) src_ff = {} try: if tag: tag = ",".join(tag) src_ff = src_fflags.get_feature_flags(module.params["project_key"], summary=0, tag=tag).to_dict() else: src_ff = src_fflags.get_feature_flags(module.params["project_key"], summary=0).to_dict() except ApiException as e: if status == 429: time.sleep(reset_rate(headers["X-RateLimit-Reset"])) if tag: tag = ",".join(tag) src_ff = src_fflags.get_feature_flags( module.params["project_key"], summary=0, tag=tag).to_dict() else: src_ff = src_fflags.get_feature_flags( module.params["project_key"], summary=0).to_dict() for flag in src_ff["items"]: fflag_body = dict( name=flag["name"], key=flag["key"], description=flag["description"], variations=flag["variations"], temporary=flag["temporary"], tags=flag["tags"], include_in_snippet=flag["include_in_snippet"], ) fflag_body_mapped = dict( (launchdarkly_api.FeatureFlagBody.attribute_map[k], v) for k, v in fflag_body.items() if v is not None) try: response, status, headers = dest_fflags.post_feature_flag_with_http_info( module.params["project_key_dest"], fflag_body_mapped) except ApiException as e: if e.status == 429: time.sleep(reset_rate(headers["X-RateLimit-Reset"])) # Retry ( response, status, headers, ) = dest_fflags.post_feature_flag_with_http_info( module.params["project_key_dest"], fflag_body) else: fail_exit(module, e) if module.params["environments_copy"]: patches = [] for fenv_key in flag["environments"]: fflag_env = dict( on=flag["environments"][fenv_key]["on"], targets=flag["environments"][fenv_key]["targets"], off_variation=flag["environments"][fenv_key] ["off_variation"], track_events=flag["environments"][fenv_key] ["track_events"], prerequisites=flag["environments"][fenv_key] ["prerequisites"], fallthrough=flag["environments"][fenv_key]["fallthrough"], ) fflag_env_mapped = dict( (launchdarkly_api.FeatureFlagConfig.attribute_map[k], v) for k, v in fflag_env.items() if v is not None) path = "/environments/" + fenv_key + "/" for key in fflag_env_mapped: if fflag_env_mapped.get(key) is not None: patch = dict(path=path + key, op="replace", value=fflag_env_mapped[key]) patches.append( launchdarkly_api.PatchOperation(**patch)) del patch try: for rule in flag["environments"][fenv_key]["rules"]: new_rule = dict(clauses=rule["clauses"]) if rule["rollout"] is not None: new_rule["rollout"] = rule["rollout"] if rule["variation"] is not None: new_rule["variation"] = rule["variation"] patch = dict( path=path + "rules/-", op="add", value=launchdarkly_api.Rule(**new_rule), ) patches.append( launchdarkly_api.PatchOperation(**patch)) except KeyError: pass if len(patches) > 0: try: ( response, status, headers, ) = dest_fflags.patch_feature_flag_with_http_info( module.params["project_key_dest"], flag["key"], patch_comment=patches, ) except ApiException as e: if e.status == 429: time.sleep(reset_rate(headers["X-RateLimit-Reset"])) # Retry dest_fflags.patch_feature_flag_with_http_info( module.params["project_key_dest"], flag["key"], patch_comment=patches, ) else: fail_exit(module, e) # Reset patches del patches new_project = dest_proj.get_project( module.params["project_key_dest"]).to_dict() module.exit_json( changed=True, project=new_project, msg="Copied project: %s to project: %s" % (module.params["project_key"], module.params["project_key_dest"]), )