From f877822c2dd155640062a442bba7d1addd4eb70b Mon Sep 17 00:00:00 2001
From: Lenka Segura <lsegura@redhat.com>
Date: Feb 02 2023 06:53:12 +0000
Subject: [PATCH 1/2] Add tasks from communishift


---

diff --git a/roles/fas2discourseconfig/defaults/main.yml b/roles/fas2discourseconfig/defaults/main.yml
index 0bc6b5c..f6b8124 100644
--- a/roles/fas2discourseconfig/defaults/main.yml
+++ b/roles/fas2discourseconfig/defaults/main.yml
@@ -1,2 +1,6 @@
 ---
 # defaults file for Fas2discourseConfig
+fas2discourse_keytab_path: "/etc/fas2discourse"
+fas2discourse_principal: "fas2discourse/fas2discourse.hostname@FEDORAPROJECT.ORG"
+f2d_namespace: "fas2discourse-operator"
+f2d_secret: "fas2discourse-operator-k8s-secret"
diff --git a/roles/fas2discourseconfig/tasks/kerberos_auth.yml b/roles/fas2discourseconfig/tasks/kerberos_auth.yml
new file mode 100644
index 0000000..3b834dd
--- /dev/null
+++ b/roles/fas2discourseconfig/tasks/kerberos_auth.yml
@@ -0,0 +1,4 @@
+---
+# tasks file for Fas2Discourse
+- name: Authorize with kinit
+  shell: kinit -k -t "{{ fas2discourse_keytab_path  }}/fas2discourse-keytab" -l 3600 {{ fas2discourse_principal  }}
diff --git a/roles/fas2discourseconfig/tasks/main.yml b/roles/fas2discourseconfig/tasks/main.yml
index 1a10545..ee885de 100644
--- a/roles/fas2discourseconfig/tasks/main.yml
+++ b/roles/fas2discourseconfig/tasks/main.yml
@@ -1,2 +1,6 @@
 ---
 # tasks file for Fas2discourseConfig
+
+- include_tasks: kerberos_auth.yml
+- include_tasks: retrieve_ipa_groups.yml
+- include_tasks: sync_group_membership.yml 
diff --git a/roles/fas2discourseconfig/tasks/retrieve_ipa_groups.yml b/roles/fas2discourseconfig/tasks/retrieve_ipa_groups.yml
new file mode 100644
index 0000000..11fb50f
--- /dev/null
+++ b/roles/fas2discourseconfig/tasks/retrieve_ipa_groups.yml
@@ -0,0 +1,20 @@
+---
+# tasks file for fas2discourse
+
+- name: Retrieve fasjson group/user data based on pattern supplied
+  fas2discourse_retrieve_fasjson_data:
+    keytab_path: "{{ fas2discourse_keytab_path }}"
+    principal: "{{ fas2discourse_principal }}"
+    group_name_pattern: "{{ fas2discourse_group_regex_pattern }}"
+  register: fasjson_response
+
+- name: Set fact
+  set_fact:
+    fas2discourse_fasjson_response: "{{ fasjson_response }}"
+#- name: Prints the groups
+#  ansible.builtin.debug:
+#    msg:
+#    - "Groups found: {{ fas2discourse_fasjson_response['matched_groups'] }}"
+
+#- name: Write groups to json file
+#  copy: content="{{ fas2discourse_fasjson_response['matched_groups'] }}" dest=/tmp/groups.json
diff --git a/roles/fas2discourseconfig/tasks/sync_group_membership.yml b/roles/fas2discourseconfig/tasks/sync_group_membership.yml
new file mode 100644
index 0000000..6de3990
--- /dev/null
+++ b/roles/fas2discourseconfig/tasks/sync_group_membership.yml
@@ -0,0 +1,29 @@
+---
+# tasks file for Fas2Discourse
+
+- k8s_info:
+    api_version: v1
+    kind: Secret
+    namespace: "{{ cao_namespace }}"
+    name: "{{ cao_secret }}"
+  register: cao_secret_yaml
+
+- set_fact:
+    cao_secret: "{{ cao_secret_yaml.resources[0] | from_yaml }}"
+- set_fact:
+    fas2discourse_ocp_api_token: "{{ cao_secret.data['fas2discourse-ocp-api-token'] | b64decode }}"
+- set_fact:
+    fas2discourse_ocp_api_host: "{{ cao_secret.data['fas2discourse-ocp-api-host'] | b64decode }}"
+
+- name: Sync user membership between IPA and Openshift Groups
+  community.okd.k8s:
+    api_key: "{{ fas2discourse_ocp_api_token }}"
+    host: "{{ fas2discourse_ocp_api_host }}"
+    state: present
+    definition:
+      apiVersion: user.openshift.io/v1
+      kind: Group
+      metadata:
+        name: "{{ item['groupname'] }}-admins"
+      users: "{{ item['groupmembers'] | default([]) }}"
+  with_items: "{{ fas2discourse_fasjson_response['matched_groups'] }}"

From 8f5ae589948cc9ee0a85eb85da07cc9e19bc8fb5 Mon Sep 17 00:00:00 2001
From: Lenka Segura <lsegura@redhat.com>
Date: Feb 07 2023 09:50:00 +0000
Subject: [PATCH 2/2] Add python module to library


---

diff --git a/roles/fas2discourseconfig/library/fas2discourse_retrieve_fasjson_data.py b/roles/fas2discourseconfig/library/fas2discourse_retrieve_fasjson_data.py
new file mode 100644
index 0000000..e98aaeb
--- /dev/null
+++ b/roles/fas2discourseconfig/library/fas2discourse_retrieve_fasjson_data.py
@@ -0,0 +1,190 @@
+#!/usr/bin/python
+
+# Copyright: (c) 2018, Terry Jones <terry.jones@example.org>
+# GNU General Public License v3.0+ (see COPYING or
+# https://www.gnu.org/licenses/gpl-3.0.txt)
+
+import json
+import requests
+
+from ansible.module_utils.basic import AnsibleModule
+from requests_kerberos import HTTPKerberosAuth
+
+__metaclass__ = type
+
+DOCUMENTATION = r"""
+---
+module: fas2discourse_retrieve_fasjson_data
+
+short_description: Retrieve fasjson group and user data.
+
+version_added: "0.0.1"
+
+description: This module retrieves fasjson group and users data which match
+the groups in discourse.
+
+options:
+    keytab_path:
+        description: This is the location on disk where the kerberos keytab is stored.
+        required: true
+        type: str
+    principal:
+        description: The is the kerberos principal.
+        required: true
+        type: str
+     discourse_groups:
+        description: These are the groups retrieved from the discouse.
+        required: true
+        type: str
+
+author:
+    - David Kirwan (dkirwan@redhat.com)
+    - Lenka Segura (lsegura@redhat.com)
+    - Patrik Polakovic (ppolakov@redhat.com)
+"""
+
+EXAMPLES = r"""
+- name: Retrieve fasjson group/user data based on the discourse groups
+  fas2discourse_retrieve_fasjson_data:
+    keytab_path: "{{ fas2discourse_keytab }}"
+    principal: "{{ fas2discourse_principal }}"
+    discourse_groups: "{{ discourse_groups }}"
+  register: fas2discourse_fasjson_response
+"""
+
+RETURN = r"""
+# These are examples of possible return values, and in general should use other names for return
+# values.
+matched_groups:
+    description: The groups and their users which match the discourse groups.
+    type: str
+    returned: always
+    sample:
+[
+  {
+    "group_name": "yyy",
+    "group_members": [
+      "uuu",
+      "iii",
+      "eee",
+      "zqq"
+    ]
+  },
+  {
+    "group_name": "abc",
+    "group_members": [
+      "xyc",
+      "cyz",
+      "xxx",
+      "zzz"
+    ]
+  }
+]
+
+msg:
+    description: The output message that the module generates.
+    type: str
+    returned: always
+    sample: 'Successfully retrieved groups and their users from fasjson.'
+"""
+
+
+# Helper function to create the http requests
+def get_http_client(keytab_path, principal):
+    try:
+        kerberos_auth = HTTPKerberosAuth(principal=principal)
+    except Exception as e:
+        print("Error trying to authenticate with Kerberos", e)
+        raise
+    session = requests.Session()
+    session.auth = kerberos_auth
+    return session
+
+
+# Helper function to retrieve fasjson groups
+def get_groups(http_client):
+    response = http_client.get("%sgroups/" % ("https://fasjson.fedoraproject.org/v1/"))
+    if response.ok:
+        return response.json()
+
+
+# Helper function to retrieve fasjson group members
+def get_group_members(http_client, groupname):
+    response = http_client.get(
+        "%sgroups/%s/members/" % ("https://fasjson.fedoraproject.org/v1/", groupname)
+    )
+    if response.ok:
+        return response.json()
+
+
+def run_module():
+    # define available arguments/parameters a user can pass to the module
+    module_args = dict(
+        keytab_path=dict(type="str", required=True),
+        principal=dict(type="str", required=True),
+        discourse_groups=dict(type="str", required=True),
+    )
+
+    # seed the result dict in the object
+    # we primarily care about changed and state
+    # changed is if this module effectively modified the target
+    # state will include any data that you want your module to pass back
+    # for consumption, for example, in a subsequent task
+    result = dict(changed=False, original_message="", message="")
+
+    # the AnsibleModule object will be our abstraction working with Ansible
+    # this includes instantiation, a couple of common attr would be the
+    # args/params passed to the execution, as well as if the module
+    # supports check mode
+    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
+
+    # if the user is working with this module in only check mode we do not
+    # want to make any changes to the environment, just return the current
+    # state with no modifications
+    if module.check_mode:
+        module.exit_json(**result)
+
+    # manipulate or modify the state as needed (this is going to be the
+    # part where your module will do what it needs to do)
+    keytab_path = module.params["keytab_path"]
+    principal = module.params["principal"]
+#    discourse_groups = module.params["discourse_groups"]
+    # let's hardcode the discourse groups for the moment
+    discourse_groups = ["council", "moderators", "design", "magazine_editors", "community-blog", "pgm-team"]
+
+    try:
+        http_client = get_http_client(keytab_path, principal)
+        groups_response = get_groups(http_client)
+
+        fas2discourse_groups = []
+        for v in groups_response["result"]:
+            if v["groupname"] in discourse_groups:
+                group = {"groupname": v["groupname"], "groupmembers": []}
+
+                group_member_res = get_group_members(http_client, v["groupname"])
+                # print(json.dumps(group_member_res))
+
+                for v in group_member_res["result"]:
+                    group["groupmembers"].append(v["username"])
+                fas2discourse_groups.append(group)
+                # print(v["groupname"])
+
+        # print(json.dumps(fas2discourse_groups))
+
+        result["matched_groups"] = json.dumps(fas2discourse_groups)
+        result["changed"] = True
+        result["msg"] = "Successfully retrieved groups and their users from fasjson."
+    except Exception:
+        raise
+
+    # in the event of a successful module execution, you will want to
+    # simple AnsibleModule.exit_json(), passing the key/value results
+    module.exit_json(**result)
+
+
+def main():
+    run_module()
+
+
+if __name__ == "__main__":
+    main()

