This Puppet module provide tooling for Continuous Delivery (CD) of applications in a Puppet managed environment by leveraging orchestration through Bolt or Choria.
Each application is declared as an application resource. They are identified by a unique title, an application name, an environment name and a path:
application { 'acme':
  application => 'acme',
  environment => 'production',
  path        => '/opt/acme',
}On disc, this will result in this directory hierarchy (assuming 3 deployments are created: d1, d2, d3):
/opt/acme/
|-> current@ -> /opt/acme/d3
|-> d1/
|-> d2/
`-> d3/
Your profile is likely to declare an application resource and additional resources that make it useful and point in the current directory:
class profile::acme {
  application { 'acme':
    application => 'acme',
    environment => 'production',
    path        => '/opt/acme',
  }
  file { '/usr/local/bin/acme-runner':
    ensure => link,
    target => '/opt/acme/current/bin/acme-runner',
  }
  apache::vhost { 'acme.example.com':
    docroot => '/opt/acme/current/public',
  }
}Sometimes, some data must persist through deployments (e.g. uploaded files, logs).  The application module install the mtree gem to manage symbolic links in the deployments directory and have them point to a persistent-data directory if a .mtree file is found at the root of a deployment.
Assuming a .mtree file is added at the root of the previous project containing:
/set type=dir uname=deploy gname=deploy mode=0755
.
	db uname=user
		production.sqlite3 type=file uname=user mode=0640
		..
	..
	config
		database.yml type=file gname=user mode=0640
		..
	..
	log
		production.log type=file gname=user mode=0660
		..
	..
	tmp uname=user gname=user
	..
..
On the next deployment d4, the described hierarchy tree will be created in the persistent-data directory, and all files corresponding to leaves of this tree in the deployment will be removed and replaced by symbolic-links to the corresponding persistent-data file:
/opt/acme/
|-> current@ -> /opt/acme/d4
|-> d1/
|-> d2/
|-> d3/
|-> d4/
|   |-> db/
|   |   `-> production.sqlite3@ -> /opt/acme/persistent-data/db/production.sqlite3
|   |-> config/
|   |   `-> database.yml@ -> /opt/acme/persistent-data/config/database.yml
|   |-> log/
|   |   `-> production.log@ -> /opt/acme/persistent-data/log/production.log
|   `-> tmp@ -> /opt/acme/persistent-data/tmp/
`-> persistent-data/
    |-> db/
    |   `-> production.sqlite3
    |-> config/
    |   `-> database.yml
    |-> log/
    |   `-> production.log
    `-> tmp/
Actions that must be performed before / after deployment and activation can be registered in hooks that can be shared by multiple applications. Before hooks can abort an operation by exiting with a non-null exit code.
As an example, one may want to use the following to deploy Ruby on Rails applications:
application::kind { 'rails':
  before_activate => @(SH),
    #!/bin/sh
    set -e
    RAILS_ENV=$ENVIRONMENT bundle exec rails db:migrate
    | SH
  after_activate  => @(SH),
    #!/bin/sh
    touch tmp/restart.txt
    | SH
}
application { 'website':
  # ...
  kind => 'rails',
}The goal of this module is to allow building custom CD using GitLab and Choria. The misc directory features templates to help setup a CD container. This allows you to rely on GitLab Generic Packages Repository to push the packages you build and deploy them using short lived CI/CD job tokens. The following example build and deploy a new version of an application each time a new tag is pushed:
variables:
  URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${CI_PROJECT_NAME}/${CI_COMMIT_TAG}/artifact.tar.gz"
package:
  stage: package
  only:
    - tags
  script:
    - tar zcf /tmp/artifact.tar.gz --exclude .git .
    - curl --fail --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file /tmp/artifact.tar.gz "${URL}"'
deploy:
  stage: deploy
  only:
    - tags
  needs:
    - package
  image:
    name: registry.example.com/image-builder/mco
  script: 'mco tasks run application::deploy --application=${CI_PROJECT_NAME} --environment=production --url="${URL}" --deployment_name="${CI_COMMIT_TAG}" --header="{\"JOB-TOKEN\": \"${CI_JOB_TOKEN}\"}" -C profile::${CI_PROJECT_NAME}'