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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/.yardopts +3 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +37 -0
  9. data/Rakefile +6 -0
  10. data/bin/pfm +8 -0
  11. data/docs/GettingStarted.md +299 -0
  12. data/idlc-sdk-pfm.gemspec +44 -0
  13. data/lib/idlc-sdk-pfm/builtin_commands.rb +11 -0
  14. data/lib/idlc-sdk-pfm/cli.rb +150 -0
  15. data/lib/idlc-sdk-pfm/command/apply.rb +71 -0
  16. data/lib/idlc-sdk-pfm/command/base.rb +195 -0
  17. data/lib/idlc-sdk-pfm/command/build.rb +120 -0
  18. data/lib/idlc-sdk-pfm/command/configure.rb +41 -0
  19. data/lib/idlc-sdk-pfm/command/destroy.rb +61 -0
  20. data/lib/idlc-sdk-pfm/command/exec.rb +24 -0
  21. data/lib/idlc-sdk-pfm/command/format.rb +64 -0
  22. data/lib/idlc-sdk-pfm/command/generate.rb +83 -0
  23. data/lib/idlc-sdk-pfm/command/generator_commands/base.rb +50 -0
  24. data/lib/idlc-sdk-pfm/command/generator_commands/server_build.rb +58 -0
  25. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/Berksfile +3 -0
  26. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/build_cookbook/.kitchen.yml +21 -0
  27. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/build_cookbook/README.md +146 -0
  28. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/build_cookbook/test-fixture-recipe.rb +8 -0
  29. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/chefignore +107 -0
  30. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/cookbook_readmes/README-policy.md +9 -0
  31. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/cookbook_readmes/README.md +54 -0
  32. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/delivery-config.json +12 -0
  33. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/delivery-project.toml +36 -0
  34. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/gitignore +21 -0
  35. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/README.md +24 -0
  36. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/README.md +27 -0
  37. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +7 -0
  38. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/metadata.rb +6 -0
  39. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +8 -0
  40. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/data_bags/README.md +56 -0
  41. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/data_bags/example/example_item.json +4 -0
  42. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/dot-chef-repo.txt +6 -0
  43. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/environments/README.md +9 -0
  44. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/environments/example.json +13 -0
  45. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/policies/README.md +24 -0
  46. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/roles/README.md +9 -0
  47. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/repo/roles/example.json +13 -0
  48. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/spec_helper.rb +2 -0
  49. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/files/default/spec_helper_policyfile.rb +2 -0
  50. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/metadata.rb +7 -0
  51. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/app.rb +89 -0
  52. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/attribute.rb +12 -0
  53. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/build_cookbook.rb +182 -0
  54. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/cookbook.rb +144 -0
  55. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/cookbook_file.rb +24 -0
  56. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/lwrp.rb +23 -0
  57. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/policyfile.rb +8 -0
  58. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/recipe.rb +51 -0
  59. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/repo.rb +67 -0
  60. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/recipes/template.rb +32 -0
  61. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.all_rights.erb +3 -0
  62. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.apachev2.erb +201 -0
  63. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.gplv2.erb +339 -0
  64. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.gplv3.erb +674 -0
  65. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/LICENSE.mit.erb +21 -0
  66. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/Policyfile.rb.erb +25 -0
  67. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/README.md.erb +4 -0
  68. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/attribute.rb.erb +0 -0
  69. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/build_cookbook/Berksfile.erb +7 -0
  70. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/build_cookbook/metadata.rb.erb +10 -0
  71. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/build_cookbook/recipe.rb.erb +8 -0
  72. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/cookbook_file.erb +0 -0
  73. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/inspec_default_test.rb.erb +18 -0
  74. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/kitchen.yml.erb +26 -0
  75. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/kitchen_policyfile.yml.erb +33 -0
  76. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/metadata.rb.erb +20 -0
  77. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/provider.rb.erb +0 -0
  78. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/recipe.rb.erb +5 -0
  79. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/recipe_spec.rb.erb +22 -0
  80. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/repo/gitignore.erb +128 -0
  81. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/resource.rb.erb +0 -0
  82. data/lib/idlc-sdk-pfm/command/generator_commands/skeletons/code_generator/templates/default/template.erb +0 -0
  83. data/lib/idlc-sdk-pfm/command/generator_commands.rb +34 -0
  84. data/lib/idlc-sdk-pfm/command/plan.rb +80 -0
  85. data/lib/idlc-sdk-pfm/command/templates/app/files/config/client.rb.template +9 -0
  86. data/lib/idlc-sdk-pfm/command/templates/app/files/config/init.ps1.userdata +16 -0
  87. data/lib/idlc-sdk-pfm/command/templates/base/files/config/client.rb.template +6 -0
  88. data/lib/idlc-sdk-pfm/command/templates/base/files/config/init.ps1.userdata +219 -0
  89. data/lib/idlc-sdk-pfm/command/validate.rb +85 -0
  90. data/lib/idlc-sdk-pfm/command/validator_commands/base.rb +65 -0
  91. data/lib/idlc-sdk-pfm/command/validator_commands/infrastructure.rb +46 -0
  92. data/lib/idlc-sdk-pfm/command/validator_commands/server_build.rb +135 -0
  93. data/lib/idlc-sdk-pfm/command/validator_commands.rb +32 -0
  94. data/lib/idlc-sdk-pfm/commands_map.rb +61 -0
  95. data/lib/idlc-sdk-pfm/generator.rb +52 -0
  96. data/lib/idlc-sdk-pfm/helpers.rb +49 -0
  97. data/lib/idlc-sdk-pfm/settings.rb +205 -0
  98. data/lib/idlc-sdk-pfm/validator.rb +52 -0
  99. data/lib/idlc-sdk-pfm/version.rb +3 -0
  100. data/lib/idlc-sdk-pfm.rb +24 -0
  101. 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