Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SA-6478] Add owner label as a prefix while creating integration #165

Open
wants to merge 58 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
397baf5
Add owner label as a prefix while creating integration
John2020-cyber Dec 13, 2024
5a9749c
fix
John2020-cyber Dec 13, 2024
f859b3b
update
John2020-cyber Dec 31, 2024
76ca029
update
John2020-cyber Dec 31, 2024
bb6b879
update
John2020-cyber Dec 31, 2024
216a83c
update
John2020-cyber Dec 31, 2024
d80869f
update
John2020-cyber Dec 31, 2024
316825f
update
John2020-cyber Dec 31, 2024
5bba315
update
John2020-cyber Dec 31, 2024
bb371a9
update
John2020-cyber Jan 7, 2025
a68b36f
update
John2020-cyber Jan 7, 2025
4f4ba58
update
John2020-cyber Jan 7, 2025
6993d79
update
John2020-cyber Jan 7, 2025
04d450a
update
John2020-cyber Jan 7, 2025
fb5a916
update
John2020-cyber Jan 7, 2025
1155d1a
update
John2020-cyber Jan 7, 2025
ba41590
update
John2020-cyber Jan 7, 2025
ee54ea8
update
John2020-cyber Jan 7, 2025
755288b
update
John2020-cyber Jan 7, 2025
f1f85c9
update
John2020-cyber Jan 7, 2025
6497252
update
John2020-cyber Jan 7, 2025
dddfba0
update
John2020-cyber Jan 7, 2025
ad85cee
update
John2020-cyber Jan 7, 2025
83b7b1e
update
John2020-cyber Jan 7, 2025
50b22c2
update
John2020-cyber Jan 7, 2025
a707fc0
update
John2020-cyber Jan 7, 2025
ac800a4
update
John2020-cyber Jan 7, 2025
9796f90
update
John2020-cyber Jan 7, 2025
b3dd087
update
John2020-cyber Jan 8, 2025
70f8d42
update
John2020-cyber Jan 8, 2025
99accb5
update
John2020-cyber Jan 8, 2025
58dbff6
update
John2020-cyber Jan 8, 2025
3ca8b4c
update
John2020-cyber Jan 8, 2025
609e850
update
John2020-cyber Jan 8, 2025
dd486ea
update
John2020-cyber Jan 8, 2025
7f09d37
update
John2020-cyber Jan 8, 2025
7696fdc
update
John2020-cyber Jan 8, 2025
e6f93dd
update
John2020-cyber Jan 8, 2025
313564e
update
John2020-cyber Jan 8, 2025
d6bac6d
update
John2020-cyber Jan 8, 2025
f720a42
update
John2020-cyber Jan 8, 2025
ef8b6e1
update
John2020-cyber Jan 8, 2025
31b81b3
update
John2020-cyber Jan 8, 2025
d9f8f67
update
John2020-cyber Jan 8, 2025
aa1615c
update
John2020-cyber Jan 8, 2025
bbbda93
update
John2020-cyber Jan 8, 2025
14ed456
update
John2020-cyber Jan 8, 2025
c5d63b3
update
John2020-cyber Jan 8, 2025
8671912
update
John2020-cyber Jan 8, 2025
2882936
update
John2020-cyber Jan 8, 2025
da6e35d
update
John2020-cyber Jan 8, 2025
73e5efc
update
John2020-cyber Jan 8, 2025
ed95730
update
John2020-cyber Jan 8, 2025
1bfc635
update
John2020-cyber Jan 8, 2025
4aa724f
update
John2020-cyber Jan 8, 2025
656b17a
update
John2020-cyber Jan 8, 2025
957073f
update
John2020-cyber Jan 8, 2025
b605b5d
update
John2020-cyber Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,33 @@
kind: ManagedCluster
register: managed_clusters_raw

- name: Extract list of ManagedCluster CRs
- name: Initialize managed_clusters as an empty list
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comments on each code block why you need this , like first initialize list then extract names of managed clusters .. currently code is not very understandable

ansible.builtin.set_fact:
managed_clusters: "{{ managed_clusters | default([]) + [{'name': item.metadata.name}] }}"
managed_clusters: []

- name: Extract ManagedCluster names with prefix
ansible.builtin.set_fact:
managed_cluster_names: "{{ managed_cluster_names | default([]) + [item.metadata.name] }}"
loop: "{{ managed_clusters_raw.resources }}"
loop_control:
loop_var: item

- name: Extract ManagedCluster owners with prefix
ansible.builtin.set_fact:
managed_cluster_owners: "{{ managed_cluster_owners | default([]) + [item.metadata.labels.owner | default('unknown')] }}"
loop: "{{ managed_clusters_raw.resources }}"
loop_control:
loop_var: item

- name: Determine which ManagedCluster CR doesn't have integrations
- name: Combine managed_cluster_names and managed_cluster_owners into a list of strings
ansible.builtin.set_fact:
create_integration_for: "{{ managed_clusters | rejectattr('name', 'in', existing_integration_names) | list }}"
managed_clusters: >-
{{
managed_cluster_names
| zip(managed_cluster_owners)
| map('join', '-')
| list
}}
- name: Fetch current status of Config CR
kubernetes.core.k8s_info:
Expand All @@ -57,13 +74,9 @@
ansible.builtin.set_fact:
previous_managed_clusters: "{{ config_cr.resources[0].status.managedClusters | default([]) }}"

- name: Extract current ManagedCluster names
ansible.builtin.set_fact:
current_managed_clusters: "{{ managed_clusters | map(attribute='name') | list }}"

- name: Determine integrations to delete in Grafana Cloud
ansible.builtin.set_fact:
delete_integration_for: "{{ previous_managed_clusters | difference(current_managed_clusters) }}"
delete_integration_for: "{{ previous_managed_clusters | difference(managed_clusters) }}"

- name: Delete integrations and dashboards when there are integrations to delete
when: delete_integration_for | length > 0
Expand Down Expand Up @@ -136,14 +149,27 @@
message: "Clears old managed clusters"
when: delete_integration_for

- name: Remove deleted integrations from managedClusters
ansible.builtin.set_fact:
updated_managed_clusters: >-
{{
config_cr.resources[0].status.managedClusters
| map('regex_replace', '^name: ', '')
| map('regex_replace', '-owner: ', '-')
| difference(delete_integration_for)
| unique
| list
}}
when: delete_integration_for | length > 0

- name: Update CR status for IntegrationsDeleted
operator_sdk.util.k8s_status:
api_version: grafanacloud.stakater.com/v1alpha1
kind: Config
name: "{{ cr_name }}"
namespace: "{{ cr_namespace }}"
status:
managedClusters: "{{ current_managed_clusters }}"
managedClusters: "{{ updated_managed_clusters }}"
conditions:
- lastTransitionTime: "{{ ansible_date_time.iso8601 }}"
status: "True"
Expand All @@ -160,7 +186,7 @@
kind: ManifestWork
metadata:
name: "{{ item.name }}-manifestwork-grafana-oncall"
namespace: "{{ item.name }}"
namespace: "{{ item.name | regex_replace('^(.+)-[^-]+$', '\\1') }}"
spec:
workload:
manifests:
Expand All @@ -169,11 +195,10 @@
metadata:
name: alertmanager-main
namespace: openshift-monitoring
loop: "{{ integrations_to_delete }}" # Ensure you have a loop here
loop: "{{ integrations_to_delete }}"
loop_control:
label: "{{ item.name }}"
when:
- delete_integration_for | length > 0
when: delete_integration_for | length > 0
register: manifestwork_deletion_results

- name: End play if any integrations failed or were skipped
Expand Down
166 changes: 129 additions & 37 deletions roles/grafana_cloud_operator/tasks/grafana_oncall_hub_spoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,48 +43,109 @@
kind: ManagedCluster
register: managed_clusters_raw

- name: Extract the list of ManagedCluster CRs
- name: Extract ManagedCluster names with prefix
ansible.builtin.set_fact:
managed_clusters: "{{ managed_clusters | default([]) + [{'name': item.metadata.name}] }}"
managed_cluster_names: "{{ managed_cluster_names | default([]) + ['name: ' ~ item.metadata.name] }}"
loop: "{{ managed_clusters_raw.resources }}"
loop_control:
loop_var: item

- name: Remove duplicate entries from managed_clusters
- name: Extract ManagedCluster owners with prefix
ansible.builtin.set_fact:
managed_clusters: "{{ managed_clusters | unique(attribute='name') }}"
managed_cluster_owners: "{{ managed_cluster_owners | default([]) + ['owner: ' ~ item.metadata.labels.owner | default('unknown')] }}"
loop: "{{ managed_clusters_raw.resources }}"
loop_control:
loop_var: item

- name: Combine managed_cluster_names and managed_cluster_owners into a dictionary
ansible.builtin.set_fact:
managed_clusters: >-
{{
dict(
managed_cluster_names
| map('regex_replace', '^name: ', '')
| zip(
managed_cluster_owners
| map('regex_replace', '^owner: ', '')
)
)
}}
- name: Adds name as prefix to integration_names
ansible.builtin.set_fact:
integration_names: "{{ existing_integration_names | map('regex_replace', '^', 'name: ') | list }}"

- name: Determine which ManagedCluster CRs don't have integrations
- name: Filter common clusters for integration by name
ansible.builtin.set_fact:
create_integration_for: "{{ managed_clusters | rejectattr('name', 'in', existing_integration_names) | list }}"
common_clusters: >-
{{
managed_clusters
| dict2items
| selectattr('key', 'in', integration_names)
| items2dict
}}
- name: Determine which ManagedCluster CRs don't have integrations (case-insensitive)
ansible.builtin.set_fact:
create_integration_for: >-
{{
managed_clusters
| dict2items
| map(attribute='key')
| zip(
managed_clusters | dict2items | map(attribute='value')
)
| map('join', '-')
| reject('in', integration_names
| map('regex_replace', '^name: ', '')
| map('lower')
| list)
| list
}}
- name: Transform create_integration_for into a list of dictionaries
ansible.builtin.set_fact:
create_integration_for_dict: "{{ create_integration_for_dict | default([]) + [{'name': item}] }}"
loop: "{{ create_integration_for }}"
loop_control:
loop_var: item

- name: Integration creation
block:
- name: Fetch Slack Channel from ManagedCluster namespace
kubernetes.core.k8s_info:
api_version: slack.stakater.com/v1alpha1
kind: Channel
namespace: "{{ item.name }}"
namespace: "{{ item.name | regex_replace('^(.+)-[^-]+$', '\\1') }}"
register: slack_channel_info
loop: "{{ create_integration_for }}"
loop: "{{ create_integration_for_dict }}"
loop_control:
label: "{{ item.name }}"
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Extract Channel id from slack channel
ansible.builtin.set_fact:
slack_channel_ids: "{{ slack_channel_ids | default([]) + [{'name': item.metadata.name, 'slack_id': item.status.id}] }}"
loop: "{{ slack_channel_info.results | map(attribute='resources') | flatten }}"
loop_control:
label: "{{ item.metadata.name }}"
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Populate List with spaces if any
vars:
slack_id_fetched: "{{ slack_channel_ids | selectattr('name', 'contains', item.name) | map(attribute='slack_id') | join(',') }}"
slack_id_fetched: >-
{{
slack_channel_ids
| default([])
| selectattr('name', 'contains', item)
| map(attribute='slack_id')
| join(',')
}}
ansible.builtin.set_fact:
slack_channel_validated: "{{ slack_channel_validated | default([]) + [{'name': item.name, 'slack_id': slack_id_fetched}] }}"
slack_channel_validated: "{{ slack_channel_validated | default([]) + [{'name': item, 'slack_id': slack_id_fetched}] }}"
loop: "{{ create_integration_for }}"
loop_control:
label: "{{ item.name }}"
label: "{{ item }}"
when: slack_channel_ids is defined

- name: Create a new integration in Grafana OnCall integration for each ManagedClusters that does not have one
Expand All @@ -102,29 +163,30 @@
"type": "alertmanager",
"name": item.name,
"default_route": {
"slack": {
"channel_id": slack_channel_validated[loop_index].slack_id,
"enabled": slack_cond
}
"slack": {
"channel_id": slack_channel_validated[loop_index].slack_id,
"enabled": slack_cond
}
} if slack_channel_validated is defined and
slack_channel_validated | length > loop_index and
slack_channel_validated[loop_index].slack_id | length > 0
else {
"type": "alertmanager",
"name": item.name
}
} if slack_channel_validated is defined and
slack_channel_validated | length > loop_index and
slack_channel_validated[loop_index].slack_id | length > 0
else {
"type": "alertmanager",
"name": item.name
}
}}
status_code: [200, 201]
register: grafana_integration_response
loop: "{{ create_integration_for }}"
loop: "{{ create_integration_for_dict }}"
loop_control:
label: "{{ item.name }}"
index_var: loop_index
retries: 5
delay: 6
until: grafana_integration_response.status in [200, 201]
failed_when: false
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Update status with ManagedCluster field
operator_sdk.util.k8s_status:
Expand All @@ -136,25 +198,41 @@
managedClusters: []
when:
- "'managedClusters' not in current_config_cr.resources[0].status"
- create_integration_for | length == grafana_integration_response.results | length
- create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Extract existing ManagedCluster names from current status
ansible.builtin.set_fact:
existing_managed_cluster_names: "{{ current_config_cr.resources[0].status.managedClusters | list | default([]) }}"
when: create_integration_for | length == grafana_integration_response.results | length
existing_managed_cluster_names: >-
{{
current_config_cr.resources[0].status.managed_clusters
| default([])
}}
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Set fact for list of ManagedCluster names
- name: Extract new ManagedCluster names
ansible.builtin.set_fact:
managed_cluster_names: "{{ managed_clusters | map(attribute='name') | list }}"
when: create_integration_for | length == grafana_integration_response.results | length
managed_cluster_names: >-
{{
managed_clusters
| dict2items
| map(attribute='key')
| zip(
managed_clusters
| dict2items
| map(attribute='value')
)
| map('join', '-')
| list
}}
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Merge existing ManagedCluster names with new ones
ansible.builtin.set_fact:
updated_managed_cluster_names: >-
{{
(existing_managed_cluster_names + managed_cluster_names) | unique
}}
when: create_integration_for | length == grafana_integration_response.results | length
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Update CR status to IntegrationsCreated
operator_sdk.util.k8s_status:
Expand All @@ -170,7 +248,7 @@
type: "Successful"
reason: "IntegrationsCreated"
message: "Grafana integrations created for all ManagedClusters."
when: create_integration_for | length == grafana_integration_response.results | length
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Inform user if Grafana integration creation was skipped or failed
when: grafana_integration_response is skipped or (grafana_integration_response.results | rejectattr('status', 'in', [200, 201]) | list | length > 0)
Expand All @@ -193,26 +271,37 @@
reason: "IntegrationCreationFailed"
message: "Failed to create Grafana integration for ManagedClusters."
loop: "{{ grafana_integration_response.results }}"
when: item.status not in [200, 201]

- name: Start deletion for hubAndSpoke mode
ansible.builtin.include_tasks: delete_grafana_oncall_hub_spoke.yml
when:
- grafana_integration_response is defined
- grafana_integration_response.results is defined
- grafana_integration_response.results | length > 0
- item.status not in [200, 201]

- name: Associate Grafana integration details with ManagedClusters
ansible.builtin.set_fact:
mapped_integrations: "{{ mapped_integrations | default([]) + [{'cluster': item.item, 'grafana_details': item.json}] }}"
loop: "{{ grafana_integration_response.results }}"
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Transform and set namespace for each cluster
ansible.builtin.set_fact:
transformed_namespaces: "{{ item.cluster.name | regex_replace('^(.*?)-.*$', '\\1') }}"
loop: "{{ mapped_integrations }}"
loop_control:
label: "{{ item.cluster.name }}"
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

# Following tasks will execute only if Grafana integration was created successfully
- name: Modify Alertmanager secret
ansible.builtin.include_tasks: modify_alertmanager_secret.yml
vars:
receiver_name: "{{ item.grafana_details.name }}"

Check warning on line 298 in roles/grafana_cloud_operator/tasks/grafana_oncall_hub_spoke.yml

View workflow job for this annotation

GitHub Actions / Operator Pull Request

jinja[spacing]

Jinja2 spacing could be improved: {{ transformed_namespaces }} -> {{ transformed_namespaces }}
receiver_url: "{{ item.grafana_details.link }}"
namespace: "{{ item.cluster.name }}"
namespace: "{{ transformed_namespaces }}"
cluster_name: "{{ item.cluster.name }}"
provision_mode: "hubAndSpoke"
loop: "{{ mapped_integrations }}"
when: create_integration_for_dict is defined and create_integration_for_dict | length > 0

- name: Update CR status for ManifestWork creation
operator_sdk.util.k8s_status:
Expand All @@ -227,7 +316,7 @@
type: "Successful"
reason: "ManifestWorksCreated"
message: "ManifestWorks created for all ManagedClusters"
when: not manifestwork_creation_results.failed
when: manifestwork_creation_results is defined and not manifestwork_creation_results.failed

- name: Update CR status for ManifestWork creation failure
kubernetes.core.k8s:
Expand All @@ -244,4 +333,7 @@
type: "Failed"
reason: "ManifestWorkCreationFailed"
message: "Failed to create ManifestWork for one or more ManagedClusters"
when: manifestwork_creation_results.failed
when: manifestwork_creation_results is defined and not manifestwork_creation_results.failed

- name: Start deletion for hubAndSpoke mode
ansible.builtin.include_tasks: delete_grafana_oncall_hub_spoke.yml
Loading
Loading