puppet_cd::server::service
diff --git a/doc/puppet_classes/puppet_cd_3A_3Amain_3A_3Aconfig.html b/doc/puppet_classes/puppet_cd_3A_3Amain_3A_3Aconfig.html
index f5529a7..00f8d54 100644
--- a/doc/puppet_classes/puppet_cd_3A_3Amain_3A_3Aconfig.html
+++ b/doc/puppet_classes/puppet_cd_3A_3Amain_3A_3Aconfig.html
@@ -109,7 +109,12 @@
11
12
13
-14
+14
+15
+16
+17
+18
+19
# File 'manifests/main/config.pp', line 6
@@ -122,6 +127,11 @@ class puppet_cd::main::config (
if $pt_use_puppetdb == true {
include puppet_cd::puppetdb::service
}
+
+ if $pt_use_r10k == true {
+ include puppet_cd::r10k::install
+ include puppet_cd::r10k::webhook
+ }
}
|
diff --git a/doc/puppet_classes/puppet_cd_3A_3Aparams.html b/doc/puppet_classes/puppet_cd_3A_3Aparams.html
index 5e9ccf1..19a3b91 100644
--- a/doc/puppet_classes/puppet_cd_3A_3Aparams.html
+++ b/doc/puppet_classes/puppet_cd_3A_3Aparams.html
@@ -77,6 +77,10 @@
puppet_cd::main::install
+
puppet_cd::r10k::install
+
+
puppet_cd::r10k::webhook
+
puppet_cd::puppetdb::dirs
puppet_cd::puppetdb::files
@@ -242,6 +246,24 @@
+
+
+ pt_r10k_pkg
+
+
+ (Array)
+
+
+ (defaults to: ['ruby','ruby-devel'])
+
+
+ —
+
+
the packages for r10k to install
+
+
+
+
pt_no_ssl_port
@@ -296,24 +318,6 @@
-
-
- pt_manage_user
-
-
- (Boolean)
-
-
- (defaults to: true)
-
-
- —
-
-
whether to manage the puppet user
-
-
-
-
pt_user
@@ -1376,6 +1380,109 @@
+
+
+ pt_use_r10k
+
+
+ (Boolean)
+
+
+ (defaults to: false)
+
+
+ —
+
+
whether to use r10k service
+
+
+
+
+
+
+ pt_use_r10k_webhook
+
+
+ (Boolean)
+
+
+ (defaults to: false)
+
+
+ —
+
+
whether to use r10k webhook service
+
+
+
+
+
+
+ pt_r10k_remote
+
+
+ (String)
+
+
+ (defaults to: 'git@gitlab.example.net/repo.git')
+
+
+ —
+
+
the remote url for the r10k control repo
+
+
+
+
+
+
+ pt_r10k_prefix
+
+
+ (Boolean)
+
+
+ (defaults to: false)
+
+
+ —
+
+
the r10k prefix. defaults to false
+
+
+
+
+
+
+ pt_r10k_basedir
+
+
+ (String)
+
+
+ (defaults to: '/etc/puppetlabs/code/environments')
+
+
+ —
+
+
the base directory for r10k.yaml
+
+
+
+
+
+
+ pt_manage_user
+
+
+ (Boolean)
+
+
+ (defaults to: true)
+
+
+
+
@@ -1387,11 +1494,6 @@
-81
-82
-83
-84
-85
86
87
88
@@ -1524,10 +1626,32 @@
215
216
217
-218
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
- # File 'manifests/params.pp', line 81
+ # File 'manifests/params.pp', line 86
class puppet_cd::params (
@@ -1540,6 +1664,7 @@ class puppet_cd::params (
String $pt_agent_pkg = 'puppet-agent',
String $pt_server_pkg = 'puppetserver',
Array $pt_db_pkg = ['puppetdb','puppetdb-termini'],
+ Array $pt_r10k_pkg = ['ruby','ruby-devel'],
# user settings
## puppet user
@@ -1583,7 +1708,7 @@ class puppet_cd::params (
String $pt_storeconfigs_backend = 'puppetdb',
String $pt_parser = 'current',
Boolean $pt_cert_revocation = true,
-## puppetdb
+ ## puppetdb
Boolean $pt_use_puppetdb = false,
String $pt_logging_max_file_size = '200MB',
String $pt_logging_max_history = '90',
@@ -1611,8 +1736,19 @@ class puppet_cd::params (
String $pt_repl_port = '8082',
String $pt_repl_host = '127.0.0.1',
+# r10k
+ Boolean $pt_use_r10k = false,
+ Boolean $pt_use_r10k_webhook = false,
+ String $pt_r10k_remote = 'git@gitlab.example.net/repo.git',
+ Boolean $pt_r10k_prefix = false,
+ String $pt_r10k_basedir = '/etc/puppetlabs/code/environments',
+
) {
- $fqdn = $facts['networking']['fqdn']
+# facts
+ $fqdn = $facts['networking']['fqdn']
+ $domain = $facts['networking']['domain']
+ $os_name = $facts['os']['name']
+ $os_release = $facts['os']['release']['major']
# directories
## puppet
@@ -1632,6 +1768,8 @@ class puppet_cd::params (
$pt_puppetdb_ssl = "${pt_puppetdb_main}/ssl"
$pt_puppetdb_log = '/var/log/puppetlabs/puppetdb'
$pt_puppetdb_var_dir = '/opt/puppetlabs/server/data/puppetdb'
+## r10k
+ $pt_r10k_dir = "${pt_main_dir}/r10k"
# files
## puppet
@@ -1641,22 +1779,25 @@ class puppet_cd::params (
$pt_hiera_config = "${pt_puppetdir}/hiera.yaml"
## puppetdb
$pt_bootstrap_conf = "${pt_puppetdb_main}/bootstrap.cfg"
- $pt_bootstrap_erb = 'cd_puppet/puppetdb/bootstrap.cfg.erb'
+ $pt_bootstrap_erb = 'puppet_cd/puppetdb/bootstrap.cfg.erb'
$pt_puppetdb_access_log = "${pt_puppetdb_log}/puppetdb-access"
$pt_request_logging_conf = "${pt_puppetdb_main}/request-logging.xml"
- $pt_request_logging_erb = 'cd_puppet/puppetdb/request_logging.xml.erb'
+ $pt_request_logging_erb = 'puppet_cd/puppetdb/request_logging.xml.erb'
$pt_logback_conf = "${pt_puppetdb_main}/logback.xml"
- $pt_logback_erb = 'cd_puppet/puppetdb/logback.xml.erb'
+ $pt_logback_erb = 'puppet_cd/puppetdb/logback.xml.erb'
$pt_puppetdb_config_ini = "${pt_puppetdb_conf_d}/config.ini"
- $pt_puppetdb_config_erb = 'cd_puppet/puppetdb/config.ini.erb'
+ $pt_puppetdb_config_erb = 'puppet_cd/puppetdb/config.ini.erb'
$pt_puppetdb_database_ini = "${pt_puppetdb_conf_d}/database.ini"
- $pt_puppetdb_database_erb = 'cd_puppet/puppetdb/database.ini.erb'
+ $pt_puppetdb_database_erb = 'puppet_cd/puppetdb/database.ini.erb'
$pt_puppetdb_jetty_ini = "${pt_puppetdb_conf_d}/jetty.ini"
- $pt_puppetdb_jetty_erb = 'cd_puppet/puppetdb/jetty.ini.erb'
+ $pt_puppetdb_jetty_erb = 'puppet_cd/puppetdb/jetty.ini.erb'
$pt_puppetdb_conf_file = "${pt_puppetdir}/puppetdb.conf"
- $pt_puppetdb_conf_erb = 'cd_puppet/puppetdb/puppetdb.conf.erb'
+ $pt_puppetdb_conf_erb = 'puppet_cd/puppetdb/puppetdb.conf.erb'
$pt_puppetdb_repl_ini = "${pt_puppetdb_conf_d}/repl.ini"
- $pt_puppetdb_repl_erb = 'cd_puppet/puppetdb/repl.ini.erb'
+ $pt_puppetdb_repl_erb = 'puppet_cd/puppetdb/repl.ini.erb'
+## r10k
+ $pt_r10k_file = "${pt_r10k_dir}/r10k.yaml"
+ $pt_r10k_erb = 'puppet_cd/r10k/r10k.yaml.erb'
# service
$pt_server_service = 'puppetserver'
diff --git a/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Ainstall.html b/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Ainstall.html
new file mode 100644
index 0000000..53e6fbb
--- /dev/null
+++ b/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Ainstall.html
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+ Puppet Class: puppet_cd::r10k::install
+
+ — Documentation by YARD 0.9.36
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Puppet Class: puppet_cd::r10k::install
+
+
+
+ - Inherits:
+ - puppet_cd::params
+
+
+
+
+ - Defined in:
+ -
+ manifests/r10k/install.pp
+
+
+
+
+ Summary
+ Class manages r10k installation for the puppet_cd module.
+
+ Overview
+
+
+
+ puppet_cd::r10k::install.pp Module name: puppet_cd Author: Arne Teuke (arne_teuke@confdroid)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+ |
+
+ # File 'manifests/r10k/install.pp', line 6
+
+class puppet_cd::r10k::install (
+
+) inherits puppet_cd::params {
+ if ($pt_pm_fqdn == $fqdn) and ($pt_use_r10k == true) {
+ # install required packages
+ package { $pt_r10k_pkg:
+ ensure => $pt_pkg_ensure,
+ before => Package['r10k'],
+ }
+
+ # install r10k via gem
+ package { 'r10k':
+ ensure => $pt_pkg_ensure,
+ provider => gem,
+ }
+
+ # configure r10k.yaml
+ file { $pt_r10k_file:
+ ensure => file,
+ owner => 'root',
+ group => 'root',
+ mode => '0440',
+ selrange => s0,
+ selrole => object_r,
+ seltype => puppet_etc_t,
+ seluser => unconfined_u,
+ content => template($pt_r10k_erb),
+ }
+ }
+}
+ |
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Awebhook.html b/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Awebhook.html
new file mode 100644
index 0000000..632e8d4
--- /dev/null
+++ b/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Awebhook.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+ Puppet Class: puppet_cd::r10k::webhook
+
+ — Documentation by YARD 0.9.36
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Puppet Class: puppet_cd::r10k::webhook
+
+
+
+ - Inherits:
+ - puppet_cd::params
+
+
+
+
+ - Defined in:
+ -
+ manifests/r10k/webhook.pp
+
+
+
+
+ Summary
+ Class manages r10k webhook settings for the puppet_cd module.
+
+ Overview
+
+
+
+ puppet_cd::r10k::webhook.pp Module name: puppet_cd Author: Arne Teuke (arne_teuke@confdroid)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6
+7
+8
+9
+10
+ |
+
+ # File 'manifests/r10k/webhook.pp', line 6
+
+class puppet_cd::r10k::webhook (
+
+) inherits puppet_cd::params {
+
+}
+ |
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/manifests/main/config.pp b/manifests/main/config.pp
index 234343e..69027ae 100644
--- a/manifests/main/config.pp
+++ b/manifests/main/config.pp
@@ -11,4 +11,9 @@ class puppet_cd::main::config (
if $pt_use_puppetdb == true {
include puppet_cd::puppetdb::service
}
+
+ if $pt_use_r10k == true {
+ include puppet_cd::r10k::install
+ include puppet_cd::r10k::webhook
+ }
}
diff --git a/manifests/params.pp b/manifests/params.pp
index 0c27473..6169c7f 100644
--- a/manifests/params.pp
+++ b/manifests/params.pp
@@ -10,10 +10,10 @@
# @param [String] pt_agent_pkg the packages for agents to install
# @param [String] pt_server_pkg the server packages to install
# @param [Array] pt_db_pkg the packages for puppetdb
+# @param [Array] pt_r10k_pkg the packages for r10k to install
# @param [String] pt_no_ssl_port non-ssl port number for puppetdb
# @param [String] pt_ssl_port ssl port for puppetdb
# @param [Boolean] pt_use_ssl_only whether to use ssl only.
-# @param [Boolean] pt_manage_user whether to manage the puppet user
# @param [String] pt_user the puppet user
# @param [String] pt_user_comment the user comment
# @param [String] pt_user_home the user home
@@ -77,6 +77,11 @@
# @param [Boolean] pt_enable_repl whether to allow puppetdb replication
# @param [String] pt_repl_port the replication port
# @param [String] pt_repl_host the replication host
+# @param [Boolean] pt_use_r10k whether to use r10k service
+# @param [Boolean] pt_use_r10k_webhook whether to use r10k webhook service
+# @param [String] pt_r10k_remote the remote url for the r10k control repo
+# @param [Boolean] pt_r10k_prefix the r10k prefix. defaults to false
+# @param [String] pt_r10k_basedir the base directory for r10k.yaml
###############################################################################
class puppet_cd::params (
@@ -89,6 +94,7 @@ class puppet_cd::params (
String $pt_agent_pkg = 'puppet-agent',
String $pt_server_pkg = 'puppetserver',
Array $pt_db_pkg = ['puppetdb','puppetdb-termini'],
+ Array $pt_r10k_pkg = ['ruby','ruby-devel'],
# user settings
## puppet user
@@ -132,7 +138,7 @@ class puppet_cd::params (
String $pt_storeconfigs_backend = 'puppetdb',
String $pt_parser = 'current',
Boolean $pt_cert_revocation = true,
-## puppetdb
+ ## puppetdb
Boolean $pt_use_puppetdb = false,
String $pt_logging_max_file_size = '200MB',
String $pt_logging_max_history = '90',
@@ -160,8 +166,19 @@ class puppet_cd::params (
String $pt_repl_port = '8082',
String $pt_repl_host = '127.0.0.1',
+# r10k
+ Boolean $pt_use_r10k = false,
+ Boolean $pt_use_r10k_webhook = false,
+ String $pt_r10k_remote = 'git@gitlab.example.net/repo.git',
+ Boolean $pt_r10k_prefix = false,
+ String $pt_r10k_basedir = '/etc/puppetlabs/code/environments',
+
) {
- $fqdn = $facts['networking']['fqdn']
+# facts
+ $fqdn = $facts['networking']['fqdn']
+ $domain = $facts['networking']['domain']
+ $os_name = $facts['os']['name']
+ $os_release = $facts['os']['release']['major']
# directories
## puppet
@@ -181,6 +198,8 @@ class puppet_cd::params (
$pt_puppetdb_ssl = "${pt_puppetdb_main}/ssl"
$pt_puppetdb_log = '/var/log/puppetlabs/puppetdb'
$pt_puppetdb_var_dir = '/opt/puppetlabs/server/data/puppetdb'
+## r10k
+ $pt_r10k_dir = "${pt_main_dir}/r10k"
# files
## puppet
@@ -190,22 +209,25 @@ class puppet_cd::params (
$pt_hiera_config = "${pt_puppetdir}/hiera.yaml"
## puppetdb
$pt_bootstrap_conf = "${pt_puppetdb_main}/bootstrap.cfg"
- $pt_bootstrap_erb = 'cd_puppet/puppetdb/bootstrap.cfg.erb'
+ $pt_bootstrap_erb = 'puppet_cd/puppetdb/bootstrap.cfg.erb'
$pt_puppetdb_access_log = "${pt_puppetdb_log}/puppetdb-access"
$pt_request_logging_conf = "${pt_puppetdb_main}/request-logging.xml"
- $pt_request_logging_erb = 'cd_puppet/puppetdb/request_logging.xml.erb'
+ $pt_request_logging_erb = 'puppet_cd/puppetdb/request_logging.xml.erb'
$pt_logback_conf = "${pt_puppetdb_main}/logback.xml"
- $pt_logback_erb = 'cd_puppet/puppetdb/logback.xml.erb'
+ $pt_logback_erb = 'puppet_cd/puppetdb/logback.xml.erb'
$pt_puppetdb_config_ini = "${pt_puppetdb_conf_d}/config.ini"
- $pt_puppetdb_config_erb = 'cd_puppet/puppetdb/config.ini.erb'
+ $pt_puppetdb_config_erb = 'puppet_cd/puppetdb/config.ini.erb'
$pt_puppetdb_database_ini = "${pt_puppetdb_conf_d}/database.ini"
- $pt_puppetdb_database_erb = 'cd_puppet/puppetdb/database.ini.erb'
+ $pt_puppetdb_database_erb = 'puppet_cd/puppetdb/database.ini.erb'
$pt_puppetdb_jetty_ini = "${pt_puppetdb_conf_d}/jetty.ini"
- $pt_puppetdb_jetty_erb = 'cd_puppet/puppetdb/jetty.ini.erb'
+ $pt_puppetdb_jetty_erb = 'puppet_cd/puppetdb/jetty.ini.erb'
$pt_puppetdb_conf_file = "${pt_puppetdir}/puppetdb.conf"
- $pt_puppetdb_conf_erb = 'cd_puppet/puppetdb/puppetdb.conf.erb'
+ $pt_puppetdb_conf_erb = 'puppet_cd/puppetdb/puppetdb.conf.erb'
$pt_puppetdb_repl_ini = "${pt_puppetdb_conf_d}/repl.ini"
- $pt_puppetdb_repl_erb = 'cd_puppet/puppetdb/repl.ini.erb'
+ $pt_puppetdb_repl_erb = 'puppet_cd/puppetdb/repl.ini.erb'
+## r10k
+ $pt_r10k_file = "${pt_r10k_dir}/r10k.yaml"
+ $pt_r10k_erb = 'puppet_cd/r10k/r10k.yaml.erb'
# service
$pt_server_service = 'puppetserver'
diff --git a/manifests/r10k/install.pp b/manifests/r10k/install.pp
new file mode 100644
index 0000000..8ce10c7
--- /dev/null
+++ b/manifests/r10k/install.pp
@@ -0,0 +1,35 @@
+## puppet_cd::r10k::install.pp
+# Module name: puppet_cd
+# Author: Arne Teuke (arne_teuke@confdroid)
+# @summary Class manages r10k installation for the puppet_cd module.
+###############################################################################
+class puppet_cd::r10k::install (
+
+) inherits puppet_cd::params {
+ if ($pt_pm_fqdn == $fqdn) and ($pt_use_r10k == true) {
+ # install required packages
+ package { $pt_r10k_pkg:
+ ensure => $pt_pkg_ensure,
+ before => Package['r10k'],
+ }
+
+ # install r10k via gem
+ package { 'r10k':
+ ensure => $pt_pkg_ensure,
+ provider => gem,
+ }
+
+ # configure r10k.yaml
+ file { $pt_r10k_file:
+ ensure => file,
+ owner => 'root',
+ group => 'root',
+ mode => '0440',
+ selrange => s0,
+ selrole => object_r,
+ seltype => puppet_etc_t,
+ seluser => unconfined_u,
+ content => template($pt_r10k_erb),
+ }
+ }
+}
diff --git a/manifests/r10k/webhook.pp b/manifests/r10k/webhook.pp
new file mode 100644
index 0000000..9ace78f
--- /dev/null
+++ b/manifests/r10k/webhook.pp
@@ -0,0 +1,10 @@
+## puppet_cd::r10k::webhook.pp
+# Module name: puppet_cd
+# Author: Arne Teuke (arne_teuke@confdroid)
+# @summary Class manages r10k webhook settings for the puppet_cd module.
+###############################################################################
+class puppet_cd::r10k::webhook (
+
+) inherits puppet_cd::params {
+
+}
diff --git a/templates/puppetdb/logback.xml.erb b/templates/puppetdb/logback.xml.erb
old mode 100755
new mode 100644
diff --git a/templates/r10k/r10k.yaml.erb b/templates/r10k/r10k.yaml.erb
new file mode 100644
index 0000000..9b0b77d
--- /dev/null
+++ b/templates/r10k/r10k.yaml.erb
@@ -0,0 +1,7 @@
+:cachedir: /var/cache/r10k
+
+:sources:
+ :puppet:
+ remote: <%= @pt_r10k_remote %>
+ prefix: <&= @pt_r10k_prefix %>
+ basedir: '<%= @pt_r10k_basedir %>'
diff --git a/templates/r10k/requirements.txt.erb b/templates/r10k/requirements.txt.erb
new file mode 100644
index 0000000..8ca4007
--- /dev/null
+++ b/templates/r10k/requirements.txt.erb
@@ -0,0 +1,5 @@
+pytest==7.4.3
+pytest-cov==4.1.0
+httpx==0.25.2
+flake8==6.1.0
+pylint==3.0.1
\ No newline at end of file
diff --git a/templates/r10k/webhook.py.erb b/templates/r10k/webhook.py.erb
new file mode 100644
index 0000000..c5f7862
--- /dev/null
+++ b/templates/r10k/webhook.py.erb
@@ -0,0 +1,198 @@
+#!/usr/bin/env python3
+"""
+Custom r10k Webhook Server for Puppet Control Repo
+"""
+
+from datetime import datetime
+import os
+import subprocess
+import logging
+import hmac
+import hashlib
+
+from fastapi import FastAPI, Request, HTTPException, BackgroundTasks
+from fastapi.responses import JSONResponse
+import uvicorn
+from pydantic import BaseModel
+
+
+# Configure logging
+logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s',
+ handlers=[
+ logging.FileHandler('/var/log/r10k-webhook.log'),
+ logging.StreamHandler()
+ ]
+)
+logger = logging.getLogger(__name__)
+
+
+app = FastAPI(title="r10k Webhook Server")
+
+
+class WebhookPayload(BaseModel):
+ """Data model for webhook payload"""
+ ref: str
+ project: dict
+ commits: list
+
+
+def run_r10k_deploy() -> bool:
+ """Run r10k deploy command"""
+ try:
+ cmd = [
+ '/usr/bin/r10k', 'deploy',
+ '-v',
+ '-c', '/etc/puppetlabs/r10k/r10k.conf'
+ ]
+
+ logger.info("Starting r10k deploy...")
+ result = subprocess.run(
+ cmd,
+ capture_output=True,
+ text=True,
+ check=True
+ )
+
+ logger.info("r10k deploy successful!")
+ logger.debug("r10k stdout: %s", result.stdout)
+ if result.stderr:
+ logger.warning("r10k stderr: %s", result.stderr)
+ return True
+
+ except subprocess.CalledProcessError as e:
+ logger.error("r10k deploy failed: %s", e)
+ logger.error("stdout: %s", e.stdout)
+ logger.error("stderr: %s", e.stderr)
+ return False
+ except FileNotFoundError:
+ logger.error("r10k binary not found")
+ return False
+ except PermissionError:
+ logger.error("Permission denied running r10k")
+ return False
+
+
+def validate_signature(payload: bytes, signature: str, secret: str) -> bool:
+ """Validate webhook signature"""
+ if not secret:
+ return True
+
+ expected = hmac.new(
+ secret.encode(),
+ payload,
+ hashlib.sha256
+ ).hexdigest()
+
+ if signature.startswith('sha256='):
+ return hmac.compare_digest(signature, f'sha256={expected}')
+
+ return hmac.compare_digest(signature, expected)
+
+
+@app.post("/webhook")
+async def webhook_handler(
+ request: Request,
+ background_tasks: BackgroundTasks
+):
+ """Handle incoming webhook requests"""
+
+ body = await request.body()
+ headers = dict(request.headers)
+ event_type = headers.get(
+ 'x-gitlab-event',
+ headers.get('x-github-event', 'unknown')
+ )
+ signature = headers.get(
+ 'x-gitlab-token',
+ headers.get('x-hub-signature-256', '')
+ )
+
+ print(
+ f"DEBUG: Received webhook: event_type={event_type}, "
+ f"headers={headers}"
+ )
+ logger.info(
+ "Received webhook: event_type=%s, headers=%s",
+ event_type,
+ headers
+ )
+
+ webhook_secret = os.getenv('R10K_WEBHOOK_SECRET', '')
+ is_valid = validate_signature(body, signature, webhook_secret)
+ if webhook_secret and not is_valid:
+ logger.warning("Invalid webhook signature")
+ raise HTTPException(status_code=403, detail="Invalid signature")
+
+ try:
+ payload = await request.json()
+ ref = payload.get('ref', '')
+ branch = ref.split('/')[-1] if '/' in ref else ref
+ print(
+ f"DEBUG: Parsed payload: ref={ref}, "
+ f"branch={branch}"
+ )
+ logger.info("Parsed payload: ref=%s, branch=%s", ref, branch)
+
+ if branch not in ['main', 'master']:
+ logger.info("Ignoring non-main branch: %s", branch)
+ return JSONResponse({
+ "status": "ignored",
+ "branch": branch
+ })
+
+ # Match GitLab event types explicitly
+ valid_events = [
+ 'push hook', 'merge request hook',
+ 'push', 'Push', 'Push Hook'
+ ]
+ normalized_event = event_type.lower().strip()
+ print(f"DEBUG: Normalized event: {normalized_event}")
+ logger.info("Normalized event: %s", normalized_event)
+ if normalized_event in valid_events:
+ logger.info("Triggering r10k for %s on %s", event_type, branch)
+ background_tasks.add_task(run_r10k_deploy)
+ return JSONResponse({
+ "status": "accepted",
+ "message": "r10k deploy triggered",
+ "timestamp": datetime.utcnow().isoformat(),
+ "branch": branch
+ })
+
+ logger.info("Ignoring event type: %s", event_type)
+ return JSONResponse({
+ "status": "ignored",
+ "event": event_type
+ })
+
+ except ValueError as e:
+ logger.error("Webhook processing error: %s", e)
+ raise HTTPException(
+ status_code=400,
+ detail="Invalid payload"
+ ) from e
+
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ result = subprocess.run(
+ ['r10k', '--version'],
+ capture_output=True,
+ text=True,
+ check=True
+ )
+ return {
+ "status": "healthy",
+ "r10k_version": result.stdout.strip()
+ }
+
+
+if __name__ == "__main__":
+ uvicorn.run(
+ "webhook_server:app",
+ host="0.0.0.0",
+ port=8080,
+ log_level="info"
+ )
|