Skip to content

Commit

Permalink
Adds grafana organization support (#11)
Browse files Browse the repository at this point in the history
* adds grafana organization support

* update dependencies

* adds init.py to install script properly

* update dockerfile

* add github action to build and push docker image

* use the same path in Dockerfile as in makefile

* initial commit

* changed repository to novatec repo

---------

Co-authored-by: Jens Plüddemann <[email protected]>
  • Loading branch information
JenSeReal and Jens Plüddemann authored Oct 28, 2024
1 parent b9fe531 commit 26fb21a
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 21 deletions.
4 changes: 2 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
*.yml
*.csv
script/__pycache__**
**/*.md
.gitignore
132 changes: 132 additions & 0 deletions .github/workflows/docker-build-and-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: Create and publish a Docker image

on:
push:
branches: ["**"] # run for any commit or tag push on any branch
tags-ignore: ["v**"] # reserve v* tags for releases

env:
REGISTRY_IMAGE: ghcr.io/novatecconsulting/grafana-ldap-sync-script

jobs:
build:
name: Build and publish docker image for grafana-ldap-sync-script on ${{ matrix.platform }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
platform:
- linux/amd64
- linux/arm64
include:
- platform: linux/arm64
os: [ubuntu-latest]
- platform: linux/amd64
os: [ubuntu-latest]
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Prepare for grafana-ldap-sync-script on ${{ matrix.platform }}
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Extract metadata (tags, labels) for Docker from grafana-ldap-sync-script
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=ref,event=pr
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push by digest for grafana-ldap-sync-script ${{ matrix.platform }}
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=build-${{ env.PLATFORM_PAIR }}
cache-to: type=gha,scope=build-${{ env.PLATFORM_PAIR }}

- name: Export digest for grafana-ldap-sync-script on ${{ matrix.platform }}
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-grafana-ldap-sync-script-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

merge:
runs-on: ubuntu-latest
needs:
- build
strategy:
fail-fast: false
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-grafana-ldap-sync-script*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=ref,event=pr
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }}
33 changes: 27 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
FROM python:3.9-slim
FROM python:3.13-slim AS installer
RUN apt-get update
RUN apt-get install -y --no-install-recommends build-essential gcc

COPY requirements.txt /requirements.txt
RUN python -m venv /opt/venv
# Make sure we use the virtualenv:
ENV PATH="/opt/venv/bin:$PATH"

RUN pip install -r /requirements.txt && mkdir /app
WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY script ./script
COPY setup.py .
RUN pip install .

FROM python:3.13-slim AS runtime
COPY --from=installer /opt/venv /opt/venv

WORKDIR /data
COPY config.yml .
COPY example.csv /data/bind.csv

WORKDIR /app
# Make sure we use the virtualenv:
ENV PATH="/opt/venv/bin:$PATH"

COPY run.py .

COPY LICENSE run.py /app/
COPY script /app/script
VOLUME [ "/data" ]

ENTRYPOINT [ "python3", "./run.py" ]
CMD [ "python", "run.py", "--config=/data/config.yml", "--bind=/data/bind.csv" ]
3 changes: 2 additions & 1 deletion config.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
config:
grafana:

# URL of the target grafana-server.
url: localhost:3000
# Protocol to use when connecting to grafana (http, https)
Expand All @@ -9,6 +8,8 @@ config:
user: admin
# Password of account with admin rights on target grafana-server.
password: admin
# Grafana Organization ID that should be used to insert the teams.
# org_id: 1

ldap:
# Set to True if NTLM should be used for LDAP.
Expand Down
29 changes: 29 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
services:
grafana:
image: grafana/grafana:11.2.2
restart: unless-stopped
volumes:
- grafana-storage:/var/lib/grafana
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 1m
timeout: 1s
retries: 3
ports:
- 3000:3000
attach: false

grafana-ldap-sync-script:
build:
dockerfile: Dockerfile
volumes:
- ./example.csv:/data/bind.csv:ro
# you need to change grafana.config.url to 'grafana:3000' from 'localhost:3000' for this to work!
- ./config.yml:/data/config.yml:ro
depends_on:
grafana:
condition: service_healthy


volumes:
grafana-storage:
10 changes: 5 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
requests~=2.24.0
grafana_client~=2.0.2
ldap3~=2.6
PyYAML~=5.3.1
pyasn1>=0.4.6
requests~=2.32.3
grafana_client~=4.2.0
ldap3~=2.9.1
PyYAML~=6.0.2
pyasn1>=0.4.6
6 changes: 4 additions & 2 deletions run.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from script.core import startUserSync
import argparse
import logging

from script.core import startUserSync


class DispatchingFormatter:
def __init__(self, formatters, default_formatter):
self._formatters = formatters
Expand All @@ -23,7 +25,7 @@ def setup_logger():
else:
log_format_mut = log_format


logger = logging.getLogger()
while logger.handlers:
logger.handlers.pop()
Expand Down
Empty file added script/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions script/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging

import yaml

logging.basicConfig(level=logging.INFO)
Expand All @@ -15,6 +16,7 @@ def __init__(self, config_path):
GRAFANA_AUTH = ""
GRAFANA_URL = ""
GRAFANA_PROTOCOL = "http"
GRAFANA_ORG_ID = None

LDAP_SERVER_URL = ""
LDAP_PORT = ""
Expand Down Expand Up @@ -49,6 +51,7 @@ def load_config(self, config_path):
self.GRAFANA_URL = config["grafana"]["url"]
if config["grafana"]["protocol"]:
self.GRAFANA_PROTOCOL = config["grafana"]["protocol"]
self.GRAFANA_ORG_ID = config["grafana"]["org_id"] if "org_id" in config["grafana"] else None

self.LDAP_SERVER_URL = config["ldap"]["url"]
self.LDAP_PORT = config["ldap"]["port"]
Expand Down
9 changes: 6 additions & 3 deletions script/grafana.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from grafana_client.client import GrafanaClientError, GrafanaBadInputError
import logging

from grafana_client import GrafanaApi
from grafana_client.client import GrafanaBadInputError, GrafanaClientError

from .config import *
from .helpers import *
import logging

grafana_api = ""
configuration = ""
Expand All @@ -16,7 +18,8 @@ def setup_grafana(config_dict):
grafana_api = GrafanaApi(
auth=configuration.GRAFANA_AUTH,
host=configuration.GRAFANA_URL,
protocol=configuration.GRAFANA_PROTOCOL
protocol=configuration.GRAFANA_PROTOCOL,
organization_id=configuration.GRAFANA_ORG_ID
)


Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
from setuptools import find_packages, setup

setup(
name='grafana-ldap-sync-script',
name='script',
version='1.1.0',
description='Script for syncing LDAP Users & Groups with Grafana Users & Teams',
packages=find_packages(exclude=('tests', 'docs')),
Expand Down

0 comments on commit 26fb21a

Please sign in to comment.