diff --git a/doc/puppet_classes/puppet_cd_3A_3Aparams.html b/doc/puppet_classes/puppet_cd_3A_3Aparams.html index 0b36cf0..0df5e7c 100644 --- a/doc/puppet_classes/puppet_cd_3A_3Aparams.html +++ b/doc/puppet_classes/puppet_cd_3A_3Aparams.html @@ -1670,17 +1670,7 @@ 238 239 240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 +241
# File 'manifests/params.pp', line 88
@@ -1801,9 +1791,6 @@ 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"
-  $pt_r10k_webhook_dir              = '/etc/r10k-webhook'
 
 # files
 ## puppet
@@ -1830,14 +1817,7 @@ class puppet_cd::params (
   $pt_puppetdb_repl_ini             = "${pt_puppetdb_conf_d}/repl.ini"
   $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'
-  $pt_r10k_webhook_file             = "${pt_r10k_webhook_dir}/webhook_server.py"
-  $pt_r10k_webhook_erb              = 'puppet_cd/r10k/webhook.py.erb'
-  $pt_r10k_req_file                 = "${pt_r10k_webhook_dir}/requirements.txt"
-  $pt_r10k_req_erb                  = 'puppet_cd/r10k/requirements.txt.erb'
-  $pt_r10k_wh_config_file           =  "${pt_r10k_webhook_dir}/config.json"
-  $pt_r10k_wh_config_erb            = 'puppet_cd/r10k/r10k_webhook_config.erb'
+  $pt_r10k_hook_file                = '/usr/local/bin/webhook'
 
 # service
   $pt_server_service                = 'puppetserver'
diff --git a/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Awebhook.html b/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Awebhook.html
index d51ba97..a149208 100644
--- a/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Awebhook.html
+++ b/doc/puppet_classes/puppet_cd_3A_3Ar10k_3A_3Awebhook.html
@@ -125,55 +125,7 @@
 27
 28
 29
-30
-31
-32
-33
-34
-35
-36
-37
-38
-39
-40
-41
-42
-43
-44
-45
-46
-47
-48
-49
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64
-65
-66
-67
-68
-69
-70
-71
-72
-73
-74
-75
-76
-77
-78
+30
# File 'manifests/r10k/webhook.pp', line 6
@@ -182,73 +134,25 @@ class puppet_cd::r10k::webhook (
 
 ) inherits puppet_cd::params {
   if ($pt_pm_fqdn == $fqdn) and ($pt_use_r10k_webhook == true) {
-    # install packages
-    package { $pt_r10k_webhook_pkg:
-      ensure => $pt_pkg_ensure,
-    }
-
-    # create the webhook dir
-    file { $pt_r10k_webhook_dir:
-      ensure   => directory,
+    # create the webhook binary
+    file { $pt_r10k_hook_file:
+      ensure   => file,
       owner    => 'root',
       group    => 'root',
       mode     => '0755',
       selrange => s0,
       selrole  => object_r,
-      seltype  => etc_t,
-      seluser  => system_u,
+      seltype  => bin_t,
+      seluser  => unconfined_u,
+      source   => 'puppet:///module/puppet_cd/webhook',
     }
 
-    # create the requirements file
-    file { $pt_r10k_req_file:
-      ensure   => file,
-      owner    => 'puppet',
-      group    => 'puppet',
-      mode     => '0644',
-      selrange => s0,
-      selrole  => object_r,
-      seltype  => etc_t,
-      seluser  => system_u,
-      content  => template($pt_r10k_req_erb),
-    }
-
-    # create the webhook config file
-    file { $pt_r10k_wh_config_file:
-      ensure   => file,
-      owner    => 'root',
-      group    => 'root',
-      mode     => '0644',
-      selrange => s0,
-      selrole  => object_r,
-      seltype  => etc_t,
-      seluser  => system_u,
-      content  => template($pt_r10k_wh_config_erb),
-      require  => File[$pt_r10k_webhook_dir],
-    }
-
-
-    # install pip dependencies
-    exec { 'pip_install_r10k_webhook':
-      command => 'pip3 install --user -r /opt/r10k-webhook/requirements.txt',
-      user    => 'puppet',
-      require => [Package[$pt_r10k_webhook_pkg],File[$pt_r10k_req_file]],
-      unless  => 'pip3 show fastapi',  # Idempotent check
-    }
-
-    # establish exec systemd reload
-    exec { 'systemctl_daemon_reload':
-      command     => 'systemctl daemon-reload',
-      path        => ['/bin', '/usr/bin'],
-      require     => Exec['pip_install_r10k_webhook'],
-      refreshonly => true,
-    }
-
-    # manage service
-    service { 'r10k-webhook':
-      ensure    => 'running',
-      enable    => true,
-      subscribe => File[$pt_r10k_wh_config_file],
-    }
+#    # manage service
+#    service { 'r10k-webhook':
+#      ensure    => 'running',
+#      enable    => true,
+#      subscribe => File[$pt_r10k_wh_config_file],
+#    }
   }
 }
diff --git a/files/webhook b/files/webhook new file mode 100644 index 0000000..024455b Binary files /dev/null and b/files/webhook differ diff --git a/manifests/params.pp b/manifests/params.pp index de0641c..eca724d 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -201,9 +201,6 @@ 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" - $pt_r10k_webhook_dir = '/etc/r10k-webhook' # files ## puppet @@ -230,14 +227,7 @@ class puppet_cd::params ( $pt_puppetdb_repl_ini = "${pt_puppetdb_conf_d}/repl.ini" $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' - $pt_r10k_webhook_file = "${pt_r10k_webhook_dir}/webhook_server.py" - $pt_r10k_webhook_erb = 'puppet_cd/r10k/webhook.py.erb' - $pt_r10k_req_file = "${pt_r10k_webhook_dir}/requirements.txt" - $pt_r10k_req_erb = 'puppet_cd/r10k/requirements.txt.erb' - $pt_r10k_wh_config_file = "${pt_r10k_webhook_dir}/config.json" - $pt_r10k_wh_config_erb = 'puppet_cd/r10k/r10k_webhook_config.erb' + $pt_r10k_hook_file = '/usr/local/bin/webhook' # service $pt_server_service = 'puppetserver' diff --git a/manifests/r10k/webhook.pp b/manifests/r10k/webhook.pp index 3a5e9ef..41af8df 100644 --- a/manifests/r10k/webhook.pp +++ b/manifests/r10k/webhook.pp @@ -7,72 +7,24 @@ class puppet_cd::r10k::webhook ( ) inherits puppet_cd::params { if ($pt_pm_fqdn == $fqdn) and ($pt_use_r10k_webhook == true) { - # install packages - package { $pt_r10k_webhook_pkg: - ensure => $pt_pkg_ensure, - } - - # create the webhook dir - file { $pt_r10k_webhook_dir: - ensure => directory, + # create the webhook binary + file { $pt_r10k_hook_file: + ensure => file, owner => 'root', group => 'root', mode => '0755', selrange => s0, selrole => object_r, - seltype => etc_t, - seluser => system_u, + seltype => bin_t, + seluser => unconfined_u, + source => 'puppet:///module/puppet_cd/webhook', } - # create the requirements file - file { $pt_r10k_req_file: - ensure => file, - owner => 'puppet', - group => 'puppet', - mode => '0644', - selrange => s0, - selrole => object_r, - seltype => etc_t, - seluser => system_u, - content => template($pt_r10k_req_erb), - } - - # create the webhook config file - file { $pt_r10k_wh_config_file: - ensure => file, - owner => 'root', - group => 'root', - mode => '0644', - selrange => s0, - selrole => object_r, - seltype => etc_t, - seluser => system_u, - content => template($pt_r10k_wh_config_erb), - require => File[$pt_r10k_webhook_dir], - } - - - # install pip dependencies - exec { 'pip_install_r10k_webhook': - command => 'pip3 install --user -r /opt/r10k-webhook/requirements.txt', - user => 'puppet', - require => [Package[$pt_r10k_webhook_pkg],File[$pt_r10k_req_file]], - unless => 'pip3 show fastapi', # Idempotent check - } - - # establish exec systemd reload - exec { 'systemctl_daemon_reload': - command => 'systemctl daemon-reload', - path => ['/bin', '/usr/bin'], - require => Exec['pip_install_r10k_webhook'], - refreshonly => true, - } - - # manage service - service { 'r10k-webhook': - ensure => 'running', - enable => true, - subscribe => File[$pt_r10k_wh_config_file], - } +# # manage service +# service { 'r10k-webhook': +# ensure => 'running', +# enable => true, +# subscribe => File[$pt_r10k_wh_config_file], +# } } } diff --git a/templates/r10k/requirements.txt.erb b/templates/r10k/requirements.txt.erb deleted file mode 100644 index 4d50e5b..0000000 --- a/templates/r10k/requirements.txt.erb +++ /dev/null @@ -1,4 +0,0 @@ -#fastapi==0.115.0 -#uvicorn==0.30.6 -#pydantic==2.8.2 -r10k-webhook \ No newline at end of file diff --git a/templates/r10k/webhook.py.erb b/templates/r10k/webhook.py.erb deleted file mode 100644 index c5f7862..0000000 --- a/templates/r10k/webhook.py.erb +++ /dev/null @@ -1,198 +0,0 @@ -#!/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" - )