knife-artifactory 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d57af63a2e4d97bd447477bd0ae1a3fe8dd4e10fff29f98e249a2c3945aa2b28
4
- data.tar.gz: 9deb1ef44897e7c12fe6a0ec4e440809d55df05a70d662f1008d1734a45447e2
3
+ metadata.gz: 87c86116d7a6ea38d43bdef6c785a84a332195886cb5ae80bcdac8c22df38ae5
4
+ data.tar.gz: 72f5782c99a6684a147090c9e2bedc8623beefc715077d1cbb38d9097599e4a6
5
5
  SHA512:
6
- metadata.gz: abff25d20f732130844ad178c00cf8a7149251220c3efd470405dd4111692812d8b31f6916a251978a7a772548beb3596244cf09b3fa5aba731aaed82fa01d8b
7
- data.tar.gz: 11575c085633e4bfd13fecd9a39e00a4728dee1fed23a5107224b388afc7e33f9d6d4ab2baeb8bf5025d2d97c620e8706e8360c41e6f233fde41bfdf15e566af
6
+ metadata.gz: 50d717bf5443e36954f1109464ed7ba7b538cea20ca533c57768352ed17aeb9ce495af2461f65eec8dcd0ad7421cada25a213b9579268fde9eec960c1504acf5
7
+ data.tar.gz: 697352d1bc0e7b90c87146df58e10a7dec0cf5cf88d7a3e4ecde748844f54cd956a9228f11dac81e3b1bf0699f9d8e6fc4be042834182662f44727951f639251
@@ -1,15 +1,15 @@
1
- # Overrides the default Chef::Knife::CookbookSiteShare to allow basic authentication against an Artifactory backend.
1
+ # Overrides the default Chef::Knife::SupermarketShare to allow basic authentication against an Artifactory backend.
2
2
  # Ideally we would like to use a mechanism that allows injecting pluggable authentication middleware into the Chef::Http
3
3
  # REST clients, but in the interest of allowing not-only-newest knife client versions to work with Artifactory we chose
4
4
  # this solution for now.
5
5
 
6
- require 'chef/knife'
7
- require 'chef/knife/cookbook_site_download'
8
- require 'knife-artifactory/utils'
6
+ require "chef/knife"
7
+ require "chef/knife/cookbook_site_download"
8
+ require "knife-artifactory/utils"
9
9
 
10
10
  class Chef
11
11
  class Knife
12
- class ArtifactoryDownload < Knife::CookbookSiteDownload
12
+ class ArtifactoryDownload < Knife::SupermarketDownload
13
13
 
14
14
  dependency_loaders.concat(superclass.dependency_loaders)
15
15
  options.merge!(superclass.options)
@@ -32,7 +32,7 @@ class Chef
32
32
 
33
33
  def current_cookbook_data
34
34
  unless config[:artifactory_download]
35
- Chef::Log.debug('[KNIFE-ART] ArtifactoryDownload::current_cookbook_data called without artifactory flag, delegating to super')
35
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryDownload::current_cookbook_data called without artifactory flag, delegating to super")
36
36
  return orig_current_cookbook_data
37
37
  end
38
38
  @current_cookbook_data ||= begin
@@ -42,15 +42,15 @@ class Chef
42
42
 
43
43
  def desired_cookbook_data
44
44
  unless config[:artifactory_download]
45
- Chef::Log.debug('[KNIFE-ART] ArtifactoryDownload::desired_cookbook_data called without artifactory flag, delegating to super')
45
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryDownload::desired_cookbook_data called without artifactory flag, delegating to super")
46
46
  return orig_desired_cookbook_data
47
47
  end
48
48
  @desired_cookbook_data ||= begin
49
- uri = if @name_args.length == 1
50
- current_cookbook_data["latest_version"]
51
- else
52
- specific_cookbook_version_url
53
- end
49
+ uri = if @name_args.length == 1
50
+ current_cookbook_data["latest_version"]
51
+ else
52
+ specific_cookbook_version_url
53
+ end
54
54
 
55
55
  noauth_rest.get(uri, auth_header)
56
56
  end
@@ -58,7 +58,7 @@ class Chef
58
58
 
59
59
  def download_cookbook
60
60
  unless config[:artifactory_download]
61
- Chef::Log.debug('[KNIFE-ART] ArtifactoryDownload::download_cookbook called without artifactory flag, delegating to super')
61
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryDownload::download_cookbook called without artifactory flag, delegating to super")
62
62
  return orig_download_cookbook
63
63
  end
64
64
  ui.info "Downloading #{@name_args[0]} from Supermarket at version #{version} to #{download_location}"
@@ -70,7 +70,7 @@ class Chef
70
70
 
71
71
  def auth_header
72
72
  @auth_header ||= begin
73
- ::Knife::KnifeArt::KnifeArtUtils.auth_header_from(cookbooks_api_url)
73
+ ::KnifeArtifactory::Utils.auth_header_from(cookbooks_api_url)
74
74
  end
75
75
  end
76
76
 
@@ -1,15 +1,14 @@
1
- # Overrides the default Chef::Knife::CookbookSiteInstall to allow basic authentication against an Artifactory backend.
1
+ # Overrides the default Chef::Knife::SupermarketInstall to allow basic authentication against an Artifactory backend.
2
2
  # Ideally we would like to use a mechanism that allows injecting pluggable authentication middleware into the Chef::Http
3
3
  # REST clients, but in the interest of allowing not-only-newest knife client versions to work with Artifactory we chose
4
4
  # this solution for now.
5
5
 
6
-
7
- require 'chef/knife'
8
- require 'chef/knife/cookbook_site_install'
6
+ require "chef/knife"
7
+ require "chef/knife/cookbook_site_install"
9
8
 
10
9
  class Chef
11
10
  class Knife
12
- class ArtifactoryInstall < Knife::CookbookSiteInstall
11
+ class ArtifactoryInstall < Knife::SupermarketInstall
13
12
 
14
13
  dependency_loaders.concat(superclass.dependency_loaders)
15
14
  options.merge!(superclass.options)
@@ -30,7 +29,7 @@ class Chef
30
29
 
31
30
  def download_cookbook_to(download_path)
32
31
  unless config[:artifactory_install]
33
- Chef::Log.debug('[KNIFE-ART] ArtifactoryInstall::download_cookbook_to called without artifactory flag, delegating to super')
32
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryInstall::download_cookbook_to called without artifactory flag, delegating to super")
34
33
  return orig_download_cookbook_to(download_path)
35
34
  end
36
35
  downloader = Chef::Knife::ArtifactoryDownload.new
@@ -1,10 +1,10 @@
1
1
 
2
- require 'chef/knife'
3
- require 'chef/knife/cookbook_site_list'
2
+ require "chef/knife"
3
+ require "chef/knife/cookbook_site_list"
4
4
 
5
5
  class Chef
6
6
  class Knife
7
- class ArtifactoryList < Knife::CookbookSiteList
7
+ class ArtifactoryList < Knife::SupermarketList
8
8
 
9
9
  dependency_loaders.concat(superclass.dependency_loaders)
10
10
  options.merge!(superclass.options)
@@ -1,10 +1,10 @@
1
1
 
2
- require 'chef/knife'
3
- require 'chef/knife/cookbook_site_search'
2
+ require "chef/knife"
3
+ require "chef/knife/cookbook_site_search"
4
4
 
5
5
  class Chef
6
6
  class Knife
7
- class ArtifactorySearch < Knife::CookbookSiteSearch
7
+ class ArtifactorySearch < Knife::SupermarketSearch
8
8
 
9
9
  dependency_loaders.concat(superclass.dependency_loaders)
10
10
  options.merge!(superclass.options)
@@ -2,19 +2,18 @@
2
2
  # 1. allow passing flags to the super class so that the do_upload method of this
3
3
  # class is called and that signing key verification is skipped by the underlying Chef::HTTP::Authenticator that's
4
4
  # used with the rest client (see comment below).
5
- # 2. Override (monkey patch) the required methods in Chef::HTTP::Authenticator and Knife::CookbookSiteShare
5
+ # 2. Override (monkey patch) the required methods in Chef::HTTP::Authenticator and Knife::SupermarketShare
6
6
  # to allow inserting our own logic that deploys a cookbook to Artifactory.
7
7
  #
8
8
  # The Supermarket API is kept (post /api/v1/cookbooks/cookbook_name) by Artifactory although it does not currently
9
9
  # return a correct response (it simply returns 200) due to performance considerations.
10
10
 
11
-
12
- require 'chef/knife'
13
- require 'chef/knife/cookbook_site_share'
11
+ require "chef/knife"
12
+ require "chef/knife/cookbook_site_share"
14
13
 
15
14
  class Chef
16
15
  class Knife
17
- class ArtifactoryShare < Knife::CookbookSiteShare
16
+ class ArtifactoryShare < Knife::SupermarketShare
18
17
 
19
18
  dependency_loaders.concat(superclass.dependency_loaders)
20
19
  options.merge!(superclass.options)
@@ -22,34 +21,94 @@ class Chef
22
21
  banner "knife artifactory share COOKBOOK [CATEGORY] (options)"
23
22
  category "artifactory"
24
23
 
24
+ option :overwrite_cookbook,
25
+ long: "--[no-]overwrite-cookbook",
26
+ boolean: true,
27
+ default: true,
28
+ description: "Overwrite existing cookbook version if it already exists. Default is yes."
29
+
25
30
  alias_method :orig_run, :run
26
31
  alias_method :orig_get_category, :get_category
27
32
  alias_method :orig_do_upload, :do_upload
28
33
 
29
34
  def run
30
- begin
31
35
  # I'm forced to use threadlocal until we find a better solution... can't really find a way to pass configuration
32
36
  # down to the Chef::CookbookUploader, Chef::ServerAPI, Chef::HTTP or Chef::HTTP::Authenticator
33
37
  # (which are created one after another starting) with CookbookUploader to make it skip the signing key verification.
34
38
  # Can make the authenticator skip by passing load_signing_key(nil, nil) and opts[:sign_request] => false
35
- Thread.current[:artifactory_deploy] = 'yes'
39
+ Thread.current[:artifactory_deploy] = "yes"
36
40
  # Send artifactory deploy flag to super
37
41
  config[:artifactory_deploy] = true
38
42
  Chef::Log.debug("[KNIFE-ART] running site share with config: #{config}")
43
+
44
+ if !overwrite_cookbook? && cookbook_versions_in_artifactory.include?(cookbook_version)
45
+ ui.info("Cookbook version already exists, skipping upload.")
46
+ exit(0)
47
+ end
48
+
39
49
  orig_run
40
- ensure
50
+ ensure
41
51
  # always cleanup threadlocal
42
- Thread.current[:artifactory_deploy] = nil
52
+ Thread.current[:artifactory_deploy] = nil
53
+ end
54
+
55
+ #
56
+ # @example
57
+ # cookbook_versions_in_artifactory #=> ["1.0.0", "1.0.1", "1.1.0", "1.2.0"]
58
+ #
59
+ # @return [Array<String>] versions in artifactory
60
+ #
61
+ def cookbook_versions_in_artifactory
62
+ return [] if cookbook_name.nil?
63
+
64
+ data = noauth_rest.get("#{supermarket_uri}/cookbooks/#{cookbook_name}")
65
+ data["metrics"]["downloads"]["versions"].keys
66
+ end
67
+
68
+ #
69
+ # @example
70
+ # cookbook_version #=> 1.0.1
71
+ #
72
+ # @example
73
+ # cookbook_version #=> 0.1.0
74
+ #
75
+ # @example
76
+ # cookbook_version #=> nil
77
+ #
78
+ # @return [String, nil] version of cookbook present in cookbook path or nil if no
79
+ # coobook versions exist locally.
80
+ #
81
+ def cookbook_version
82
+ cl = Chef::CookbookLoader.new(cookbook_path)
83
+ if cl.cookbook_exists?(cookbook_name)
84
+ cookbook = cl[cookbook_name]
85
+ cookbook.version
43
86
  end
44
87
  end
45
88
 
46
89
  private
47
90
 
91
+ def cookbook_name
92
+ @name_args[0] if @name_args.length >= 1
93
+ end
94
+
95
+ def cookbook_path
96
+ config[:cookbook_path] ||= Chef::Config[:cookbook_path]
97
+ end
98
+
99
+ def supermarket_uri
100
+ "#{config[:supermarket_site]}/api/v1"
101
+ end
102
+
103
+ def overwrite_cookbook?
104
+ config[:overwrite_cookbook]
105
+ end
106
+
48
107
  # Pretty much copy paste of the original, just with authentication on the rest client...
49
108
  def get_category(cookbook_name)
50
109
  # Use Artifactory deployment logic only if flag sent by Artifactory plugin
51
110
  unless config[:artifactory_deploy]
52
- Chef::Log.debug('[KNIFE-ART] ArtifactoryShare::get_category called without artifactory flag, delegating to super')
111
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryShare::get_category called without artifactory flag, delegating to super")
53
112
  return orig_get_category(cookbook_name)
54
113
  end
55
114
  begin
@@ -57,7 +116,7 @@ class Chef
57
116
  if data.nil?
58
117
  return data["category"]
59
118
  else
60
- return 'Other'
119
+ return "Other"
61
120
  end
62
121
  rescue => e
63
122
  return "Other" if e.kind_of?(Net::HTTPServerException) && e.response.code == "404"
@@ -65,18 +124,17 @@ class Chef
65
124
  Chef::Log.debug("\n#{e.backtrace.join("\n")}")
66
125
  exit(1)
67
126
  end
68
-
69
127
  end
70
128
 
71
129
  def do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
72
130
  # Use Artifactory deployment logic only if flag sent by Artifactory plugin
73
131
  unless config[:artifactory_deploy]
74
- Chef::Log.debug('[KNIFE-ART] ArtifactoryShare::do_upload called without artifactory flag, delegating to super')
132
+ Chef::Log.debug("[KNIFE-ART] ArtifactoryShare::do_upload called without artifactory flag, delegating to super")
75
133
  orig_do_upload(cookbook_filename, cookbook_category, user_id, user_secret_filename)
76
134
  return
77
135
  end
78
136
  # cookbook_filename is set as tempDir/cookbook_name in parent
79
- cookbook_name = cookbook_filename.split('/')[-1]
137
+ cookbook_name = cookbook_filename.split("/")[-1]
80
138
  uri = "#{config[:supermarket_site]}/api/v1/cookbooks/#{cookbook_name}"
81
139
  uri += "?category=#{cookbook_category}" if cookbook_category
82
140
  Chef::Log.debug("[KNIFE-ART] Deploying cookbook #{cookbook_name} to Artifactory url at #{uri}")
@@ -85,7 +143,7 @@ class Chef
85
143
  # debug log will be able to show the response Artifactory returned in case of errors.
86
144
  file_contents = File.open(cookbook_filename, "rb") { |f| f.read }
87
145
  # no need to send auth header here, 'normal' HTTP client uses url with credentials from config
88
- rest.post(uri, file_contents, {"content-type" => "application/x-binary"})
146
+ rest.post(uri, file_contents, { "content-type" => "application/x-binary" })
89
147
  end
90
148
 
91
149
  end
@@ -101,11 +159,11 @@ class Chef
101
159
 
102
160
  def load_signing_key(key_file, raw_key = nil)
103
161
  Chef::Log.debug("[KNIFE-ART] global var: #{Thread.current[:artifactory_deploy]}")
104
- if Thread.current.key?(:artifactory_deploy) and Thread.current[:artifactory_deploy].eql? 'yes'
105
- Chef::Log.debug('[KNIFE-ART] Artifactory plugin substituting for Chef::Http::Authenticator --> omitting signing key usage')
162
+ if Thread.current.key?(:artifactory_deploy) && Thread.current[:artifactory_deploy].eql?("yes")
163
+ Chef::Log.debug("[KNIFE-ART] Artifactory plugin substituting for Chef::Http::Authenticator --> omitting signing key usage")
106
164
  @sign_request = false
107
- @raw_key = ''
108
- @key = ''
165
+ @raw_key = ""
166
+ @key = ""
109
167
  else
110
168
  # Artifactory flag not present, call original implementation
111
169
  orig_load_signing_key(key_file, raw_key)
@@ -1,10 +1,10 @@
1
1
 
2
- require 'chef/knife'
3
- require 'chef/knife/cookbook_site_show'
2
+ require "chef/knife"
3
+ require "chef/knife/cookbook_site_show"
4
4
 
5
5
  class Chef
6
6
  class Knife
7
- class ArtifactoryShow < Knife::CookbookSiteShow
7
+ class ArtifactoryShow < Knife::SupermarketShow
8
8
 
9
9
  dependency_loaders.concat(superclass.dependency_loaders)
10
10
  options.merge!(superclass.options)
@@ -1,7 +1,7 @@
1
1
  # More or less copy-pasted from cookbook_site_unshare because the http call happens inside the run method, not much
2
2
  # sense in extending it
3
3
 
4
- require 'chef/knife'
4
+ require "chef/knife"
5
5
 
6
6
  class Chef
7
7
  class Knife
@@ -15,11 +15,11 @@ class Chef
15
15
  category "artifactory"
16
16
 
17
17
  option :supermarket_site,
18
- :short => "-m SUPERMARKET_SITE",
19
- :long => "--supermarket-site SUPERMARKET_SITE",
20
- :description => "Supermarket Site",
21
- :default => "https://supermarket.chef.io",
22
- :proc => Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
18
+ short: "-m SUPERMARKET_SITE",
19
+ long: "--supermarket-site SUPERMARKET_SITE",
20
+ description: "Supermarket Site",
21
+ default: "https://supermarket.chef.io",
22
+ proc: Proc.new { |supermarket| Chef::Config[:knife][:supermarket_site] = supermarket }
23
23
 
24
24
  def run
25
25
  @cookbook_name = @name_args[0]
@@ -41,7 +41,7 @@ class Chef
41
41
  url = "#{cookbooks_api_url}/#{@cookbook_name}/#{@cookbook_version}"
42
42
  noauth_rest.delete(url, auth_header)
43
43
  rescue Net::HTTPServerException => e
44
- raise e unless (e.message =~ /Forbidden/ || e.message =~ /Unauthorized/)
44
+ raise e unless e.message =~ /Forbidden/ || e.message =~ /Unauthorized/
45
45
  ui.error "Forbidden: You must have delete permissions on the target repo to delete #{@cookbook_name}."
46
46
  exit 1
47
47
  end
@@ -57,7 +57,7 @@ class Chef
57
57
 
58
58
  def auth_header
59
59
  @auth_header ||= begin
60
- ::Knife::KnifeArt::KnifeArtUtils.auth_header_from(cookbooks_api_url)
60
+ ::KnifeArtifactory::Utils.auth_header_from(cookbooks_api_url)
61
61
  end
62
62
  end
63
63
 
@@ -1,4 +1,4 @@
1
- require 'base64'
1
+ require "base64"
2
2
 
3
3
  module KnifeArtifactory
4
4
  class Utils
@@ -6,14 +6,14 @@ module KnifeArtifactory
6
6
  def self.auth_header_from(uri)
7
7
  Chef::Log.debug("[KNIFE-ART] in util, got url: #{uri}")
8
8
  begin
9
- url = URI.parse(uri.gsub(%r{/+$}, ""))
10
- Chef::Log.debug("[KNIFE-ART] in util, parsed url: #{uri}")
11
- if url.user and url.password
12
- user = URI.unescape(url.user)
13
- password = URI.unescape(url.password)
14
- return {"Authorization" => "Basic " + Base64.strict_encode64("#{user}:#{password}")}
15
- end
16
- {}
9
+ url = URI.parse(uri.gsub(%r{/+$}, ""))
10
+ Chef::Log.debug("[KNIFE-ART] in util, parsed url: #{uri}")
11
+ if url.user && url.password
12
+ user = URI.unescape(url.user)
13
+ password = URI.unescape(url.password)
14
+ return { "Authorization" => "Basic " + Base64.strict_encode64("#{user}:#{password}") }
15
+ end
16
+ {}
17
17
  end
18
18
  rescue Exception => e
19
19
  Chef::Log.warn("[KNIFE-ART] Unable to parse url: #{uri} --> #{e.message}")
@@ -1,3 +1,3 @@
1
1
  module KnifeArtifactory
2
- VERSION = '0.1.0'
2
+ VERSION = "0.2.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-artifactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Feldman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-23 00:00:00.000000000 Z
11
+ date: 2019-05-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Enables basic authentication support for share and upload operations
14
14
  to Artifactory when it serves as a Supermarket.
@@ -18,13 +18,13 @@ executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - lib/chef/knife/artifactory_download.rb
22
+ - lib/chef/knife/artifactory_install.rb
23
+ - lib/chef/knife/artifactory_list.rb
24
+ - lib/chef/knife/artifactory_search.rb
25
+ - lib/chef/knife/artifactory_share.rb
21
26
  - lib/chef/knife/artifactory_show.rb
22
- - lib/chef/knife/knife_art_download.rb
23
- - lib/chef/knife/knife_art_install.rb
24
- - lib/chef/knife/knife_art_list.rb
25
- - lib/chef/knife/knife_art_search.rb
26
- - lib/chef/knife/knife_art_share.rb
27
- - lib/chef/knife/knife_art_unshare.rb
27
+ - lib/chef/knife/artifactory_unshare.rb
28
28
  - lib/knife-artifactory/utils.rb
29
29
  - lib/knife-artifactory/version.rb
30
30
  homepage: https://github.com/jasonwbarnett/knife-artifactory