diff --git a/.gitignore b/.gitignore index 5312ec8..164fffb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vagrant/ .idea/ provision/provision-nexus/sources/ +shared/ diff --git a/README.md b/README.md index 5e781f0..9becf66 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ This will: * Configure Nexus through Groovy scripts. * Create the `adhoc-package` repository. * Create the `npm-group`, `npm-hosted` and `npmjs.org-proxy` repositories. + * Create the `chocolatey-group`, `chocolatey-hosted` and `chocolatey.org-proxy` repositories. * Configure the NuGet `nuget-hosted` repository to accept pushing with an API key. * Schedule a task to remove the old snapshots from the `maven-snapshots` repository. * Create users and a custom `deployer` role. @@ -25,6 +26,8 @@ This will: Build and install the [Ubuntu Base Box](https://github.com/rgl/ubuntu-vagrant). +Build and install the [Windows Base Box](https://github.com/rgl/windows-2016-vagrant). + Add the following entry to your `/etc/hosts` file: ``` diff --git a/Vagrantfile b/Vagrantfile index f5284b8..e808c1d 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,14 +1,32 @@ +nexus_domain = 'nexus.example.com' +nexus_ip = '192.168.56.3' + Vagrant.configure(2) do |config| - config.vm.box = 'ubuntu-16.04-amd64' - config.vm.hostname = 'nexus.example.com' - config.vm.network 'private_network', ip: '192.168.56.3' config.vm.provider 'virtualbox' do |vb| vb.linked_clone = true vb.cpus = 2 - vb.memory = 4096 + vb.memory = 2048 + end + + config.vm.define :nexus do |config| + config.vm.box = 'ubuntu-16.04-amd64' + config.vm.hostname = nexus_domain + config.vm.network 'private_network', ip: nexus_ip + config.vm.provision :shell, path: 'provision/provision-base.sh' + config.vm.provision :shell, path: 'provision/provision-nexus.sh' + config.vm.provision :shell, path: 'provision/test.sh' + config.vm.provision :shell, path: 'provision/summary.sh' + end + + config.vm.define :windows do |config| + config.vm.box = 'windows-2016-amd64' + config.vm.network 'private_network', ip: '192.168.56.4' + config.vm.provider :virtualbox do |v, override| + v.customize ['modifyvm', :id, '--vram', 64] + v.customize ['modifyvm', :id, '--clipboard', 'bidirectional'] + end + config.vm.provision :shell, inline: "echo '#{nexus_ip} #{nexus_domain}' | Out-File -Encoding Ascii -Append c:/Windows/System32/drivers/etc/hosts" + config.vm.provision :shell, path: 'provision/windows/ps.ps1', args: ['provision-base.ps1', nexus_domain] + config.vm.provision :shell, path: 'provision/windows/ps.ps1', args: ['use-chocolatey-repository.ps1', nexus_domain] end - config.vm.provision :shell, path: 'provision/provision-base.sh' - config.vm.provision :shell, path: 'provision/provision-nexus.sh' - config.vm.provision :shell, path: 'provision/test.sh' - config.vm.provision :shell, path: 'provision/summary.sh' end diff --git a/provision/provision-base.sh b/provision/provision-base.sh index 557c7b1..91a3cb5 100644 --- a/provision/provision-base.sh +++ b/provision/provision-base.sh @@ -58,6 +58,13 @@ openssl x509 -req -sha256 \ -days 365 \ -in $config_fqdn-csr.pem \ -out $config_fqdn-crt.pem +openssl x509 \ + -in $config_fqdn-crt.pem \ + -outform der \ + -out $config_fqdn-crt.der +# copy the certificate to a place where it can be used by other machines. +mkdir -p /vagrant/shared +cp $config_fqdn-crt.* /vagrant/shared popd diff --git a/provision/provision-nexus/src/main/groovy/provision.groovy b/provision/provision-nexus/src/main/groovy/provision.groovy index 595e554..2302e11 100644 --- a/provision/provision-nexus/src/main/groovy/provision.groovy +++ b/provision/provision-nexus/src/main/groovy/provision.groovy @@ -1,8 +1,9 @@ -// run this file inside the Vagrant environment with bash /vagrant/execute-provision.groovy-script.sh +// run this file inside the Vagrant environment with bash /vagrant/provision/execute-provision.groovy-script.sh // see https://help.sonatype.com/display/NXRM3/REST+and+Integration+API // see https://github.com/sonatype/nexus-book-examples/tree/nexus-3.x/scripting/nexus-script-example import groovy.json.JsonOutput +import org.sonatype.nexus.repository.storage.WritePolicy import org.sonatype.nexus.security.user.UserSearchCriteria import org.sonatype.nexus.security.authc.apikey.ApiKeyStore import org.sonatype.nexus.security.realm.RealmManager @@ -29,6 +30,15 @@ repository.createNpmProxy("npmjs.org-proxy", "https://registry.npmjs.org", "defa repository.createNpmGroup("npm-group", ["npm-hosted", "npmjs.org-proxy"], "default") +// create a chocolatey repository backed by the default blob store. +repository.createNugetHosted("chocolatey-hosted", "default", true, WritePolicy.ALLOW_ONCE) +// create a chocolatey proxy repository backed by the default blob store. +// see https://help.sonatype.com/display/NXRM3/.NET+Package+Repositories+with+NuGet +repository.createNugetProxy("chocolatey.org-proxy", "https://chocolatey.org/api/v2/", "default") +// create a chocolatey group repository that merges the chocolatey-host and chocolatey.org-proxy together. +repository.createNugetGroup("chocolatey-group", ["chocolatey-hosted", "chocolatey.org-proxy"], "default") + + // see http://stackoverflow.com/questions/8138164/groovy-generate-random-string-from-given-character-set def random(String alphabet, int n) { new Random().with { diff --git a/provision/test.sh b/provision/test.sh index 6daf210..018e75c 100644 --- a/provision/test.sh +++ b/provision/test.sh @@ -23,6 +23,7 @@ function nuget { nuget_source_url=http://localhost:8081/repository/nuget-group/ nuget_source_push_url=http://localhost:8081/repository/nuget-hosted/ nuget_source_push_api_key=$(nexus-groovy get-jenkins-nuget-api-key | jq -r '.result | fromjson | .apiKey') +echo -n $nuget_source_push_api_key >/vagrant/shared/jenkins-nuget-api-key # test installing a package from the public NuGet repository. nuget install MsgPack -Source $nuget_source_url diff --git a/provision/windows/GoogleChrome-external_extensions.json b/provision/windows/GoogleChrome-external_extensions.json new file mode 100644 index 0000000..3703272 --- /dev/null +++ b/provision/windows/GoogleChrome-external_extensions.json @@ -0,0 +1,10 @@ +{ + // JSON Formatter (https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa). + "bcjindcccaagfpapjjmafapmmgkkhgoa": { + "external_update_url": "https://clients2.google.com/service/update2/crx" + }, + // uBlock Origin (https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm). + "cjpalhdlnbpafiamejdnhcphjbkeiagm": { + "external_update_url": "https://clients2.google.com/service/update2/crx" + } +} \ No newline at end of file diff --git a/provision/windows/GoogleChrome-master_bookmarks.html b/provision/windows/GoogleChrome-master_bookmarks.html new file mode 100644 index 0000000..3dd16a8 --- /dev/null +++ b/provision/windows/GoogleChrome-master_bookmarks.html @@ -0,0 +1,10 @@ + + +Bookmarks +

Bookmarks

+

+

Bookmarks bar

+

+

OpenSSH for Windows +

+

diff --git a/provision/windows/GoogleChrome-master_preferences.json b/provision/windows/GoogleChrome-master_preferences.json new file mode 100644 index 0000000..50a5896 --- /dev/null +++ b/provision/windows/GoogleChrome-master_preferences.json @@ -0,0 +1,34 @@ +{ + "session": { + "restore_on_startup": 1 + }, + "bookmark_bar": { + "show_on_all_tabs": true + }, + "sync_promo": { + "show_on_first_run_allowed": false + }, + "distribution": { + "import_bookmarks_from_file": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\master_bookmarks.html", + "import_bookmarks": true, + "import_history": true, + "import_home_page": true, + "import_search_engine": true, + "suppress_first_run_bubble": true, + "do_not_create_desktop_shortcut": true, + "do_not_create_quick_launch_shortcut": false, + "do_not_launch_chrome": true, + "do_not_register_for_update_launch": true, + "make_chrome_default": true, + "make_chrome_default_for_user": true, + "suppress_first_run_default_browser_prompt": false, + "system_level": true, + "verbose_logging": true + }, + "first_run_tabs": [ + "chrome://extensions", + "chrome://version", + "https://github.com/rgl", + "https://ruilopes.com" + ] +} \ No newline at end of file diff --git a/provision/windows/provision-base.ps1 b/provision/windows/provision-base.ps1 new file mode 100644 index 0000000..2be5656 --- /dev/null +++ b/provision/windows/provision-base.ps1 @@ -0,0 +1,38 @@ +param( + [string]$nexusDomain = 'nexus.example.com' +) + +# set keyboard layout. +# NB you can get the name from the list: +# [System.Globalization.CultureInfo]::GetCultures('InstalledWin32Cultures') | out-gridview +Set-WinUserLanguageList pt-PT -Force + +# set the date format, number format, etc. +Set-Culture pt-PT + +# set the timezone. +# tzutil /l lists all available timezone ids +& $env:windir\system32\tzutil /s "GMT Standard Time" + +# show window content while dragging. +Set-ItemProperty -Path 'HKCU:Control Panel\Desktop' -Name DragFullWindows -Value 1 + +# show hidden files. +Set-ItemProperty -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name Hidden -Value 1 + +# show file extensions. +Set-ItemProperty -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name HideFileExt -Value 0 + +# display full path in the title bar. +New-Item -Path HKCU:Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState -Force ` + | New-ItemProperty -Name FullPath -Value 1 -PropertyType DWORD ` + | Out-Null + +# set default Explorer location to This PC. +Set-ItemProperty -Path HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name LaunchTo -Value 1 + +# trust the nexus server certificate. +Import-Certificate ` + -FilePath "c:/vagrant/shared/$nexusDomain-crt.der" ` + -CertStoreLocation Cert:\LocalMachine\Root ` + | Out-Null diff --git a/provision/windows/ps.ps1 b/provision/windows/ps.ps1 new file mode 100644 index 0000000..1532f6a --- /dev/null +++ b/provision/windows/ps.ps1 @@ -0,0 +1,47 @@ +param( + [Parameter(Mandatory=$true)] + [String]$script, + [Parameter(ValueFromRemainingArguments=$true)] + [String[]]$scriptArguments +) + +Set-StrictMode -Version Latest + +$ErrorActionPreference = 'Stop' + +trap { + Write-Output "ERROR: $_" + Write-Output (($_.ScriptStackTrace -split '\r?\n') -replace '^(.*)$','ERROR: $1') + Write-Output (($_.Exception.ToString() -split '\r?\n') -replace '^(.*)$','ERROR EXCEPTION: $1') + Exit 1 +} + +# wrap the choco command (to make sure this script aborts when it fails). +function Start-Choco([string[]]$Arguments, [int[]]$SuccessExitCodes=@(0)) { + $command, $commandArguments = $Arguments + if ($command -eq 'install') { + $Arguments = @($command, '--no-progress') + $commandArguments + } + for ($n = 0; $n -lt 10; ++$n) { + if ($n) { + # NB sometimes choco fails with "The package was not found with the source(s) listed." + # but normally its just really a transient "network" error. + Write-Host "Retrying choco install..." + Start-Sleep -Seconds 3 + } + &C:\ProgramData\chocolatey\bin\choco.exe @Arguments + if ($SuccessExitCodes -Contains $LASTEXITCODE) { + return + } + } + throw "$(@('choco')+$Arguments | ConvertTo-Json -Compress) failed with exit code $LASTEXITCODE" +} +function choco { + Start-Choco $Args +} + +cd c:/vagrant/provision/windows +$script = Resolve-Path $script +cd (Split-Path $script -Parent) +Write-Host "Running $script..." +. $script @scriptArguments diff --git a/provision/windows/use-chocolatey-repository.ps1 b/provision/windows/use-chocolatey-repository.ps1 new file mode 100644 index 0000000..6975231 --- /dev/null +++ b/provision/windows/use-chocolatey-repository.ps1 @@ -0,0 +1,68 @@ +param( + [string]$nexusDomain = 'nexus.example.com' +) + +# install chocolatey. +iex ((New-Object Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + +Write-Host 'Default Chocolatey sources:' +choco sources list + +# see https://github.com/chocolatey/choco/wiki/CommandsSources +Write-Host 'Configuring chocolatey to use the nexus server...' +choco sources remove --name chocolatey +choco sources add --name nexus --source https://$nexusDomain/repository/chocolatey-group/ + +Write-Host 'Current Chocolatey sources:' +choco sources list + +Write-Host 'Installing Google Chrome from the nexus server...' +# NB --ignore-checksums is needed because chrome does not release a versioned +# installer... as such, sometimes this package installation breaks if we +# do not ignore the checksums and there's a new chrome version available. +# see https://www.chromium.org/administrators/configuring-other-preferences +choco install -y --ignore-checksums googlechrome +$chromeLocation = 'C:\Program Files (x86)\Google\Chrome\Application' +cp -Force GoogleChrome-external_extensions.json (Get-Item "$chromeLocation\*\default_apps\external_extensions.json").FullName +cp -Force GoogleChrome-master_preferences.json "$chromeLocation\master_preferences" +cp -Force GoogleChrome-master_bookmarks.html "$chromeLocation\master_bookmarks.html" + +# see https://github.com/chocolatey/choco/wiki/CreatePackages +# see https://docs.nuget.org/docs/reference/nuspec-reference +Write-Host 'Creating the graceful-terminating-console-application-windows chocolatey package...' +Push-Location $env:TEMP +mkdir graceful-terminating-console-application-windows | Out-Null +cd graceful-terminating-console-application-windows +Set-Content -Encoding Ascii graceful-terminating-console-application-windows.nuspec @' + + + graceful-terminating-console-application-windows + 0.4.0 + Rui Lopes + Rui Lopes + http://choosealicense.com/licenses/mit/ + https://github.com/rgl/graceful-terminating-console-application-windows + false + a graceful terminating console application for windows + Release Notes Go Here + Copyright Rui Lopes + graceful console terminate exit + + +'@ +mkdir tools | Out-Null +(New-Object Net.WebClient).DownloadFile( + 'https://github.com/rgl/graceful-terminating-console-application-windows/releases/download/v0.4.0/graceful-terminating-console-application-windows.zip', + "$env:TEMP\graceful-terminating-console-application-windows.zip") +Expand-Archive "$env:TEMP\graceful-terminating-console-application-windows.zip" tools +choco pack +Write-Host 'Publishing the graceful-terminating-console-application-windows chocolatey package...' +choco push ` + --source https://$nexusDomain/repository/chocolatey-hosted/ ` + --api-key (Get-Content c:\vagrant\shared\jenkins-nuget-api-key) +Pop-Location + +Write-Host 'Installing the graceful-terminating-console-application-windows chocolatey package...' +choco install -y graceful-terminating-console-application-windows +Write-Host 'graceful-terminating-console-application-windows installed at:' +dir C:\ProgramData\chocolatey\bin\graceful-terminating-console-application-windows.exe