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)
Exemple #5
0
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()
    )
Exemple #6
0
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)
Exemple #7
0
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
Exemple #8
0
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
Exemple #9
0
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"]),
    )