Esempio n. 1
0
def _create_project(module, api_instance):
    if module.params["conftest"]["enabled"]:
        rego_test(module)

    project_config = {
        "name": module.params["name"],
        "key": module.params["project_key"],
    }

    if module.params["environments"]:
        environments = []
        for env in module.params["environments"]:
            environments.append(env)
        project_config["environments"] = environments

    if module.params["tags"] and module.params["tags"] is not None:
        project_config["tags"] = module.params["tags"]

    # if module.params['include_in_snippet_by_default'] and module.params['include_in_snippet_by_default'] is not None:
    #     project_config['include_in_snippet_by_default'] = module.params['include_in_snippet_by_default']

    project_body = launchdarkly_api.ProjectBody(**project_config)

    try:
        response, status, headers = api_instance.post_project_with_http_info(
            project_body=project_body)
        module.exit_json(changed=True, content=response.to_dict())

    except ApiException as e:
        fail_exit(module, e)
def _fetch_flags(module, api_instance):
    try:
        if module.params.get("key"):
            if module.params.get("env"):
                response = api_instance.get_feature_flag(
                    module.params["project_key"],
                    module.params["key"],
                    env=module.params["env"],
                )
            else:
                response = api_instance.get_feature_flag(
                    module.params["project_key"], module.params["key"]
                )

        else:
            keys = ["project_key", "env", "summary", "archived", "tag"]
            filtered_keys = dict(
                (k, module.params[k])
                for k in keys
                if k in module.params and module.params[k] is not None
            )
            response = api_instance.get_feature_flags(**filtered_keys)

        return response.to_dict()
    except launchdarkly_api.rest.ApiException as e:
        if e.status == 404:
            return None
        else:
            fail_exit(module, e)
def _create_user_segment(module, api_instance):
    if module.params["conftest"]["enabled"]:
        rego_test(module)

    name = (module.params["name"] if module.params["name"] is not None else
            module.params["user_segment_key"])
    user_segment_config = {
        "name": name,
        "key": module.params["user_segment_key"]
    }

    user_segment_config["description"] = (module.params["description"]
                                          if module.params.get("description")
                                          else "")
    user_segment_config["tags"] = (module.params["tags"]
                                   if module.params.get("tags") else [])

    user_segment_body = launchdarkly_api.UserSegmentBody(**user_segment_config)

    try:
        api_response = api_instance.post_user_segment(
            module.params["project_key"],
            module.params["environment_key"],
            user_segment_body,
        )
    except ApiException as e:
        fail_exit(module, e)

    _configure_user_segment(module, api_instance, api_response, True)
def _delete_user_segment(module, api_instance):
    try:
        api_instance.delete_user_segment(
            module.params["project_key"],
            module.params["environment_key"],
            module.params["user_segment_key"],
        )
        module.exit_json(changed=True, msg="successfully deleted user segment")
    except ApiException as e:
        fail_exit(module, e)
def _delete_flag(module, api_instance):
    feature_flag_config = {
        "project_key": module.params["project_key"],
        "feature_flag_key": module.params["key"],
    }
    try:
        api_response = api_instance.delete_feature_flag(**feature_flag_config)
        module.exit_json(changed=True, msg="feature flag deleted")
    except ApiException as e:
        fail_exit(module, e)
Esempio n. 6
0
def _fetch_projects(module, api_instance):
    try:
        if module.params.get("project_key"):
            response = api_instance.get_project(
                module.params["project_key"]).to_dict()

        else:
            get_projects = api_instance.get_projects()
            projects = [proj.to_dict() for proj in get_projects.items]
            final_projects = []
            if module.params.get("tags"):

                filter_projects = [
                    d for d in projects
                    if len(set(d["tags"]).intersection(module.params["tags"]))
                ]

            if module.params.get("environment_tags"):
                try:
                    filter_projects
                except NameError:
                    filter_projects = None

                if filter_projects:
                    env_projects = filter_projects
                else:
                    env_projects = projects
                for i, proj in enumerate(env_projects):
                    filtered_environments = []
                    for env in proj["environments"]:
                        if module.params.get("environment_tags") and set(
                                env["tags"]).intersection(
                                    module.params["environment_tags"]):
                            filtered_environments.append(env)
                        elif module.params.get("environment_tags"):
                            continue
                        else:
                            filtered_environments = env
                    env_projects[i]["environments"] = filtered_environments
                final_projects = env_projects
            else:
                final_projects = filter_projects

            get_projects = [
                d for d in final_projects if len(d["environments"]) > 0
            ]

            response = get_projects

        return response
    except launchdarkly_api.rest.ApiException as e:
        if e.status == 404:
            return None
        else:
            fail_exit(module, e)
Esempio n. 7
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()
    )
def _fetch_flag(module, api_instance):
    try:
        response = api_instance.get_feature_flag(module.params["project_key"],
                                                 module.params["key"])
        return response
    except ApiException as e:
        if e.status == 404:
            return None
        else:
            fail_exit(module, e)
    return None
Esempio n. 9
0
def _delete_environment(module, api_instance):
    try:
        response, status, headers = api_instance.delete_environment_with_http_info(
            module.params["project_key"], module.params["environment_key"])
        if status != 204:
            module.exit_json(failed=True,
                             msg="Failed to delete enviroment status: %d" %
                             status)
        module.exit_json(msg="successfully deleted environment")
    except ApiException as e:
        fail_exit(module, e)
Esempio n. 10
0
def _fetch_project(module, api_instance):
    try:
        # Get an environment given a project and key.
        project = api_instance.get_project(module.params["project_key"])
        return project
    except ApiException as e:
        if e.status == 404:
            return False
        else:
            fail_exit(module, e)
    return False
def _fetch_webhook(module, api_instance):
    if module.params["webhook_id"] is not None:
        try:
            # Get a webhook given an id.
            webhook = api_instance.get_webhook(module.params["webhook_id"])
            return webhook
        except ApiException as e:
            if e.status == 404:
                return False
            else:
                fail_exit(module, e)
    else:
        return False
Esempio n. 12
0
def _configure_environment(module, api_instance, environment=None):
    changed = False
    patches = []
    if environment:
        if environment.name == module.params["name"]:
            del module.params["name"]
        if environment.color == module.params["color"]:
            del module.params["color"]
        if (environment.default_ttl == module.params["default_ttl"]
                or module.params["default_ttl"] is None):
            del module.params["default_ttl"]
        if environment.secure_mode == module.params["secure_mode"]:
            del module.params["secure_mode"]
        if environment.default_track_events == module.params[
                "default_track_events"]:
            del module.params["default_track_events"]
        if set(environment.tags) == set(module.params["tags"]):
            del module.params["tags"]
        if environment.confirm_changes == module.params["confirm_changes"]:
            del module.params["confirm_changes"]
        if environment.require_comments == module.params["require_comments"]:
            del module.params["require_comments"]
        if len(module.params.keys()) <= 4:
            module.exit_json(changed=False, msg="environment unchanged")
    for key in module.params:
        if (key not in [
                "state", "api_key", "environment_key", "project_key",
                "conftest"
        ] and module.params[key] is not None):
            patches.append(parse_env_param(module.params, key))

    if len(patches) > 0:
        try:
            api_response = api_instance.patch_environment(
                module.params["project_key"],
                module.params["environment_key"],
                patch_delta=patches,
            )
        except ApiException as e:
            fail_exit(module, e)

        module.exit_json(
            changed=True,
            msg="environment successfully configured",
            environment=api_response.to_dict(),
        )

    module.exit_json(changed=False,
                     msg="environment unchanged",
                     environment=environment.to_dict())
def _fetch_user_segment(module, api_instance):
    try:
        # Get a user segment given a project, environment, and user_segment_key.
        user_segment = api_instance.get_user_segment(
            module.params["project_key"],
            module.params["environment_key"],
            module.params["user_segment_key"],
        )
        return user_segment
    except ApiException as e:
        if e.status == 404:
            return False
        else:
            fail_exit(module, e)
    return False
Esempio n. 14
0
def _fetch_feature_flag(module, api_instance):
    try:
        # Get an environment given a project and key.
        feature_flag = api_instance.get_feature_flag(
            module.params["project_key"],
            module.params["flag_key"],
            env=module.params["environment_key"],
        )
        return feature_flag.environments[module.params["environment_key"]]
    except ApiException as e:
        if e.status == 404:
            raise AnsibleError(
                "Flag: %s does not exist in Project: %s"
                % (module.params["flag_key"], module.params["project_key"])
            )
        fail_exit(module, e)
def _create_flag(module, api_instance):
    # Variations can only be set at time of flag creation.
    if module.params["conftest"]["enabled"]:
        validate_params(module)

    if module.params["kind"] == "bool":
        variations = [
            launchdarkly_api.Variation(value=True),
            launchdarkly_api.Variation(value=False),
        ]
    elif module.params["kind"] == "json":
        # No easy way to check isinstance json
        variations = _build_variations(module)
    elif module.params["kind"] == "str":
        if not all(
                isinstance(item, string_types)
                for item in module.params["variations"]):
            module.exit_json(msg="Variations need to all be strings")
        variations = _build_variations(module)
    elif module.params["kind"] == "number":
        if not all(
                isinstance(item, int) for item in module.params["variations"]):
            module.exit_json(msg="Variations need to all be integers")
        variations = _build_variations(module)

    feature_flag_config = {
        "key": module.params["key"],
        "variations": variations,
        "temporary": module.params["temporary"],
        "name": module.params["name"],
    }

    try:
        response, status, headers = api_instance.post_feature_flag_with_http_info(
            module.params["project_key"], feature_flag_config)

    except ApiException as e:
        err = json.loads(str(e.body))
        if err["code"] == "key_exists":
            module.exit_json(msg="error: Key already exists")
        else:
            fail_exit(module, e)

    _configure_flag(module, api_instance, response)
    module.exit_json(msg="flag successfully created",
                     content=api_response.to_dict())
Esempio n. 16
0
def _configure_flag_sync(module, api_instance):
    results = []
    max_targets = len(module.params["environment_targets"]) - 1
    for idx, env in enumerate(module.params["environment_targets"]):
        source = {"key": module.params["environment_key"]}

        target = {"key": env}

        feature_flag_copy_body = {"source": source, "target": target}

        if module.params["included_actions"] is not None:
            feature_flag_copy_body["included_actions"] = module.params[
                "included_actions"]

        if module.params["excluded_actions"] is not None:
            feature_flag_copy_body["excluded_actions"] = module.params[
                "excluded_actions"]

        try:
            response, status, headers = api_instance.copy_feature_flag_with_http_info(
                module.params["project_key"],
                module.params["flag_key"],
                launchdarkly_api.FeatureFlagCopyBody(**feature_flag_copy_body),
            )

            if idx == max_targets:
                # LD Returns a FeatureFlag Object containing all Environments. Only need last one.
                feature_flag = response.to_dict()

        except ApiException as e:
            if e.status == 429:
                time.sleep(reset_rate(e.headers["X-RateLimit-Reset"]))
                api_instance.copy_feature_flag_with_http_info(
                    module.params["project_key"],
                    module.params["flag_key"],
                    launchdarkly_api.FeatureFlagCopyBody(
                        **feature_flag_copy_body),
                )
            else:
                fail_exit(module, e)

    module.exit_json(changed=True,
                     msg="feature flags synced",
                     feature_flag=feature_flag)
Esempio n. 17
0
def _configure_project(module, api_instance, project=None, changed=False):
    if module.params["conftest"]["enabled"]:
        rego_test(module)

    patches = []

    if project:
        if module.params["tags"] is None or set(project.tags) == set(
                module.params["tags"]):
            del module.params["tags"]
        if project.name == module.params["name"]:
            del module.params["name"]
        # Uncomment when attribute is added to project response
        # if project.include_in_snippet_by_default == module.params['include_in_snippet_by_default']:
        #  del module.parmas['include_in_snippet_by_default']

    for key in module.params:
        if module.params.get(key) and key not in [
                "state",
                "api_key",
                "environments",
                "project_key",
                "conftest",
        ]:
            patches.append(_parse_project_param(module, key))

    if len(patches) > 0:
        try:
            response, status, headers = api_instance.patch_project_with_http_info(
                module.params["project_key"], patch_delta=patches)
            changed = True
        except ApiException as e:
            fail_exit(module, e)

    try:
        response
    except NameError:
        response = project

    module.exit_json(
        changed=changed,
        msg="project successfully configured",
        content=response.to_dict(),
    )
Esempio n. 18
0
def _create_webhook(module, api_instance):
    if module.params["state"] == "enabled":
        webhook_status = True
    else:
        webhook_status = False

    webhook_config = {
        "url": module.params["url"],
        "sign": module.params["sign"],
        "on": webhook_status,
    }

    if module.params.get("secret"):
        webhook_config["secret"] = module.params["secret"]
    webhook_config["name"] = (
        module.params["name"] if module.params.get("name") else module.params["url"]
    )

    if module.params["tags"]:
        webhook_config["tags"] = module.params["tags"]

    if module.params["statements"]:
        filtered_statements = []
        for statement in module.params["statements"]:
            filtered_statements.append(
                dict(
                    (launchdarkly_api.Statement.attribute_map[k], v)
                    for k, v in statement.items()
                    if v is not None
                )
            )
        webhook_config["statements"] = filtered_statements
    webhook_body = launchdarkly_api.WebhookBody(**webhook_config)

    try:
        api_response = api_instance.post_webhook(webhook_body)
        module.params["webhook_id"] = api_response.id
    except ApiException as e:
        fail_exit(module, e)

    module.exit_json(
        changed=True, msg="webhook created", webhook=api_response.to_dict()
    )
Esempio n. 19
0
def _configure_flag(module, api_instance, feature_flag=None):
    patches = configure_flag(module.params, feature_flag)

    if len(patches) == 0:
        module.exit_json(changed=False, msg="feature flag unchanged")

    if module.params["comment"]:
        comment = module.params["comment"]
    else:
        comment = "Ansible generated operation."
    comments = dict(comment=comment, patch=patches)

    try:
        response, status, headers = api_instance.patch_feature_flag_with_http_info(
            module.params["project_key"], module.params["key"], comments)
        module.exit_json(changed=True,
                         msg="feature flag updated",
                         content=response.to_dict())
    except ApiException as e:
        fail_exit(module, e)
def main():
    module = AnsibleModule(
        argument_spec=dict(
            api_key=dict(
                required=True,
                type="str",
                no_log=True,
                fallback=(env_fallback, ["LAUNCHDARKLY_ACCESS_TOKEN"]),
            ),
            env=dict(type="str"),
            project_key=dict(type="str", required=True),
            key=dict(type="str"),
            summary=dict(type="bool"),
            archived=dict(type="bool"),
            tag=dict(type="str"),
        )
    )

    if not HAS_LD:
        module.fail_json(
            msg=missing_required_lib("launchdarkly_api"), exception=LD_IMP_ERR
        )

    # Set up API
    configuration = configure_instance(module.params["api_key"])
    api_instance = launchdarkly_api.FeatureFlagsApi(
        launchdarkly_api.ApiClient(configuration)
    )

    try:
        feature_flags = fetch_flags(module.params, api_instance)
    except launchdarkly_api.rest.ApiException as e:
        fail_exit(module, e)

    if feature_flags.get("items"):
        flags = feature_flags["items"]
    else:
        flags = feature_flags
    module.exit_json(changed=True, feature_flags=flags)
Esempio n. 21
0
def _create_environment(module, api_instance):

    environment_config = {
        "name": module.params["name"],
        "key": module.params["environment_key"],
        "color": module.params["color"],
    }

    if module.params["default_ttl"]:
        environment_config["defaultTtl"] = module.params["default_ttl"]
    environment_body = launchdarkly_api.EnvironmentPost(**environment_config)

    try:
        _, status, _ = api_instance.post_environment_with_http_info(
            project_key=module.params["project_key"],
            environment_body=environment_body)
        if status != 201:
            module.exit_json(failed=True,
                             msg="failed to create environment, status: %d" %
                             status)
    except ApiException as e:
        fail_exit(module, e)

    _configure_environment(module, api_instance)
def _configure_custom_role(module, api_instance):
    patches = []
    for key in module.params:
        if (key not in ["state", "api_key", "key", "conftest"]
                and module.params[key] is not None):
            patches.append(_parse_custom_role_param(module, key))

    if len(patches) > 0:
        try:
            api_response = api_instance.patch_custom_role(module.params["key"],
                                                          patch_delta=patches)
        except ApiException as e:
            if e.status == 404:
                module.exit_json(failed=True,
                                 msg="custom role: %s not found" %
                                 module["key"])
            else:
                fail_exit(module, e)

        module.exit_json(changed=True,
                         msg="successfully updated custom role: %s" %
                         api_response.key)
    else:
        module.exit_json(changed=False, msg="custom role unchanged")
Esempio n. 23
0
def _delete_project(module, api_instance):
    try:
        api_instance.delete_project(module.params["project_key"])
        module.exit_json(msg="successfully deleted project")
    except ApiException as e:
        fail_exit(module, e)
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"]),
    )
def _configure_user_segment(module,
                            api_instance,
                            api_response=None,
                            ans_changed=False):
    name = (module.params["name"] if module.params["name"] is not None else
            module.params["user_segment_key"])
    patches = []
    user_segment = api_response
    if user_segment:
        if user_segment.name == name and module.params["name"]:
            del module.params["name"]
        if (user_segment.description == module.params["description"]
                and module.params["description"]):
            del module.params["description"]
        if set(user_segment.tags) == set(module.params["tags"]):
            del module.params["tags"]
        if (user_segment.included and module.params["included"] and set(
                user_segment.included) == set(module.params["included"])):
            del module.params["included"]
        if (user_segment.excluded and module.params["excluded"] and set(
                user_segment.excluded) == set(module.params["excluded"])):
            del module.params["excluded"]
        dict_segment = user_segment.to_dict()
        result = diff(
            dict_segment["rules"],
            module.params["rules"],
            ignore=set([
                "kind",
                "maintainer_id",
                "tags",
                "api_key",
                "creation_date",
                "state",
                "goal_ids",
                "links",
                "maintainer",
                "id",
                "project_key",
                "comment",
                "key",
                "version",
                "user_segment_key",
                "conftest",
            ]),
        )
        if len(list(result)) == 0:
            del module.params["rules"]
    for key in module.params:
        if key not in [
                "state",
                "api_key",
                "environment_key",
                "project_key",
                "user_segment_key",
                "conftest",
        ]:
            if module.params[key] is not None:
                patches.append(parse_user_param(module.params, key))

    if len(patches) > 0:
        try:
            response, status, headers = api_instance.patch_user_segment_with_http_info(
                module.params["project_key"],
                module.params["environment_key"],
                module.params["user_segment_key"],
                patch_only=patches,
            )
            ans_changed = True
            segment = response
            msg = "user segment successfully configured"
        except ApiException as e:
            if e.status == 404:
                module.exit_json(failed=True, msg="user segment key not found")
            else:
                fail_exit(module, e)
    else:
        segment = user_segment
        msg = "segment unchanged"

    module.exit_json(changed=ans_changed,
                     msg=msg,
                     user_segment=to_native(segment.to_dict()))
def _delete_webhook(module, api_instance):
    try:
        api_instance.delete_webhook(module.params["webhook_id"])
        module.exit_json(msg="successfully deleted webhook")
    except ApiException as e:
        fail_exit(module, e)
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 _configure_flag(module, api_instance, feature_flag=None):
    patches = []
    if feature_flag:
        if feature_flag.name == module.params["name"]:
            del module.params["name"]
        if feature_flag.description == module.params["description"]:
            del module.params["description"]
        if feature_flag.include_in_snippet == module.params[
                "include_in_snippet"]:
            del module.params["include_in_snippet"]
        if feature_flag.temporary == module.params["temporary"]:
            del module.params["temporary"]
        if module.params["tags"] is not None and set(feature_flag.tags) == set(
                module.params["tags"]):
            del module.params["tags"]
        result = diff(
            feature_flag.to_dict(),
            module.params,
            ignore=set([
                "kind",
                "maintainer_id",
                "tags",
                "api_key",
                "creation_date",
                "state",
                "goal_ids",
                "links",
                "maintainer",
                "id",
                "project_key",
                "comment",
                "key",
                "version",
                "custom_properties",
                "salt",
                "environments",
            ]),
        )
        out_vars = list(result)
        if out_vars:
            changed = [
                variation for effects in out_vars for variation in effects
                if variation in ["variations"]
            ]
        # TODO fix logic to pass in name and description for bool
        if len(changed) > 0 and module.params["variations"]:
            _patch_variations(module, feature_flag.variations, patches)
            del module.params["variations"]
        else:
            del module.params["variations"]
        if (feature_flag.maintainer_id == module.params["maintainer_id"]
                or module.params["maintainer_id"] is None):
            del module.params["maintainer_id"]
        for key in module.params:
            if (key not in [
                    "state",
                    "api_key",
                    "key",
                    "environment_key",
                    "project_key",
                    "kind",
                    "comment",
                    "clone",
                    "variations",
                    "conftest",
            ] and module.params[key] is not None):
                patches.append(_parse_flag_param(module, key, key))
        if len(patches) == 0:
            module.exit_json(changed=False, msg="feature flag unchanged")

    if module.params["comment"]:
        comment = module.params["comment"]
    else:
        comment = "Ansible generated operation."
    comments = dict(comment=comment, patch=patches)

    try:
        response, status, headers = api_instance.patch_feature_flag_with_http_info(
            module.params["project_key"], module.params["key"], comments)
        module.exit_json(changed=True,
                         msg="feature flag updated",
                         content=response.to_dict())
    except ApiException as e:
        fail_exit(module, e)
def _delete_custom_role(module, api_instance):
    try:
        api_instance.delete_custom_role(module.params["key"])
        module.exit_json(msg="successfully deleted custom role")
    except ApiException as e:
        fail_exit(module, e)