idlc-sdk-pfm 1.0.0.pre.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/.yardopts +3 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +37 -0
- data/Rakefile +6 -0
- data/bin/pfm +8 -0
- data/docs/GettingStarted.md +299 -0
- data/idlc-sdk-pfm.gemspec +44 -0
- data/lib/idlc-sdk-pfm/builtin_commands.rb +11 -0
- data/lib/idlc-sdk-pfm/cli.rb +150 -0
- data/lib/idlc-sdk-pfm/command/apply.rb +71 -0
- data/lib/idlc-sdk-pfm/command/base.rb +195 -0
- data/lib/idlc-sdk-pfm/command/build.rb +120 -0
- data/lib/idlc-sdk-pfm/command/configure.rb +41 -0
- data/lib/idlc-sdk-pfm/command/destroy.rb +61 -0
- data/lib/idlc-sdk-pfm/command/exec.rb +24 -0
- data/lib/idlc-sdk-pfm/command/format.rb +64 -0
- data/lib/idlc-sdk-pfm/command/generate.rb +83 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/base.rb +50 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/server_build.rb +58 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/Berksfile +3 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/build_cookbook/.kitchen.yml +21 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/build_cookbook/README.md +146 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/build_cookbook/test-fixture-recipe.rb +8 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/chefignore +107 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/cookbook_readmes/README-policy.md +9 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/cookbook_readmes/README.md +54 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/delivery-config.json +12 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/delivery-project.toml +36 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/gitignore +21 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/README.md +24 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/README.md +27 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +7 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/metadata.rb +6 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +8 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/data_bags/README.md +56 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/data_bags/example/example_item.json +4 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/dot-chef-repo.txt +6 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/environments/README.md +9 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/environments/example.json +13 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/policies/README.md +24 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/roles/README.md +9 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/roles/example.json +13 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/spec_helper.rb +2 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/spec_helper_policyfile.rb +2 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/metadata.rb +7 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/app.rb +89 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/attribute.rb +12 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/build_cookbook.rb +182 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/cookbook.rb +144 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/cookbook_file.rb +24 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/lwrp.rb +23 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/policyfile.rb +8 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/recipe.rb +51 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/repo.rb +67 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/template.rb +32 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.all_rights.erb +3 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.apachev2.erb +201 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.gplv2.erb +339 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.gplv3.erb +674 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.mit.erb +21 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/Policyfile.rb.erb +25 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/README.md.erb +4 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/attribute.rb.erb +0 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/build_cookbook/Berksfile.erb +7 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/build_cookbook/metadata.rb.erb +10 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/build_cookbook/recipe.rb.erb +8 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/cookbook_file.erb +0 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/inspec_default_test.rb.erb +18 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/kitchen.yml.erb +26 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/kitchen_policyfile.yml.erb +33 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/metadata.rb.erb +20 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/provider.rb.erb +0 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/recipe.rb.erb +5 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/recipe_spec.rb.erb +22 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/repo/gitignore.erb +128 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/resource.rb.erb +0 -0
- data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/template.erb +0 -0
- data/lib/idlc-sdk-pfm/command/generator_commands.rb +34 -0
- data/lib/idlc-sdk-pfm/command/plan.rb +80 -0
- data/lib/idlc-sdk-pfm/command/templates/app/files/config/client.rb.template +9 -0
- data/lib/idlc-sdk-pfm/command/templates/app/files/config/init.ps1.userdata +16 -0
- data/lib/idlc-sdk-pfm/command/templates/base/files/config/client.rb.template +6 -0
- data/lib/idlc-sdk-pfm/command/templates/base/files/config/init.ps1.userdata +219 -0
- data/lib/idlc-sdk-pfm/command/validate.rb +85 -0
- data/lib/idlc-sdk-pfm/command/validator_commands/base.rb +65 -0
- data/lib/idlc-sdk-pfm/command/validator_commands/infrastructure.rb +46 -0
- data/lib/idlc-sdk-pfm/command/validator_commands/server_build.rb +135 -0
- data/lib/idlc-sdk-pfm/command/validator_commands.rb +32 -0
- data/lib/idlc-sdk-pfm/commands_map.rb +61 -0
- data/lib/idlc-sdk-pfm/generator.rb +52 -0
- data/lib/idlc-sdk-pfm/helpers.rb +49 -0
- data/lib/idlc-sdk-pfm/settings.rb +205 -0
- data/lib/idlc-sdk-pfm/validator.rb +52 -0
- data/lib/idlc-sdk-pfm/version.rb +3 -0
- data/lib/idlc-sdk-pfm.rb +24 -0
- metadata +342 -0
@@ -0,0 +1,219 @@
|
|
1
|
+
<powershell>
|
2
|
+
# Configure a Windows host for remote management with Ansible
|
3
|
+
# -----------------------------------------------------------
|
4
|
+
#
|
5
|
+
# This script checks the current WinRM/PSRemoting configuration and makes the
|
6
|
+
# necessary changes to allow Ansible to connect, authenticate and execute
|
7
|
+
# PowerShell commands.
|
8
|
+
#
|
9
|
+
# Set $VerbosePreference = "Continue" before running the script in order to
|
10
|
+
# see the output messages.
|
11
|
+
# Set $SkipNetworkProfileCheck to skip the network profile check. Without
|
12
|
+
# specifying this the script will only run if the device's interfaces are in
|
13
|
+
# DOMAIN or PRIVATE zones. Provide this switch if you want to enable winrm on
|
14
|
+
# a device with an interface in PUBLIC zone.
|
15
|
+
#
|
16
|
+
# Written by Trond Hindenes <trond@hindenes.com>
|
17
|
+
# Updated by Chris Church <cchurch@ansible.com>
|
18
|
+
# Updated by Michael Crilly <mike@autologic.cm>
|
19
|
+
#
|
20
|
+
# Version 1.0 - July 6th, 2014
|
21
|
+
# Version 1.1 - November 11th, 2014
|
22
|
+
# Version 1.2 - May 15th, 2015
|
23
|
+
|
24
|
+
Param (
|
25
|
+
[string]$SubjectName = $env:COMPUTERNAME,
|
26
|
+
[int]$CertValidityDays = 365,
|
27
|
+
[switch]$SkipNetworkProfileCheck,
|
28
|
+
$CreateSelfSignedCert = $true
|
29
|
+
)
|
30
|
+
|
31
|
+
Function New-LegacySelfSignedCert
|
32
|
+
{
|
33
|
+
Param (
|
34
|
+
[string]$SubjectName,
|
35
|
+
[int]$ValidDays = 365
|
36
|
+
)
|
37
|
+
|
38
|
+
$name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
|
39
|
+
$name.Encode("CN=$SubjectName", 0)
|
40
|
+
|
41
|
+
$key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
|
42
|
+
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
|
43
|
+
$key.KeySpec = 1
|
44
|
+
$key.Length = 1024
|
45
|
+
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
|
46
|
+
$key.MachineContext = 1
|
47
|
+
$key.Create()
|
48
|
+
|
49
|
+
$serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
|
50
|
+
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
|
51
|
+
$ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
|
52
|
+
$ekuoids.Add($serverauthoid)
|
53
|
+
$ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
|
54
|
+
$ekuext.InitializeEncode($ekuoids)
|
55
|
+
|
56
|
+
$cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
|
57
|
+
$cert.InitializeFromPrivateKey(2, $key, "")
|
58
|
+
$cert.Subject = $name
|
59
|
+
$cert.Issuer = $cert.Subject
|
60
|
+
$cert.NotBefore = (Get-Date).AddDays(-1)
|
61
|
+
$cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
|
62
|
+
$cert.X509Extensions.Add($ekuext)
|
63
|
+
$cert.Encode()
|
64
|
+
|
65
|
+
$enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
|
66
|
+
$enrollment.InitializeFromRequest($cert)
|
67
|
+
$certdata = $enrollment.CreateRequest(0)
|
68
|
+
$enrollment.InstallResponse(2, $certdata, 0, "")
|
69
|
+
|
70
|
+
# Return the thumbprint of the last installed certificate;
|
71
|
+
# This is needed for the new HTTPS WinRM listerner we're
|
72
|
+
# going to create further down.
|
73
|
+
Get-ChildItem "Cert:\LocalMachine\my"| Sort-Object NotBefore -Descending | Select -First 1 | Select -Expand Thumbprint
|
74
|
+
}
|
75
|
+
|
76
|
+
# Setup error handling.
|
77
|
+
Trap
|
78
|
+
{
|
79
|
+
$_
|
80
|
+
Exit 1
|
81
|
+
}
|
82
|
+
$ErrorActionPreference = "Stop"
|
83
|
+
|
84
|
+
# Detect PowerShell version.
|
85
|
+
If ($PSVersionTable.PSVersion.Major -lt 3)
|
86
|
+
{
|
87
|
+
Throw "PowerShell version 3 or higher is required."
|
88
|
+
}
|
89
|
+
|
90
|
+
# Find and start the WinRM service.
|
91
|
+
Write-Verbose "Verifying WinRM service."
|
92
|
+
If (!(Get-Service "WinRM"))
|
93
|
+
{
|
94
|
+
Throw "Unable to find the WinRM service."
|
95
|
+
}
|
96
|
+
ElseIf ((Get-Service "WinRM").Status -ne "Running")
|
97
|
+
{
|
98
|
+
Write-Verbose "Starting WinRM service."
|
99
|
+
Start-Service -Name "WinRM" -ErrorAction Stop
|
100
|
+
}
|
101
|
+
|
102
|
+
# WinRM should be running; check that we have a PS session config.
|
103
|
+
If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
|
104
|
+
{
|
105
|
+
if ($SkipNetworkProfileCheck) {
|
106
|
+
Write-Verbose "Enabling PS Remoting without checking Network profile."
|
107
|
+
Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
|
108
|
+
}
|
109
|
+
else {
|
110
|
+
Write-Verbose "Enabling PS Remoting"
|
111
|
+
Enable-PSRemoting -Force -ErrorAction Stop
|
112
|
+
}
|
113
|
+
}
|
114
|
+
Else
|
115
|
+
{
|
116
|
+
Write-Verbose "PS Remoting is already enabled."
|
117
|
+
}
|
118
|
+
|
119
|
+
# Make sure there is a SSL listener.
|
120
|
+
$listeners = Get-ChildItem WSMan:\localhost\Listener
|
121
|
+
If (!($listeners | Where {$_.Keys -like "TRANSPORT=HTTPS"}))
|
122
|
+
{
|
123
|
+
# HTTPS-based endpoint does not exist.
|
124
|
+
If (Get-Command "New-SelfSignedCertificate" -ErrorAction SilentlyContinue)
|
125
|
+
{
|
126
|
+
$cert = New-SelfSignedCertificate -DnsName $SubjectName -CertStoreLocation "Cert:\LocalMachine\My"
|
127
|
+
$thumbprint = $cert.Thumbprint
|
128
|
+
Write-Host "Self-signed SSL certificate generated; thumbprint: $thumbprint"
|
129
|
+
}
|
130
|
+
Else
|
131
|
+
{
|
132
|
+
$thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName
|
133
|
+
Write-Host "(Legacy) Self-signed SSL certificate generated; thumbprint: $thumbprint"
|
134
|
+
}
|
135
|
+
|
136
|
+
# Create the hashtables of settings to be used.
|
137
|
+
$valueset = @{}
|
138
|
+
$valueset.Add('Hostname', $SubjectName)
|
139
|
+
$valueset.Add('CertificateThumbprint', $thumbprint)
|
140
|
+
|
141
|
+
$selectorset = @{}
|
142
|
+
$selectorset.Add('Transport', 'HTTPS')
|
143
|
+
$selectorset.Add('Address', '*')
|
144
|
+
|
145
|
+
Write-Verbose "Enabling SSL listener."
|
146
|
+
New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
|
147
|
+
}
|
148
|
+
Else
|
149
|
+
{
|
150
|
+
Write-Verbose "SSL listener is already active."
|
151
|
+
}
|
152
|
+
|
153
|
+
# Check for basic authentication.
|
154
|
+
$basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where {$_.Name -eq "Basic"}
|
155
|
+
If (($basicAuthSetting.Value) -eq $false)
|
156
|
+
{
|
157
|
+
Write-Verbose "Enabling basic auth support."
|
158
|
+
Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
|
159
|
+
}
|
160
|
+
Else
|
161
|
+
{
|
162
|
+
Write-Verbose "Basic auth is already enabled."
|
163
|
+
}
|
164
|
+
|
165
|
+
# Configure firewall to allow WinRM HTTPS connections.
|
166
|
+
$fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
|
167
|
+
$fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
|
168
|
+
If ($fwtest1.count -lt 5)
|
169
|
+
{
|
170
|
+
Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
|
171
|
+
netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
|
172
|
+
}
|
173
|
+
ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
|
174
|
+
{
|
175
|
+
Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
|
176
|
+
netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
|
177
|
+
}
|
178
|
+
Else
|
179
|
+
{
|
180
|
+
Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
|
181
|
+
}
|
182
|
+
|
183
|
+
# Test a remoting connection to localhost, which should work.
|
184
|
+
$httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
|
185
|
+
$httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
|
186
|
+
|
187
|
+
$httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
|
188
|
+
|
189
|
+
If ($httpResult -and $httpsResult)
|
190
|
+
{
|
191
|
+
Write-Verbose "HTTP: Enabled | HTTPS: Enabled"
|
192
|
+
}
|
193
|
+
ElseIf ($httpsResult -and !$httpResult)
|
194
|
+
{
|
195
|
+
Write-Verbose "HTTP: Disabled | HTTPS: Enabled"
|
196
|
+
}
|
197
|
+
ElseIf ($httpResult -and !$httpsResult)
|
198
|
+
{
|
199
|
+
Write-Verbose "HTTP: Enabled | HTTPS: Disabled"
|
200
|
+
}
|
201
|
+
Else
|
202
|
+
{
|
203
|
+
Throw "Unable to establish an HTTP or HTTPS remoting session."
|
204
|
+
}
|
205
|
+
Write-Verbose "PS Remoting has been successfully configured for Ansible."
|
206
|
+
|
207
|
+
# Change the Administrator password to something temporary for provisioning.
|
208
|
+
# This will be changed back to something secure on deployment, so we can safely
|
209
|
+
# store this password in plain text in SCM.
|
210
|
+
$user = "Administrator"
|
211
|
+
$pass = 'Aut0m@t0r'
|
212
|
+
$newpass = [ADSI]"WinNT://localhost/$user,user"
|
213
|
+
$newpass.SetPassword($pass)
|
214
|
+
$newpass.SetInfo()
|
215
|
+
|
216
|
+
# Turn off PowerShell execution policy restrictions
|
217
|
+
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope LocalMachine
|
218
|
+
|
219
|
+
</powershell>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'idlc-sdk-pfm/command/base'
|
2
|
+
require 'idlc-sdk-pfm/command/validator_commands'
|
3
|
+
require 'idlc-sdk-pfm/command/validator_commands/base'
|
4
|
+
require 'idlc-sdk-pfm/command/validator_commands/server_build'
|
5
|
+
require 'idlc-sdk-pfm/command/validator_commands/infrastructure'
|
6
|
+
|
7
|
+
module Pfm
|
8
|
+
module Command
|
9
|
+
class Validate < Base
|
10
|
+
|
11
|
+
ValidatorCommand = Struct.new(:name, :class_name, :description)
|
12
|
+
|
13
|
+
def self.validators
|
14
|
+
@validators ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.validator(name, class_name, description)
|
18
|
+
validators << ValidatorCommand.new(name, class_name, description)
|
19
|
+
end
|
20
|
+
|
21
|
+
validator('server-build', :ServerBuild, 'Validate a server build repo')
|
22
|
+
validator('infrastructure', :Infrastructure, 'Validate an infrastructure repo')
|
23
|
+
|
24
|
+
def self.banner_headline
|
25
|
+
<<-E
|
26
|
+
Usage: pfm validate VALIDATOR [options]
|
27
|
+
Available validators:
|
28
|
+
E
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.validator_list
|
32
|
+
justify_size = validators.map { |g| g.name.size }.max + 2
|
33
|
+
validators.map { |g| " #{g.name.to_s.ljust(justify_size)}#{g.description}" }.join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.banner
|
37
|
+
banner_headline + validator_list + "\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
# pfm validate app path/to/basename --skel=path/to/skeleton --example
|
41
|
+
# pfm validate file name [path/to/cookbook_root] (inferred from cwd) --from=source_file
|
42
|
+
|
43
|
+
def initialize(*args)
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
def run(params)
|
48
|
+
if validator_spec = validator_for(params[0])
|
49
|
+
params.shift
|
50
|
+
validator = ValidatorCommands.build(validator_spec.class_name, params)
|
51
|
+
validator.run
|
52
|
+
else
|
53
|
+
msg(banner)
|
54
|
+
1
|
55
|
+
end
|
56
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
57
|
+
# Pfm::Command::Base also handles this error in the same way, but it
|
58
|
+
# does not have access to the correct option parser, so it cannot print
|
59
|
+
# the usage correctly. Therefore, invalid CLI usage needs to be handled
|
60
|
+
# here.
|
61
|
+
err("ERROR: #{e.message}\n")
|
62
|
+
msg(validator.opt_parser)
|
63
|
+
1
|
64
|
+
end
|
65
|
+
|
66
|
+
def validator_for(arg)
|
67
|
+
self.class.validators.find { |g| g.name.to_s == arg }
|
68
|
+
end
|
69
|
+
|
70
|
+
# In the Base class, this is defined to be true if any args match "-h" or
|
71
|
+
# "--help". Here we override that behavior such that if the first
|
72
|
+
# argument is a valid validator name, like `pfm validate server-build -h`,
|
73
|
+
# we delegate the request to the specified validator.
|
74
|
+
def needs_help?(params)
|
75
|
+
return false if have_validator?(params[0])
|
76
|
+
super
|
77
|
+
end
|
78
|
+
|
79
|
+
def have_validator?(name)
|
80
|
+
self.class.validators.map { |g| g.name.to_s }.include?(name)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "idlc-sdk-pfm/command/validator_commands"
|
2
|
+
|
3
|
+
module Pfm
|
4
|
+
module Command
|
5
|
+
module ValidatorCommands
|
6
|
+
class ValidationError < StandardError; end
|
7
|
+
|
8
|
+
class Base < Command::Base
|
9
|
+
attr_reader :params
|
10
|
+
attr_reader :errors
|
11
|
+
|
12
|
+
options.merge!(SharedValidatorOptions.options)
|
13
|
+
|
14
|
+
def initialize(params)
|
15
|
+
super()
|
16
|
+
@params_valid = true
|
17
|
+
@errors = []
|
18
|
+
@params = params
|
19
|
+
@failure = false
|
20
|
+
|
21
|
+
@reports_dir = "#{Pfm::Settings.new.config_directory}/tests/reports"
|
22
|
+
@artifacts_dir = "#{Pfm::Settings.new.config_directory}/tests/artifacts"
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup_context; end
|
26
|
+
|
27
|
+
def read_and_validate_params
|
28
|
+
arguments = parse_options(@params)
|
29
|
+
|
30
|
+
case arguments.size
|
31
|
+
when 0
|
32
|
+
@params_valid = (@config[:validator_name] == 'infrastructure')
|
33
|
+
|
34
|
+
when 1
|
35
|
+
@params_valid = build_exists?
|
36
|
+
|
37
|
+
when 2
|
38
|
+
|
39
|
+
else
|
40
|
+
@params_valid = false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def params_valid?
|
45
|
+
@params_valid
|
46
|
+
end
|
47
|
+
|
48
|
+
def use_circle_ci?
|
49
|
+
@params.include?('-c') || @params.include?('--circle-ci')
|
50
|
+
end
|
51
|
+
|
52
|
+
def setup_artifacts_dirs
|
53
|
+
if use_circle_ci?
|
54
|
+
@reports_dir = ENV['CIRCLE_TEST_REPORTS']
|
55
|
+
@artifacts_dir = ENV['CIRCLE_ARTIFACTS']
|
56
|
+
return
|
57
|
+
end
|
58
|
+
|
59
|
+
FileUtils.mkdir_p(@reports_dir)
|
60
|
+
FileUtils.mkdir_p(@artifacts_dir)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Pfm
|
2
|
+
module Command
|
3
|
+
module ValidatorCommands
|
4
|
+
class Infrastructure < Base
|
5
|
+
banner 'Usage: pfm validate infrastructure [options]'
|
6
|
+
|
7
|
+
option :app_release,
|
8
|
+
short: '-a VERSION',
|
9
|
+
long: '--app-release VERSION',
|
10
|
+
description: 'Application Version Number to Deploy',
|
11
|
+
default: ''
|
12
|
+
|
13
|
+
options.merge!(SharedValidatorOptions.options)
|
14
|
+
|
15
|
+
def run
|
16
|
+
@config[:validator_name] = 'infrastructure'
|
17
|
+
|
18
|
+
read_and_validate_params
|
19
|
+
setup_artifacts_dirs
|
20
|
+
|
21
|
+
if params_valid?
|
22
|
+
deploy_setup
|
23
|
+
validate
|
24
|
+
# @workspace.cleanup causing bundler issues
|
25
|
+
0
|
26
|
+
else
|
27
|
+
errors.each { |error| err("Error: #{error}") }
|
28
|
+
parse_options(params)
|
29
|
+
msg(opt_parser)
|
30
|
+
1
|
31
|
+
end
|
32
|
+
rescue ValidationError => e
|
33
|
+
err("ERROR: #{e}")
|
34
|
+
1
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate
|
38
|
+
Terraform::Binary.validate(@workspace.tmp_dir.to_s)
|
39
|
+
msg('Verified repository..')
|
40
|
+
rescue Terraform::Binary::Command::CommandFailure
|
41
|
+
raise ValidationError, 'Failures reported during validation!'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Pfm
|
2
|
+
module Command
|
3
|
+
module ValidatorCommands
|
4
|
+
class ServerBuild < Base
|
5
|
+
banner 'Usage: pfm validate server-build BUILD_NAME [options]'
|
6
|
+
|
7
|
+
option :build_version,
|
8
|
+
short: '-b VERSION',
|
9
|
+
long: '--build-version VERSION',
|
10
|
+
description: 'override version number of build',
|
11
|
+
default: nil
|
12
|
+
|
13
|
+
option :build_template,
|
14
|
+
short: '-t TEMPLATE',
|
15
|
+
long: '--build-template TEMPLATE',
|
16
|
+
description: 'The Build Template to use. Defaults to build.json',
|
17
|
+
default: 'build.json'
|
18
|
+
|
19
|
+
option :build_metadata,
|
20
|
+
short: '-m METADATA_FILE',
|
21
|
+
long: '--build-metadata METADATA_FILE',
|
22
|
+
description: 'The build metadata file to use. Defaults to \'metadata\'',
|
23
|
+
default: 'metadata'
|
24
|
+
|
25
|
+
options.merge!(SharedValidatorOptions.options)
|
26
|
+
|
27
|
+
def run
|
28
|
+
read_and_validate_params
|
29
|
+
setup_artifacts_dirs
|
30
|
+
|
31
|
+
if params_valid?
|
32
|
+
build_setup
|
33
|
+
validate
|
34
|
+
# @workspace.cleanup causing bundler issues
|
35
|
+
0
|
36
|
+
else
|
37
|
+
errors.each { |error| err("Error: #{error}") }
|
38
|
+
parse_options(params)
|
39
|
+
msg(opt_parser)
|
40
|
+
1
|
41
|
+
end
|
42
|
+
rescue ValidationError => e
|
43
|
+
err("ERROR: #{e}")
|
44
|
+
1
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate
|
48
|
+
lint_packer
|
49
|
+
lint_chef
|
50
|
+
unit_test
|
51
|
+
|
52
|
+
raise ValidationError, 'Failures reported during validation!' if @failure
|
53
|
+
msg('Verified repository..')
|
54
|
+
end
|
55
|
+
|
56
|
+
def lint_packer
|
57
|
+
Packer::Binary.validate("#{@build_config.dump_build_vars} #{@config[:build_template]}")
|
58
|
+
rescue Packer::Binary::Command::CommandFailure
|
59
|
+
@failure = true
|
60
|
+
end
|
61
|
+
|
62
|
+
def lint_chef
|
63
|
+
base_path = 'chef'
|
64
|
+
cookbooks_dir = 'cookbooks'
|
65
|
+
|
66
|
+
# Loop through the base directory looking through all of the cookbooks
|
67
|
+
# for unit tests
|
68
|
+
Dir.entries(base_path).each do |dir|
|
69
|
+
next unless File.directory? "#{base_path}/#{dir}/#{cookbooks_dir}"
|
70
|
+
next if dir.to_s == 'vendor'
|
71
|
+
|
72
|
+
Dir.entries("#{base_path}/#{dir}/#{cookbooks_dir}").each do |cookbook|
|
73
|
+
next unless File.directory? "#{base_path}/#{dir}/#{cookbooks_dir}/#{cookbook}"
|
74
|
+
# skip directories eg. '.' and '..'
|
75
|
+
next if cookbook.to_s == '.' || cookbook.to_s == '..'
|
76
|
+
|
77
|
+
# Run the syntax and semantics checkers
|
78
|
+
msg("\nRunning Rubocop on #{cookbook} cookbook")
|
79
|
+
|
80
|
+
# Copy in global .foodcritic file if set
|
81
|
+
debug("copying #{SETTINGS['RUBOCOP_RULES_FILE']} to #{Dir.pwd}")
|
82
|
+
system("cp #{SETTINGS['RUBOCOP_RULES_FILE']} #{Dir.pwd}") if File.exist? SETTINGS['RUBOCOP_RULES_FILE']
|
83
|
+
|
84
|
+
gem_path = `bundle show rubocop-junit-formatter`.strip!
|
85
|
+
system("rubocop \\
|
86
|
+
--format html -o #{@artifacts_dir}/rubocop/#{cookbook}_rubocop_output.html \\
|
87
|
+
-r #{gem_path}/lib/rubocop/formatter/junit_formatter.rb \\
|
88
|
+
--format RuboCop::Formatter::JUnitFormatter -o #{@reports_dir}/rubocop/#{cookbook}_junit.xml \\
|
89
|
+
#{base_path}/#{dir}/#{cookbooks_dir}/#{cookbook}") || @failure = true
|
90
|
+
|
91
|
+
msg("Running Foodcritic on #{cookbook} cookbook")
|
92
|
+
ENV['FOODCRITIC_JUNIT_OUTPUT_DIR'] = "#{@reports_dir}/foodcritic"
|
93
|
+
ENV['FOODCRITIC_JUNIT_OUTPUT_FILE'] = "#{cookbook}_foodcritic_junit.xml"
|
94
|
+
|
95
|
+
# Copy in global .foodcritic file if set
|
96
|
+
debug("copying #{SETTINGS['FOODCRITIC_RULES_FILE']} to #{Dir.pwd}")
|
97
|
+
system("cp #{SETTINGS['FOODCRITIC_RULES_FILE']} #{base_path}/#{dir}/#{cookbooks_dir}/#{cookbook}") if File.exist? SETTINGS['FOODCRITIC_RULES_FILE']
|
98
|
+
|
99
|
+
# Capure output but also fail if applicable
|
100
|
+
system("foodcritic #{base_path}/#{dir}/#{cookbooks_dir}/#{cookbook} -C > #{cookbook}_foodcritic.out") || @failure = true
|
101
|
+
system("foodcritic-junit < #{cookbook}_foodcritic.out")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def unit_test
|
107
|
+
# load chefspec here as it load chef and can take a long time on some systems
|
108
|
+
# so we only want to load it when we absolutely need it
|
109
|
+
require 'chefspec'
|
110
|
+
base_path = 'chef'
|
111
|
+
cookbooks_dir = 'cookbooks'
|
112
|
+
|
113
|
+
# Loop through the base directory looking through all of the cookbooks
|
114
|
+
# for unit tests
|
115
|
+
Dir.entries(base_path).each do |dir|
|
116
|
+
next unless File.directory? "#{base_path}/#{dir}/#{cookbooks_dir}"
|
117
|
+
next if dir.to_s == 'vendor'
|
118
|
+
|
119
|
+
Dir.entries("#{base_path}/#{dir}/#{cookbooks_dir}").each do |cookbook|
|
120
|
+
next unless File.directory? "#{base_path}/#{dir}/#{cookbooks_dir}/#{cookbook}"
|
121
|
+
# skip directories eg. '.' and '..'
|
122
|
+
next if cookbook.to_s == '.' || cookbook.to_s == '..'
|
123
|
+
|
124
|
+
# run rspec unit tests
|
125
|
+
Dir.chdir("#{base_path}/#{dir}/#{cookbooks_dir}/#{cookbook}") do
|
126
|
+
msg("\nRunning unit tests for #{cookbook} cookbook")
|
127
|
+
system("rspec -r rspec_junit_formatter --format progress --format RspecJunitFormatter -o #{@reports_dir}/rspec/#{cookbook}_junit.xml") || @failure = true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'mixlib/cli'
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'pathname'
|
4
|
+
require 'idlc-sdk-pfm/command/base'
|
5
|
+
require 'idlc-sdk-pfm/validator'
|
6
|
+
|
7
|
+
module Pfm
|
8
|
+
module Command
|
9
|
+
# ## SharedValidatorOptions
|
10
|
+
#
|
11
|
+
# These CLI options are shared amongst the validator commands
|
12
|
+
module SharedValidatorOptions
|
13
|
+
include Mixlib::CLI
|
14
|
+
|
15
|
+
option :circle_ci,
|
16
|
+
short: '-c',
|
17
|
+
long: '--circle-ci',
|
18
|
+
description: 'Use Circle Ci artifact output directories',
|
19
|
+
boolean: true,
|
20
|
+
default: false
|
21
|
+
end
|
22
|
+
|
23
|
+
# ## ValidatorCommands
|
24
|
+
#
|
25
|
+
# This module is the namespace for all subcommands of `pfm validate`
|
26
|
+
module ValidatorCommands
|
27
|
+
def self.build(class_name, params)
|
28
|
+
const_get(class_name).new(params)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Pfm
|
2
|
+
class CommandsMap
|
3
|
+
NULL_ARG = Object.new
|
4
|
+
|
5
|
+
CommandSpec = Struct.new(:name, :constant_name, :require_path, :description)
|
6
|
+
|
7
|
+
class CommandSpec
|
8
|
+
|
9
|
+
def instantiate
|
10
|
+
require require_path
|
11
|
+
command_class = Pfm::Command.const_get(constant_name)
|
12
|
+
command_class.new
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :command_specs
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@command_specs = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def builtin(name, constant_name, require_path: NULL_ARG, desc: "")
|
24
|
+
if null?(require_path)
|
25
|
+
snake_case_path = name.tr("-", "_")
|
26
|
+
require_path = "idlc-sdk-pfm/command/#{snake_case_path}"
|
27
|
+
end
|
28
|
+
command_specs[name] = CommandSpec.new(name, constant_name, require_path, desc)
|
29
|
+
end
|
30
|
+
|
31
|
+
def instantiate(name)
|
32
|
+
spec_for(name).instantiate
|
33
|
+
end
|
34
|
+
|
35
|
+
def have_command?(name)
|
36
|
+
command_specs.key?(name)
|
37
|
+
end
|
38
|
+
|
39
|
+
def command_names
|
40
|
+
command_specs.keys
|
41
|
+
end
|
42
|
+
|
43
|
+
def spec_for(name)
|
44
|
+
command_specs[name]
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def null?(argument)
|
50
|
+
argument.equal?(NULL_ARG)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.commands_map
|
55
|
+
@commands_map ||= CommandsMap.new
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.commands
|
59
|
+
yield commands_map
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Pfm
|
2
|
+
module Generator
|
3
|
+
# This is here to hold attr_accessor data for Generator context variables
|
4
|
+
class Context
|
5
|
+
def self.add_attr(name)
|
6
|
+
@attributes ||= []
|
7
|
+
|
8
|
+
unless @attributes.include?(name)
|
9
|
+
@attributes << name
|
10
|
+
attr_accessor(name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.reset
|
15
|
+
return if @attributes.nil?
|
16
|
+
|
17
|
+
@attributes.each do |attr|
|
18
|
+
remove_method(attr)
|
19
|
+
end
|
20
|
+
|
21
|
+
@attributes = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.reset
|
26
|
+
@context = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.context
|
30
|
+
@context ||= Context.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.add_attr_to_context(name, value = nil)
|
34
|
+
sym_name = name.to_sym
|
35
|
+
Pfm::Generator::Context.add_attr(sym_name)
|
36
|
+
Pfm::Generator::TemplateHelper.delegate_to_app_context(sym_name)
|
37
|
+
context.public_send("#{sym_name}=", value)
|
38
|
+
end
|
39
|
+
|
40
|
+
module TemplateHelper
|
41
|
+
def self.delegate_to_app_context(name)
|
42
|
+
define_method(name) do
|
43
|
+
Pfm::Generator.context.public_send(name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def year
|
48
|
+
Time.now.year
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|