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

Initial changes for dashboards automation #78

Merged
merged 1 commit into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 15 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ on:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
lint:
runs-on: ubuntu-latest

steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2

- name: Get dependencies
run: make deps

- name: Run jsonnetfmt
run: make format

build:
runs-on: ubuntu-latest

Expand All @@ -35,23 +48,10 @@ jobs:

- name: Import dashboards to grafana
run: >
for t in rendered/*.json; do
for t in rendered/**/*.json; do
echo "Importing ${t}";
dashboard=$(cat ${t});
echo "{\"dashboard\": ${dashboard}, \"overwrite\": true}" |
curl -k -Ss -XPOST -H "Content-Type: application/json" -H "Accept: application/json" -d@-
"http://admin:admin@localhost:3000/api/dashboards/db" -o /dev/null;
done

lint:
runs-on: ubuntu-latest

steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2

- name: Get dependencies
run: make deps

- name: Run jsonnetfmt
run: for t in templates/*.jsonnet; do echo "Testing template ${t}"; ./bin/jsonnetfmt --test $t; echo 'Results:' ${?}; done
done
15 changes: 4 additions & 11 deletions .github/workflows/grafana.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ defaults:
run:
shell: bash

env:
# Space separated list as a string of all dashboard json files in "rendered" to load
DASHBOARDS: "kube-burner.json"

on:
push:
branches: [ master ]
Expand All @@ -25,13 +21,10 @@ jobs:
# The secret GRAFANA_URL must be set with the format http://username:[email protected] without a trailing /
- name: Import dashboards to grafana
run: >
dashboard_list=($(echo $DASHBOARDS));
for path in "${dashboard_list[@]}"; do
full_path="rendered/${path}";
echo "Importing ${full_path}";
dashboard=$(cat ${full_path});
for t in rendered/**/*.json; do
echo "Importing ${t}";
dashboard=$(cat ${t});
echo "{\"dashboard\": ${dashboard}, \"overwrite\": true}" |
curl -k -Ss -XPOST -H "Content-Type: application/json" -H "Accept: application/json" -d@-
Copy link
Member

Choose a reason for hiding this comment

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

The internal grafana won't be accessible from outside

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, Those actions in workflows are not of any use right now. They just help us to do some sanity checks, if we are able to build jsons and deploy them into grafana. To start with lets keep it that way and our plan is to extend the same actions for our automatic deployments in future.

Copy link
Member

@rsevilla87 rsevilla87 Oct 2, 2023

Choose a reason for hiding this comment

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

As is now this workflow is gonna fail, is that expected?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes it is expected and I am planning to take it outside of this PR scope. It has been failing since a while: https://github.com/cloud-bulldozer/performance-dashboards/actions/runs/6252714644/job/16976553973 as github actions won't be able to reach our observability cluster.

"${{ secrets.GRAFANA_URL }}/api/dashboards/db" -o /dev/null;
done

done
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM registry.access.redhat.com/ubi8/ubi-minimal

# Set the working directory
WORKDIR /performance-dashboards

# Install necessary libraries for subsequent commands
RUN microdnf install -y podman python3 python3-pip && \
microdnf clean all && \
rm -rf /var/cache/yum

COPY . .

# Set permissions
RUN chmod -R 775 /performance-dashboards

# Install dependencies
RUN pip3 install --upgrade pip && \
pip3 install -r requirements.txt

# Start the command
CMD ["python3", "dittybopper/syncer/entrypoint.py"]
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ SYNCER_IMG_TAG ?= quay.io/cloud-bulldozer/dittybopper-syncer:latest
PLATFORM = linux/amd64,linux/arm64,linux/ppc64le,linux/s390x

# Get all templates at $(TEMPLATESDIR)
TEMPLATES = $(wildcard $(TEMPLATESDIR)/*.jsonnet)
TEMPLATES := $(wildcard $(TEMPLATESDIR)/**/*.jsonnet)

# Replace $(TEMPLATESDIR)/*.jsonnet by $(OUTPUTDIR)/*.json
outputs = $(patsubst $(TEMPLATESDIR)/%.jsonnet, $(OUTPUTDIR)/%.json, $(TEMPLATES))
outputs := $(patsubst $(TEMPLATESDIR)/%.jsonnet, $(OUTPUTDIR)/%.json, $(TEMPLATES))

all: deps format build

Expand Down Expand Up @@ -38,10 +38,11 @@ $(BINDIR)/jsonnet:
# Build each template and output to $(OUTPUTDIR)
$(OUTPUTDIR)/%.json: $(TEMPLATESDIR)/%.jsonnet
@echo "Building template $<"
mkdir -p $(dir $@)
$(BINDIR)/jsonnet $< > $@

build-syncer-image: build
podman build --platform=${PLATFORM} -f dittybopper/syncer/Dockerfile --manifest=${SYNCER_IMG_TAG} .
podman build --platform=${PLATFORM} -f Dockerfile --manifest=${SYNCER_IMG_TAG} .

push-syncer-image:
podman manifest push ${SYNCER_IMG_TAG} ${SYNCER_IMG_TAG}
podman manifest push ${SYNCER_IMG_TAG} ${SYNCER_IMG_TAG}
4 changes: 2 additions & 2 deletions dittybopper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ If using disconnected, you need to sync the cloud-bulldozer grafana image (shown
dittybopper/templates/dittybopper.yaml.template file) and your chosen syncer image
(defaults to quay.io/cloud-bulldozer/dittybopper-syncer:latest).

The syncer image is built with the context at the root of the repository, and the image in the dittybopper/syncer directory.
The syncer image is built with the context at the root of the repository, and the image in the root directory.
You can build it with `make build-syncer-image SYNCER_IMG_TAG=container.registry.org/organization/syncer:latest`
Alternatively, you can run the following command form the root folder of this repository: `podman build -f dittybopper/syncer/Dockerfile -t=container.registry.org/organization/syncer:latest .`
Alternatively, you can run the following command from the root folder of this repository: `podman build -f Dockerfile -t=container.registry.org/organization/syncer:latest .`

## Contribute

Expand Down
4 changes: 2 additions & 2 deletions dittybopper/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ END

export PROMETHEUS_USER=internal
export GRAFANA_ADMIN_PASSWORD=admin
export DASHBOARDS="ocp-performance.json api-performance-overview.json etcd-on-cluster-dashboard.json hypershift-performance.json ovn-dashboard.json"
export SYNCER_IMAGE=${SYNCER_IMAGE:-"quay.io/cloud-bulldozer/dittybopper-syncer:latest"} # Syncer image
export GRAFANA_URL="http://admin:${GRAFANA_ADMIN_PASSWORD}@localhost:3000"
export SYNCER_IMAGE=${SYNCER_IMAGE:-"quay.io/cloud-bulldozer/syncer:latest"} # Syncer image
export GRAFANA_IMAGE=${GRAFANA_IMAGE:-"quay.io/cloud-bulldozer/grafana:9.4.3"} # Syncer image

# Set defaults for command options
Expand Down
1 change: 1 addition & 0 deletions dittybopper/k8s-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ END

export PROMETHEUS_USER=internal
export GRAFANA_ADMIN_PASSWORD=admin
export GRAFANA_URL="http://admin:${GRAFANA_ADMIN_PASSWORD}@localhost:3000"
export DASHBOARDS="k8s-performance.json"
export SYNCER_IMAGE=${SYNCER_IMAGE:-"quay.io/cloud-bulldozer/dittybopper-syncer:latest"} # Syncer image
export GRAFANA_IMAGE=${GRAFANA_IMAGE:-"quay.io/cloud-bulldozer/grafana:9.4.3"} # Syncer image
Expand Down
7 changes: 0 additions & 7 deletions dittybopper/syncer/Dockerfile

This file was deleted.

129 changes: 129 additions & 0 deletions dittybopper/syncer/entrypoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import json
import logging
import os
import requests
import uuid
import time
from collections import defaultdict

logging.basicConfig(level=logging.INFO)


class GrafanaOperations:
"""
This class is responsible for Grafana operations
"""
def __init__(self, grafana_url: str, input_directory: str):
self.grafana_url = grafana_url
self.input_directory = input_directory
self.dashboards = defaultdict(list)
self.folder_map = dict()
self.logger = logging.getLogger(__name__)

def fetch_all_dashboards(self):
"""
This method fetches all rendered dashboards
:return:
"""
self.get_all_folders()
self.folder_map['General'] = None
for root, _, files in os.walk(self.input_directory):
folder_name = os.path.basename(root)
json_files = [os.path.join(root, filename) for filename in files if filename.endswith(".json")]
folder_name = "General" if (folder_name == "") else folder_name
if folder_name in self.folder_map:
folder_id = self.folder_map[folder_name]
else:
folder_id = self.create_folder(folder_name)
self.dashboards[folder_id].extend(json_files)

def get_all_folders(self):
"""
This method gets the entire list of folders in grafana
:return:
"""
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
}
try:
response = requests.get(
f"{self.grafana_url}/api/folders",
headers=headers,
)
response_json = response.json()
self.folder_map = {each_folder['title']: each_folder['id'] for each_folder in response_json}
except requests.exceptions.RequestException as e:
raise Exception(f"Error listing folders. Message: {e}")

def create_folder(self, folder_name):
"""
This method creates a folder in grafana
:return:
"""
uid = str(uuid.uuid4())
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
}
try:
response = requests.post(
f"{self.grafana_url}/api/folders",
headers=headers,
json={
"title": folder_name,
"uid": uid,
},
)
response_json = response.json()
self.folder_map[folder_name] = id
return response_json['id']

except requests.exceptions.RequestException as e:
raise Exception(f"Error creating folder with name:'{self.folder_name}' and uid:'{uid}'. Message: {e}")

def read_dashboard_json(self, json_file):
"""
This method reads dashboard from json file
:return:
"""
with open(json_file, 'r') as f:
return json.load(f)

def create_dashboards(self):
"""
This method creates/updates dashboard with new json
:return:
"""
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
}
for folder_id, files in self.dashboards.items():
for json_file in set(files):
dashboard_json = self.read_dashboard_json(json_file)
try:
response = requests.post(
f"{self.grafana_url}/api/dashboards/db",
headers=headers,
json={
"dashboard": dashboard_json,
"folderId": folder_id,
"overwrite": True,
},
)
if response.status_code == 200:
self.logger.info(f"Dashboard '{dashboard_json['title']}' created successfully in folder '{folder_id}'")
else:
raise Exception(
f"Failed to create dashboard '{dashboard_json['title']}' in folder '{folder_id}'. Status code: {response.status_code}. Message: {response.text}")

except requests.exceptions.RequestException as e:
raise Exception(f"Error creating dashboard '{dashboard_json['title']}' in folder '{folder_id}'. Message: {e}")

if __name__ == '__main__':
grafana_operations = GrafanaOperations(os.environ.get("GRAFANA_URL"), os.environ.get("INPUT_DIR"))
grafana_operations.fetch_all_dashboards()
grafana_operations.create_dashboards()
while True:
time.sleep(60)
22 changes: 0 additions & 22 deletions dittybopper/syncer/entrypoint.sh

This file was deleted.

8 changes: 4 additions & 4 deletions dittybopper/templates/dittybopper.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ spec:
- name: dittybopper-syncer
imagePullPolicy: Always
env:
- name: GRAFANA_ADMIN_PASSWORD
value: ${GRAFANA_ADMIN_PASSWORD}
- name: DASHBOARDS
value: ${DASHBOARDS}
- name: GRAFANA_URL
value: ${GRAFANA_URL}
- name: INPUT_DIR
value: "/performance-dashboards/rendered/"
image: ${SYNCER_IMAGE}
volumes:
- name: sc-grafana-config
Expand Down
8 changes: 4 additions & 4 deletions dittybopper/templates/k8s-dittybopper.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ spec:
- name: dittybopper-syncer
imagePullPolicy: Always
env:
- name: GRAFANA_ADMIN_PASSWORD
value: ${GRAFANA_ADMIN_PASSWORD}
- name: DASHBOARDS
value: ${DASHBOARDS}
- name: GRAFANA_URL
value: ${GRAFANA_URL}
- name: INPUT_DIR
value: "/performance-dashboards/rendered/"
image: ${SYNCER_IMAGE}
volumes:
- name: sc-grafana-config
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
requests==2.26.0

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local grafana = import 'grafonnet-lib/grafonnet/grafana.libsonnet';
local grafana = import '../grafonnet-lib/grafonnet/grafana.libsonnet';
local prometheus = grafana.prometheus;

//Panel definitions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local grafana = import 'grafonnet-lib/grafonnet/grafana.libsonnet';
local grafana = import '../grafonnet-lib/grafonnet/grafana.libsonnet';
local prometheus = grafana.prometheus;


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local grafana = import 'grafonnet-lib/grafonnet/grafana.libsonnet';
local grafana = import '../grafonnet-lib/grafonnet/grafana.libsonnet';
local prometheus = grafana.prometheus;

// Panel definitions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local grafana = import 'grafonnet-lib/grafonnet/grafana.libsonnet';
local grafana = import '../grafonnet-lib/grafonnet/grafana.libsonnet';
local prometheus = grafana.prometheus;
local stat = grafana.statPanel;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local grafana = import 'grafonnet-lib/grafonnet/grafana.libsonnet';
local grafana = import '../grafonnet-lib/grafonnet/grafana.libsonnet';
local prometheus = grafana.prometheus;


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local grafana = import 'grafonnet-lib/grafonnet/grafana.libsonnet';
local grafana = import '../grafonnet-lib/grafonnet/grafana.libsonnet';
local es = grafana.elasticsearch;

local worker_count = grafana.statPanel.new(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local grafana = import 'grafonnet-lib/grafonnet/grafana.libsonnet';
local grafana = import '../grafonnet-lib/grafonnet/grafana.libsonnet';
local prometheus = grafana.prometheus;


Expand Down
Loading