mixlib-install 0.8.0.alpha.2 → 0.8.0.alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -2
  3. data/Rakefile +5 -0
  4. data/acceptance/Gemfile +3 -1
  5. data/acceptance/Gemfile.lock +37 -5
  6. data/acceptance/current/.acceptance/acceptance-cookbook/recipes/provision.rb +3 -1
  7. data/acceptance/current/.kitchen.yml +18 -23
  8. data/acceptance/unstable/.acceptance/acceptance-cookbook/.gitignore +2 -0
  9. data/acceptance/unstable/.acceptance/acceptance-cookbook/metadata.rb +1 -0
  10. data/acceptance/unstable/.acceptance/acceptance-cookbook/recipes/destroy.rb +3 -0
  11. data/acceptance/unstable/.acceptance/acceptance-cookbook/recipes/provision.rb +3 -0
  12. data/acceptance/unstable/.acceptance/acceptance-cookbook/recipes/verify.rb +3 -0
  13. data/acceptance/unstable/.kitchen.yml +40 -0
  14. data/lib/mixlib/install.rb +35 -3
  15. data/lib/mixlib/install/backend/artifactory.rb +108 -34
  16. data/lib/mixlib/install/backend/omnitruck.rb +2 -2
  17. data/lib/mixlib/install/generator.rb +6 -1
  18. data/lib/mixlib/install/generator/base.rb +65 -0
  19. data/lib/mixlib/install/generator/bourne.rb +23 -14
  20. data/lib/mixlib/install/generator/bourne/scripts/artifactory_urls.sh.erb +31 -0
  21. data/lib/mixlib/install/generator/bourne/scripts/{fetch_metadata.sh → fetch_metadata.sh.erb} +1 -1
  22. data/lib/mixlib/install/generator/bourne/scripts/helpers.sh +7 -2
  23. data/lib/mixlib/install/generator/bourne/scripts/platform_detection.sh +8 -0
  24. data/lib/mixlib/install/generator/bourne/scripts/script_cli_parameters.sh +36 -0
  25. data/lib/mixlib/install/generator/powershell.rb +94 -0
  26. data/lib/mixlib/install/generator/powershell/scripts/get_project_metadata.ps1.erb +87 -0
  27. data/lib/mixlib/install/generator/powershell/scripts/get_project_metadata_for_artifactory.ps1.erb +83 -0
  28. data/lib/mixlib/install/generator/powershell/scripts/helpers.ps1 +69 -0
  29. data/lib/mixlib/install/generator/powershell/scripts/install_project.ps1 +96 -0
  30. data/lib/mixlib/install/options.rb +86 -23
  31. data/lib/mixlib/install/version.rb +1 -1
  32. metadata +17 -4
@@ -0,0 +1,83 @@
1
+ function Get-ProjectMetadata {
2
+ <#
3
+ .SYNOPSIS
4
+ Get metadata for a Chef Software, Inc. project
5
+ .DESCRIPTION
6
+ Get metadata for project
7
+ .EXAMPLE
8
+ iex (new-object net.webclient).downloadstring('https:/omnitruck.chef.io/install.ps1'); Get-ProjectMetadata -project chef -channel stable
9
+
10
+ Gets the download url, MD5 checksum, and SHA256 checksum for the latest stable release of Chef.
11
+ .EXAMPLE
12
+ iex (irm 'https://omnitruck.chef.io/install.ps1'); Get-ProjectMetadata -project chefdk -channel stable -version 0.8.0
13
+
14
+ Gets the download url, MD5 checksum, and SHA256 checksum for ChefDK 0.8.0.
15
+ #>
16
+ [cmdletbinding()]
17
+ param (
18
+ # Base url to retrieve metadata from.
19
+ [uri]$base_server_uri = '<%= base_url %>',
20
+ [string]
21
+ # Project to install
22
+ # chef - Chef Client
23
+ # chefdk - Chef Development Kit
24
+ # angrychef - AngryChef
25
+ # server and container are not valid windows targets
26
+ [validateset('chef', 'chefdk', 'angrychef')]
27
+ [string]
28
+ $project = 'chef',
29
+ # Version of the application to install
30
+ # This parameter is optional, if not supplied it will provide the latest version,
31
+ # and if an iteration number is not specified, it will grab the latest available iteration.
32
+ # Partial version numbers are also acceptable (using v=11
33
+ # will grab the latest 11.x client which matches the other flags).
34
+ [string]
35
+ $version,
36
+ # Release channel to install from
37
+ $channel = 'unstable',
38
+ # The following legacy switches are just aliases for the current channel
39
+ [switch]
40
+ $prerelease,
41
+ [switch]
42
+ $nightlies
43
+ )
44
+
45
+ # PowerShell is only on Windows ATM
46
+ $platform = 'windows'
47
+ Write-Verbose "Platform: $platform"
48
+
49
+ # TODO: No Win10 build endpoint yet
50
+ switch -regex ((get-wmiobject win32_operatingsystem).version) {
51
+ '10\.0\.\d+' {$platform_version = '2012r2'}
52
+ '6\.3\.\d+' {$platform_version = '2012r2'}
53
+ '6\.2\.\d+' {$platform_version = '2012'}
54
+ '6\.1\.\d+' {$platform_version = '2008r2'}
55
+ '6\.0\.\d+' {$platform_version = '2008'}
56
+ }
57
+ Write-Verbose "Platform Version: $platform_version"
58
+
59
+ # TODO: When we ship a 64 bit ruby for Windows.
60
+ $machine = 'i386'
61
+ Write-Verbose "Machine: $machine"
62
+ Write-Verbose "Project: $project"
63
+
64
+ <% artifacts.each do |artifact| %>
65
+ $artifact_info_dir = "$($env:temp)/artifact_info/<%= File.join(artifact.platform, artifact.platform_version, artifact.architecture)%>"
66
+ New-Item -ItemType directory -Path $artifact_info_dir -force
67
+ New-Item -ItemType file "$($artifact_info_dir)/artifact_info" -force
68
+ "url <%= artifact.url%>" | out-file "$artifact_info_dir/artifact_info"
69
+ "md5 <%= artifact.md5%>" | out-file "$artifact_info_dir/artifact_info" -Append
70
+ "sha256 <%= artifact.sha256%>" | out-file "$artifact_info_dir/artifact_info" -Append
71
+ <% end %>
72
+
73
+ $artifact_info_for_platform = Get-Content "$($env:temp)/artifact_info/$($platform)/$($platform_version)/$($machine)/artifact_info"
74
+
75
+ $package_metadata = ($artifact_info_for_platform).trim() -split '\n' |
76
+ foreach { $hash = @{} } {$key, $value = $_ -split '\s+'; $hash.Add($key, $value)} {$hash}
77
+
78
+ Write-Verbose "Project details: "
79
+ foreach ($key in $package_metadata.keys) {
80
+ Write-Verbose "`t$key = $($package_metadata[$key])"
81
+ }
82
+ $package_metadata
83
+ }
@@ -0,0 +1,69 @@
1
+ function New-Uri {
2
+ param ($baseuri, $newuri)
3
+
4
+ new-object System.Uri $baseuri, $newuri
5
+ }
6
+
7
+ function Get-WebContent {
8
+ param ($uri, $filepath)
9
+ $proxy = New-Object -TypeName System.Net.WebProxy
10
+ $wc = new-object System.Net.WebClient
11
+ $proxy.Address = $env:http_proxy
12
+ $wc.Proxy = $proxy
13
+
14
+ try {
15
+ if ([string]::IsNullOrEmpty($filepath)) {
16
+ $wc.downloadstring($uri)
17
+ }
18
+ else {
19
+ $wc.downloadfile($uri, $filepath)
20
+ }
21
+ }
22
+ catch {
23
+ $exception = $_.Exception
24
+ Write-Host "There was an error: "
25
+ do {
26
+ Write-Host "`t$($exception.message)"
27
+ $exception = $exception.innerexception
28
+ } while ($exception)
29
+ throw "Failed to download from $uri."
30
+ }
31
+ }
32
+
33
+ function Test-ProjectPackage {
34
+ [cmdletbinding()]
35
+ param ($Path, $Algorithm = 'SHA256', $Hash)
36
+
37
+ if (-not (get-command get-filehash)) {
38
+ function disposable($o){($o -is [IDisposable]) -and (($o | get-member | foreach-object {$_.name}) -contains 'Dispose')}
39
+ function use($obj, [scriptblock]$sb){try {& $sb} catch [exception]{throw $_} finally {if (disposable $obj) {$obj.Dispose()}} }
40
+ function Get-FileHash ($Path, $Algorithm) {
41
+ $Path = (resolve-path $path).providerpath
42
+ $hash = @{Algorithm = $Algorithm; Path = $Path}
43
+ if ($Algorithm -like 'MD5') {
44
+ use ($c = New-Object -TypeName Security.Cryptography.MD5CryptoServiceProvider) {
45
+ use ($in = (gi $path).OpenRead()) {
46
+ $hash.Hash = ([BitConverter]::ToString($c.ComputeHash($in))).Replace("-", "").ToUpper()
47
+ }
48
+ }
49
+ }
50
+ elseif ($Algorithm -like 'SHA256') {
51
+ use ($c = New-Object -TypeName Security.Cryptography.SHA256CryptoServiceProvider) {
52
+ use ($in = (gi $path).OpenRead()) {
53
+ $hash.Hash = ([BitConverter]::ToString($c.ComputeHash($in))).Replace("-", "").ToUpper()
54
+ }
55
+ }
56
+ }
57
+ new-object PSObject -Property $hash
58
+ }
59
+ }
60
+ Write-Verbose "Testing the $Algorithm hash for $path."
61
+ $ActualHash = (Get-FileHash -Algorithm $Algorithm -Path $Path).Hash.ToLower()
62
+ Write-Verbose "`tDesired Hash - '$hash'"
63
+ Write-Verbose "`tActual Hash - '$ActualHash'"
64
+ $Valid = $ActualHash -eq $Hash
65
+ if (-not $Valid) {
66
+ Write-Error "Failed to validate the downloaded installer. The expected $Algorithm hash was '$Hash' and the actual hash was '$ActualHash' for $path"
67
+ }
68
+ return $Valid
69
+ }
@@ -0,0 +1,96 @@
1
+ function Install-Project {
2
+ <#
3
+ .SYNOPSIS
4
+ Install a Chef Software, Inc. product
5
+ .DESCRIPTION
6
+ Install a Chef Software, Inc. product
7
+ .EXAMPLE
8
+ iex (new-object net.webclient).downloadstring('https:/omnitruck.chef.io/install.ps1'); Install-Project -project chef -channel stable
9
+
10
+ Installs the latest stable version of Chef.
11
+ .EXAMPLE
12
+ iex (irm 'https://omnitruck.chef.io/install.ps1'); Install-Project -project chefdk -channel current
13
+
14
+ Installs the latest integration build of the Chef Development Kit
15
+ #>
16
+ [cmdletbinding(SupportsShouldProcess=$true)]
17
+ param (
18
+ # Project to install
19
+ # chef - Chef Client
20
+ # chefdk - Chef Development Kit
21
+ # angrychef - AngryChef
22
+ # server and container are not valid windows targets
23
+ [validateset('chef', 'chefdk', 'angrychef')]
24
+ [string]
25
+ $project = 'chef',
26
+ # Release channel to install from
27
+ [validateset('current', 'stable', 'unstable')]
28
+ [string]
29
+ $channel = 'stable',
30
+ # Version of the application to install
31
+ # This parameter is optional, if not supplied it will provide the latest version,
32
+ # and if an iteration number is not specified, it will grab the latest available iteration.
33
+ # Partial version numbers are also acceptable (using v=11
34
+ # will grab the latest 11.x client which matches the other flags).
35
+ [string]
36
+ $version,
37
+ # Full path for the downloaded installer.
38
+ [string]
39
+ $filename,
40
+ # Full path to the location to download the installer
41
+ [string]
42
+ $download_directory = $env:temp,
43
+ # The following legacy switches are just aliases for the current channel
44
+ [switch]
45
+ $prerelease,
46
+ [switch]
47
+ $nightlies
48
+ )
49
+
50
+ $package_metadata = Get-ProjectMetadata -project $project -channel $channel -version $version -prerelease:$prerelease -nightlies:$nightlies
51
+
52
+ if (-not [string]::IsNullOrEmpty($filename)) {
53
+ $download_directory = split-path $filename
54
+ $filename = split-path $filename -leaf
55
+ if ([string]::IsNullOrEmpty($download_directory)) {
56
+ $download_directory = $pwd
57
+ }
58
+ }
59
+ else {
60
+ $filename = ($package_metadata.url -split '/')[-1]
61
+ }
62
+ Write-Verbose "Download directory: $download_directory"
63
+ Write-Verbose "Filename: $filename"
64
+
65
+ if (-not (test-path $download_directory)) {
66
+ mkdir $download_directory
67
+ }
68
+ $download_directory = (resolve-path $download_directory).providerpath
69
+ $download_destination = join-path $download_directory $filename
70
+
71
+ if ((test-path $download_destination) -and
72
+ (Test-ProjectPackage -Path $download_destination -Algorithm 'SHA256' -Hash $package_metadata.sha256 -ea SilentlyContinue)){
73
+ Write-Verbose "Found existing valid installer at $download_destination."
74
+ }
75
+ else {
76
+ if ($pscmdlet.ShouldProcess("$($package_metadata.url)", "Download $project")) {
77
+ Write-Verbose "Downloading $project from $($package_metadata.url) to $download_destination."
78
+ Get-WebContent $package_metadata.url -filepath $download_destination
79
+ }
80
+ }
81
+
82
+ if ($pscmdlet.ShouldProcess("$download_destination", "Installing")){
83
+ if (Test-ProjectPackage -Path $download_destination -Algorithm 'SHA256' -Hash $package_metadata.sha256) {
84
+ Write-Host "Installing $project from $download_destination"
85
+ $p = Start-Process -FilePath "msiexec" -ArgumentList "/qn /i $download_destination" -Passthru -Wait
86
+ if ($p.ExitCode -ne 0) {
87
+ throw "msiexec was not successful. Received exit code $($p.ExitCode)"
88
+ }
89
+ }
90
+ else {
91
+ throw "Failed to validate the downloaded installer for $project."
92
+ }
93
+ }
94
+ }
95
+ set-alias install -value Install-Project
96
+ export-modulemember -function 'Install-Project','Get-ProjectMetadata' -alias 'install'
@@ -16,41 +16,62 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
+ require "mixlib/versioning"
20
+
19
21
  module Mixlib
20
22
  class Install
21
23
  class Options
22
24
  class InvalidOptions < ArgumentError; end
25
+ class ArtifactoryCredentialsNotFound < StandardError; end
23
26
 
24
27
  attr_reader :options
25
- attr_reader :errors
28
+ attr_reader :defaults
26
29
 
27
30
  OMNITRUCK_CHANNELS = [:stable, :current]
28
31
  ARTIFACTORY_CHANNELS = [:unstable]
29
32
  ALL_SUPPORTED_CHANNELS = OMNITRUCK_CHANNELS + ARTIFACTORY_CHANNELS
30
33
  SUPPORTED_PRODUCT_NAMES = %w[chef chefdk]
31
- SUPPORTED_OPTIONS = [:channel, :product_name, :product_version,
32
- :platform, :platform_version, :architecture]
34
+ SUPPORTED_SHELL_TYPES = [:ps1, :sh]
35
+ SUPPORTED_OPTIONS = [
36
+ :architecture,
37
+ :channel,
38
+ :platform,
39
+ :platform_version,
40
+ :product_name,
41
+ :product_version,
42
+ :shell_type
43
+ ]
33
44
 
34
45
  def initialize(options)
35
46
  @options = options
36
- @errors = []
47
+ @defaults = {
48
+ shell_type: :sh
49
+ }
50
+
51
+ validate!
52
+ end
53
+
54
+ def validate!
37
55
  validate_options!
56
+ validate_unstable_channel! if for_artifactory?
38
57
  end
39
58
 
40
59
  def validate_options!
41
- validate_product_names
42
- validate_channels
43
- validate_unstable_version
44
- validate_platform_info
60
+ errors = []
61
+
62
+ errors << validate_product_names
63
+ errors << validate_channels
64
+ errors << validate_platform_info
65
+ errors << validate_shell_type
45
66
 
46
- unless errors.empty?
67
+ unless errors.compact.empty?
47
68
  raise InvalidOptions, errors.join("\n")
48
69
  end
49
70
  end
50
71
 
51
72
  SUPPORTED_OPTIONS.each do |option|
52
73
  define_method option do
53
- options[option] || options[option.to_s]
74
+ options[option] || options[option.to_s] || defaults[option]
54
75
  end
55
76
  end
56
77
 
@@ -62,26 +83,48 @@ module Mixlib
62
83
  OMNITRUCK_CHANNELS.include?(channel)
63
84
  end
64
85
 
86
+ def for_ps1?
87
+ platform == "windows" || shell_type == :ps1
88
+ end
89
+
90
+ def latest_version?
91
+ product_version.to_sym == :latest
92
+ end
93
+
94
+ def resolved_version(artifacts)
95
+ @resolved_version ||= begin
96
+ if latest_version?
97
+ all_versions = artifacts.collect(&:version)
98
+ # params: list of all versions, no version filtering, no pre-releases, use build version
99
+ Mixlib::Versioning.find_target_version(
100
+ all_versions,
101
+ nil,
102
+ false,
103
+ true
104
+ ).to_s
105
+ else
106
+ product_version
107
+ end
108
+ end
109
+ end
110
+
65
111
  private
66
112
 
67
113
  def validate_product_names
68
114
  unless SUPPORTED_PRODUCT_NAMES.include? product_name
69
- errors << "Unknown product name #{product_name}. \
70
- Must be one of: #{SUPPORTED_PRODUCT_NAMES.join(", ")}"
115
+ <<-EOS
116
+ Unknown product name #{product_name}.
117
+ Must be one of: #{SUPPORTED_PRODUCT_NAMES.join(", ")}
118
+ EOS
71
119
  end
72
120
  end
73
121
 
74
122
  def validate_channels
75
123
  unless ALL_SUPPORTED_CHANNELS.include? channel
76
- errors << "Unknown channel #{channel}. \
77
- Must be one of: #{ALL_SUPPORTED_CHANNELS.join(", ")}"
78
- end
79
- end
80
-
81
- def validate_unstable_version
82
- if for_artifactory? && product_version !~ /^\d+.\d+.\d+\+[0-9]{14}$/
83
- errors << "Version must match pattern '1.2.3+12345678901234' when \
84
- using channels #{ARTIFACTORY_CHANNELS.join(", ")}"
124
+ <<-EOS
125
+ Unknown channel #{channel}.
126
+ Must be one of: #{ALL_SUPPORTED_CHANNELS.join(", ")}
127
+ EOS
85
128
  end
86
129
  end
87
130
 
@@ -89,8 +132,28 @@ using channels #{ARTIFACTORY_CHANNELS.join(", ")}"
89
132
  platform_opts = [platform, platform_version, architecture]
90
133
  if (platform_opts.any?(&:nil?)) &&
91
134
  (platform_opts.any? { |opt| !opt.nil? })
92
- errors << "platform, platform version, and architecture are all \
93
- required when specifying Platform options."
135
+ <<-EOS
136
+ platform, platform version, and architecture are all required when specifying Platform options.
137
+ EOS
138
+ end
139
+ end
140
+
141
+ def validate_shell_type
142
+ unless SUPPORTED_SHELL_TYPES.include? shell_type
143
+ <<-EOS
144
+ Unknown shell type.
145
+ Must be one of: #{SUPPORTED_SHELL_TYPES.join(", ")}
146
+ EOS
147
+ end
148
+ end
149
+
150
+ def validate_unstable_channel!
151
+ if ENV["ARTIFACTORY_USERNAME"].nil? || ENV["ARTIFACTORY_PASSWORD"].nil?
152
+ raise ArtifactoryCredentialsNotFound,
153
+ <<-EOS
154
+ Must set ARTIFACTORY_USERNAME and ARTIFACTORY_PASSWORD environment variables
155
+ when using the unstable channel.
156
+ EOS
94
157
  end
95
158
  end
96
159
  end
@@ -1,5 +1,5 @@
1
1
  module Mixlib
2
2
  class Install
3
- VERSION = "0.8.0.alpha.2"
3
+ VERSION = "0.8.0.alpha.3"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixlib-install
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0.alpha.2
4
+ version: 0.8.0.alpha.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thom May
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-04 00:00:00.000000000 Z
12
+ date: 2015-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: artifactory
@@ -121,18 +121,32 @@ files:
121
121
  - acceptance/current/.acceptance/acceptance-cookbook/recipes/provision.rb
122
122
  - acceptance/current/.acceptance/acceptance-cookbook/recipes/verify.rb
123
123
  - acceptance/current/.kitchen.yml
124
+ - acceptance/unstable/.acceptance/acceptance-cookbook/.gitignore
125
+ - acceptance/unstable/.acceptance/acceptance-cookbook/metadata.rb
126
+ - acceptance/unstable/.acceptance/acceptance-cookbook/recipes/destroy.rb
127
+ - acceptance/unstable/.acceptance/acceptance-cookbook/recipes/provision.rb
128
+ - acceptance/unstable/.acceptance/acceptance-cookbook/recipes/verify.rb
129
+ - acceptance/unstable/.kitchen.yml
124
130
  - lib/mixlib/install.rb
125
131
  - lib/mixlib/install/artifact_info.rb
126
132
  - lib/mixlib/install/backend.rb
127
133
  - lib/mixlib/install/backend/artifactory.rb
128
134
  - lib/mixlib/install/backend/omnitruck.rb
129
135
  - lib/mixlib/install/generator.rb
136
+ - lib/mixlib/install/generator/base.rb
130
137
  - lib/mixlib/install/generator/bourne.rb
131
- - lib/mixlib/install/generator/bourne/scripts/fetch_metadata.sh
138
+ - lib/mixlib/install/generator/bourne/scripts/artifactory_urls.sh.erb
139
+ - lib/mixlib/install/generator/bourne/scripts/fetch_metadata.sh.erb
132
140
  - lib/mixlib/install/generator/bourne/scripts/fetch_package.sh
133
141
  - lib/mixlib/install/generator/bourne/scripts/helpers.sh
134
142
  - lib/mixlib/install/generator/bourne/scripts/install_package.sh
135
143
  - lib/mixlib/install/generator/bourne/scripts/platform_detection.sh
144
+ - lib/mixlib/install/generator/bourne/scripts/script_cli_parameters.sh
145
+ - lib/mixlib/install/generator/powershell.rb
146
+ - lib/mixlib/install/generator/powershell/scripts/get_project_metadata.ps1.erb
147
+ - lib/mixlib/install/generator/powershell/scripts/get_project_metadata_for_artifactory.ps1.erb
148
+ - lib/mixlib/install/generator/powershell/scripts/helpers.ps1
149
+ - lib/mixlib/install/generator/powershell/scripts/install_project.ps1
136
150
  - lib/mixlib/install/options.rb
137
151
  - lib/mixlib/install/product.rb
138
152
  - lib/mixlib/install/script_generator.rb
@@ -166,4 +180,3 @@ signing_key:
166
180
  specification_version: 4
167
181
  summary: A mixin to help with omnitruck installs
168
182
  test_files: []
169
- has_rdoc: