-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from chocolatey/testing-actual
Initial Playbooks, Roles, Etc
- Loading branch information
Showing
37 changed files
with
4,687 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "Ansible", | ||
"dockerFile": "dockerfile", | ||
// "mounts": [ | ||
// "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" | ||
// ], | ||
"forwardPorts": [], | ||
"customizations": { | ||
"vscode": { | ||
"extensions": [ | ||
"redhat.ansible" | ||
] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#------------------------------------------------------------------------------------------------------------- | ||
# Copyright (c) Microsoft Corporation. All rights reserved. | ||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. | ||
#------------------------------------------------------------------------------------------------------------- | ||
FROM ubuntu:latest | ||
# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser" | ||
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs | ||
# will be updated to match your local UID/GID (when using the dockerFile property). | ||
# See https://aka.ms/vscode-remote/containers/non-root-user for details. | ||
ARG USERNAME=vscode | ||
ARG USER_UID=1000 | ||
ARG USER_GID=$USER_UID | ||
|
||
# To ensure filesystem encoding is proper, add these. | ||
# See: https://github.com/pypa/pip/issues/10219#issuecomment-887337037 | ||
ENV LANG C.UTF-8 | ||
ENV LC_ALL C.UTF-8 | ||
|
||
# To make it easier for build and release pipelines to run apt-get, | ||
# configure apt to not require confirmation (assume the -y argument by default) | ||
ENV DEBIAN_FRONTEND noninteractive | ||
RUN echo "APT::Get::Assume-Yes \"true\";" > /etc/apt/apt.conf.d/90assumeyes | ||
|
||
RUN apt-get update \ | ||
&& apt-get install -y --no-install-recommends \ | ||
apt-utils \ | ||
software-properties-common \ | ||
build-essential \ | ||
jq \ | ||
git \ | ||
python3 \ | ||
python3-dev \ | ||
python3-pip && \ | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
RUN add-apt-repository universe \ | ||
&& add-apt-repository multiverse \ | ||
&& apt update | ||
|
||
RUN pip3 install --upgrade \ | ||
setuptools \ | ||
pip | ||
|
||
ADD requirements.txt /requirements.txt | ||
|
||
RUN pip3 install --upgrade -r /requirements.txt | ||
|
||
RUN ln -s /usr/bin/python3 /usr/bin/python \ | ||
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user. | ||
&& groupadd --gid $USER_GID $USERNAME \ | ||
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \ | ||
# [Optional] Add sudo support for the non-root user | ||
&& apt-get install sudo \ | ||
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\ | ||
&& chmod 0440 /etc/sudoers.d/$USERNAME \ | ||
# | ||
# Clean up | ||
&& apt-get autoremove \ | ||
&& apt-get clean \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
|
||
RUN ansible-galaxy collection install chocolatey.chocolatey --upgrade |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
ansible>=2.8.0 | ||
pywinrm>=0.2.2 | ||
pip>=19.1 | ||
psutil | ||
netaddr | ||
ansible-lint | ||
pylint | ||
jsonschema | ||
molecule | ||
jmespath | ||
dnspython |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/credentials | ||
/files/download/ | ||
/files/*.nupkg | ||
/files/*.zip | ||
__pycache__ | ||
chocolatey.license.xml | ||
*.pfx | ||
*.nupkg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"ansible.python.interpreterPath": "/bin/python3" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
<# | ||
.Synopsis | ||
Prepares the repository for an offline deployment. | ||
.Description | ||
These playbooks can be run from a network without access to the internet, | ||
but it needs to prepare packages to be run offline. | ||
This script downloads and internalizes packages for such usage. | ||
.Notes | ||
This must be run on a Windows system with access to the internet because | ||
it uses Chocolatey for Business' Package Internalizer. | ||
.Notes | ||
Instead of using this script, you can internalize all required packages manually, | ||
zip them, and drop them in the files directory as shown below. | ||
.Example | ||
.\OfflineInstallPreparation.ps1 -LicensePath C:\ProgramData\chocolatey\license\chocolatey.license.xml | ||
#> | ||
[CmdletBinding()] | ||
param( | ||
[ValidateScript({ | ||
if (-not (Test-Path (Convert-Path $_))) { | ||
throw "License file does not exist at '$($_)'. Please provide a valid -LicensePath" | ||
} | ||
$true | ||
})] | ||
[string]$LicensePath = "C:\ProgramData\chocolatey\license\chocolatey.license.xml", | ||
|
||
[ValidateScript({ | ||
if (-not (Test-Path (Convert-Path $_))) { | ||
throw "Certificate file does not exist at '$($_)'. Please provide a valid -CertificatePath" | ||
} | ||
$true | ||
})] | ||
[Parameter(Mandatory)] | ||
[string]$CertificatePath, | ||
|
||
[Parameter(Mandatory)] | ||
[securestring]$CertificatePassword, | ||
|
||
[string]$WorkingDirectory = $(Join-Path $env:Temp "choco-offline") | ||
) | ||
$ErrorActionPreference = "Stop" | ||
$ProgressPreference = "SilentlyContinue" | ||
$LicensePath = Convert-Path $LicensePath | ||
$CertificatePath = Convert-Path $CertificatePath | ||
|
||
# Validate License | ||
try { | ||
[xml]$License = Get-Content $LicensePath | ||
$Expiry = Get-Date $License.license.expiration | ||
if (-not $Expiry -or $Expiry -lt (Get-Date)) {throw} | ||
} catch { | ||
throw "License '$($LicensePath)' is not valid.$(if ($Expiry) {" It expired at '$($Expiry)'."})" | ||
} | ||
|
||
# Validate Certificate and Password | ||
try { | ||
$null = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new( | ||
$CertificatePath, | ||
$CertificatePassword, | ||
"EphemeralKeySet" | ||
) | ||
} catch { | ||
throw "Certificate '$($CertificatePath)' failed to import with the provided CertificatePassword. Please ensure the Certificate Path and Password are correct." | ||
} | ||
|
||
if (-not (Get-Command choco.exe)) { | ||
Get-Content $PSScriptRoot\templates\ChocolateyInstall.ps1.j2 | Invoke-Expression | ||
} | ||
|
||
# Initialize environment, ensure Chocolatey For Business, etc. | ||
$Licensed = ($($(choco)[0] -match "^Chocolatey (?<Version>\S+)\s*(?<LicenseType>Business)?$") -and $Matches.LicenseType) | ||
$InstalledLicensePath = "$env:ChocolateyInstall\license\chocolatey.license.xml" | ||
if (-not $Licensed) { | ||
if (-not (Test-Path $InstalledLicensePath)) { | ||
if (-not (Test-Path $env:ChocolateyInstall\license)) { | ||
$null = New-Item $env:ChocolateyInstall\license -ItemType Directory | ||
} | ||
Copy-Item $LicensePath $InstalledLicensePath -Force | ||
} | ||
choco install chocolatey.extension --source https://licensedpackages.chocolatey.org/api/v2/ --confirm | ||
} | ||
|
||
# Download each set of packages to the output directories | ||
$PackageWorkingDirectory = Join-Path $WorkingDirectory "Packages" | ||
if (-not (Test-Path $PackageWorkingDirectory)) { | ||
$null = New-Item -Path $PackageWorkingDirectory -ItemType Directory -Force | ||
} | ||
foreach ($Package in (Get-Content $PSScriptRoot\files\chocolatey.json | ConvertFrom-Json).packages) { | ||
$ChocoArgs = @( | ||
"download", "$($Package.Name)" | ||
"--output-directory", $PackageWorkingDirectory | ||
) | ||
$ChocoArgs += switch ($Package.Keys) { | ||
"Version" { "--version", $Package.Version } | ||
"Args" { $Package.Args } | ||
} | ||
if ($Package.Internalize -or $Package.PSObject.Properties.Name -notcontains "Internalize") { | ||
$ChocoArgs += "--internalize" # Default to internalizing | ||
} | ||
|
||
try { | ||
if (-not (Test-Path "$($PackageWorkingDirectory)\$($Package.Name)*.nupkg") -and -not (Test-Path "$PSScriptRoot\files\$($Package.Name)*.nupkg")) { | ||
Write-Verbose "Downloading '$($Package.Name)'" | ||
$Output = choco @ChocoArgs | ||
if ($LASTEXITCODE -ne 0) { | ||
$Output | ||
} | ||
} | ||
} catch { | ||
throw $_ | ||
} | ||
} | ||
Move-Item -Path $PackageWorkingDirectory\*.nupkg -Destination $PSScriptRoot\files\ | ||
|
||
# Jenkins Plugins | ||
$PluginsWorkingDirectory = Join-Path $WorkingDirectory "JenkinsPlugins" | ||
if (-not (Test-Path $PluginsWorkingDirectory)) { | ||
$null = New-Item -Path $PluginsWorkingDirectory -ItemType Directory -Force | ||
} | ||
$ProgressPreference = "Ignore" | ||
foreach ($Plugin in (Get-Content $PSScriptRoot\files\jenkins.json | ConvertFrom-Json).plugins) { | ||
$RestArgs = @{ | ||
Uri = "https://updates.jenkins-ci.org/latest/$($Plugin.Name).hpi" | ||
OutFile = Join-Path $PluginsWorkingDirectory "$($Plugin.Name).hpi" | ||
} | ||
if ($Plugin.Version -and $Plugin.Version -ne 'latest') { | ||
$RestArgs.Uri = "https://updates.jenkins-ci.org/download/plugins/$($Plugin.Name)/$($Plugin.Version)/$($Plugin.Name).hpi" | ||
} | ||
if (-not (Test-Path $RestArgs.OutFile)) { | ||
Invoke-WebRequest @RestArgs -UseBasicParsing | ||
} | ||
} | ||
Compress-Archive -Path $PluginsWorkingDirectory\* -Destination $PSScriptRoot\files\JenkinsPlugins.zip -Force | ||
|
||
# License and Certificate | ||
Copy-Item -Path (Convert-Path $LicensePath) -Destination $PSScriptRoot\files\chocolatey.license.xml | ||
Copy-Item -Path (Convert-Path $CertificatePath) -Destination $PSScriptRoot\files\certificate.pfx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,75 @@ | ||
# repository-template | ||
# Chocolatey for Business Ansible Environment | ||
|
||
## Deployment | ||
|
||
To deploy the Chocolatey for Business Ansible Environment, first, clone the repository to your chosen Ansible environment, make the following modifications, and deploy the `c4b-environment.yml` playbook. | ||
|
||
Create hosts. Depending on your chosen configuration, you may not need to create all of them: | ||
|
||
| Group | Purpose | | ||
| --------------- | ---------------------------------------------------------------------------- | | ||
| ccm_server | Runs the Chocolatey Central Management service and administration interface. | | ||
| nexus_server | Runs Sonatype Nexus Repository, to store and distribute packages. | | ||
| jenkins_server | Runs Jenkins, to run jobs to updating packages in the Nexus repository. | | ||
| database_server | Runs SQL Server Express, to store information from the CCM service. | | ||
|
||
By default, any non-specified service will be installed on the ccm_server host. | ||
|
||
You should provide the following arguments: | ||
|
||
| Argument | Purpose | | ||
| -------------------------- | -------------------------------------------------- | | ||
| license_path | Your Chocolatey for Business license file. | | ||
| certificate_path | The PFX certificate to use for all HTTPS services. | | ||
| certificate_password | The password for the PFX certificate. | | ||
|
||
Finally, you can deploy the playbook as follows (using the example hosts file): | ||
|
||
`ansible-playbook ./c4b-environment.yml -i ./hosts.yml` | ||
|
||
You will be prompted for any values you have not provided in `--extra-vars` or another fashion. An example of passing a variable on the command-line is as follows: | ||
|
||
`ansible-playbook ./c4b-environment --extra-vars "license_path=/path/to/chocolatey.license.xml certificate_path=/path/to/certificate.pfx"` | ||
|
||
You can also define variables in AWX, or within a file. For further details, see [Defining variables at runtime](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#passing-variables-on-the-command-line). | ||
|
||
For further information on deploying this environment, see [the docs page](https://docs.chocolatey.org/en-us/c4b-environments/ansible/). | ||
|
||
## Hardware Recommendations | ||
|
||
We recommend the following configuration if deploying to a single Ansible host: | ||
|
||
- Windows Server 2019+ | ||
- 4+ CPU cores | ||
- 16 GB+ RAM (8GB as a bare minimum; 4GB of RAM is reserved specifically for Nexus) | ||
- 500 GB+ of free space for local NuGet package artifact storage | ||
|
||
If deploying to multiple hosts, please refer to the recommended specifications for: | ||
|
||
- [Chocolatey Central Management](https://docs.chocolatey.org/en-us/central-management/setup/#high-level-requirements) | ||
- [Sonatype Nexus Repository](https://help.sonatype.com/repomanager3/product-information/sonatype-nexus-repository-system-requirements) | ||
- [Jenkins](https://www.jenkins.io/doc/book/installing/windows/#prerequisites) | ||
- [SQL Server Express](https://www.microsoft.com/en-us/download/details.aspx?id=104781) | ||
|
||
## Offline Installation | ||
|
||
To install in an air-gapped environment, you can download this repository to a local machine and run the `OfflineInstallPreparation.ps1` script. | ||
|
||
This script downloads all the required files and packages to ensure a successful installation. Please note that you will require a Windows machine with a licensed copy of Chocolatey, as it utilises the Package Internalizer feature. | ||
|
||
After the script has run, copy the directory to your Ansible environment and deploy it. | ||
|
||
## Storing Secrets | ||
|
||
After the playbook has run, various secrets will have been created and stored in the `/credentials` directory. To keep these secure, you should use [Ansible Vault](https://docs.ansible.com/ansible/latest/vault_guide/index.html) or something similar to store and inject them instead of the password lookup files, as `lookup('ansible.builtin.password'` does not support encryption or Ansible Vault. To do so, follow these steps for each secret (using `ccm_client_salt` as the example): | ||
|
||
- In a terminal on your Ansible machine, run `ansible-vault encrypt /path/to/repository/credentials/ccm_client_salt`. | ||
- Open the `/path/to/repository/credentials/ccm_client_salt` file and copy the new contents of the file. | ||
- Open the `./group_vars/all.yml` file and overwrite the value of `ccm_client_salt` with the vaulted value. | ||
|
||
This will result in re-deployment of the environment using this secret, going forward. | ||
|
||
If you want to re-deploy the environment having changed your passwords, or initially deploy it using your own generated values, you can use `ansible-vault` and the `all.yml` file to deploy using those values. | ||
|
||
- In a terminal on your Ansible machine, run `ansible-vault encrypt_string 'some-secure-password-here' --name 'ccm_client_salt'`. | ||
- Open the `./group_vars/all.yml` file and overwrite the line beginning `ccm_client_salt:` with the output of the `ansible-vault` command. |
Oops, something went wrong.