scooter 4.3.2 → 4.5.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
- SHA1:
3
- metadata.gz: 3ca54fada5ece86c1fe113fa7f0c25bacd1ebc62
4
- data.tar.gz: 1ce08824ac9b30cf1dc06521dd4f0902bc3e7236
2
+ SHA256:
3
+ metadata.gz: f71907b52f6d00c4a5c3922bad60f2c1bea0a39556959f9ce678bdbdfdcdd63f
4
+ data.tar.gz: '07956a1b0006f9c680f8e54ff80f77d2d1fcad5359af6304e50d9ba4f19a7cd8'
5
5
  SHA512:
6
- metadata.gz: f599a2cc0544ba20572986a9f40e42a586a2c34c14cb455d6c04ea98848abf7f28a6d9458f05dd546b13f7dec8b3f43feeea7b9b86e2c54ef7d1050318bcc0fd
7
- data.tar.gz: d1a8bca420de1f93d34758efe72ab55cdd7b96dc74cc502b2dbe829a44307081d86c0dd5c94e50ca04d9d26c3440165392b8e2ba45638e076c025c8e56e45327
6
+ metadata.gz: ea079fd367c468e76f8cfd84503c912a63727a0c6877aa86d0cd7fea239a3687b78f2dcaf369b81a8ea830b3e8ef34fd30534c539cf2fe9cff1748cb79e381ab
7
+ data.tar.gz: 45d3dc393431935218e795bd83b4df78c075c0e801a25ae9763a4886f0128a963735e92a940c23d20ed268d6bd1d9ad08aa61d3d882565863673a59047f4eddf
@@ -0,0 +1,33 @@
1
+ name: Unit
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ unit:
10
+ name: Unit
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ include:
16
+ - ruby: "2.7"
17
+ - ruby: "3.1"
18
+ - ruby: "3.2"
19
+ steps:
20
+ - name: Checkout repository
21
+ uses: actions/checkout@v4
22
+ - name: Setup Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby }}
26
+ - name: Install bundler
27
+ run: |
28
+ gem install bundler
29
+ bundle config path vendor/bundle
30
+ - name: Install gems
31
+ run: bundle install
32
+ - name: Run unit tests
33
+ run: bundle exec rspec
data/CODEOWNERS ADDED
@@ -0,0 +1 @@
1
+ * @puppetlabs/dumpling
data/README.md CHANGED
@@ -32,17 +32,14 @@ Scooter is currently divvied into the following sections:
32
32
  ## Running the tests
33
33
 
34
34
  ```
35
- bundle exec rake test
35
+ bundle exec rake spec
36
36
  ```
37
37
 
38
38
  ## Versioning
39
39
 
40
40
  Scooter's development began with Puppet Enterprise 3.7, but that was only available for internal testing at that time; Scooter is open-sourced and available on [rubygems.org](https://rubygems.org) at version 4.x to support the LTS version of Puppet Enterprise, 2016.4.0.
41
41
 
42
- ## Rdocs
43
-
44
- Please view the [RubyDocs](http://rubydoc.info/github/puppetlabs/scooter) for further documentation.
45
42
 
46
43
  ## Contributing
47
44
 
48
- Scooter is very closely related to [Beaker](https://github.com/puppetlabs/beaker); if you wish to contribute to this project, please follow the [outline](https://github.com/puppetlabs/beaker/blob/master/CONTRIBUTING.md) there for contributing to this repo.
45
+ Scooter is very closely related to [Beaker](https://github.com/voxpupuli/beaker); if you wish to contribute to this project, please follow the [outline](https://github.com/voxpupuli/beaker/blob/master/CONTRIBUTING.md) there for contributing to this repo.
@@ -0,0 +1,62 @@
1
+ module Beaker::DSL::Helpers::WebHelpers
2
+
3
+ # Generates a new http connection object, using the ever-present options hash to
4
+ # configure the connection.
5
+ #
6
+ # @param host [Beaker::Host optional] supply a SUT host object; will use puppet on host
7
+ # to configure certs, and use the options in the host object instead of the global.
8
+ # @return [Beaker::Http::Connection] an object wrapping the Faraday::Connection object.
9
+ def generate_new_http_connection(host = nil)
10
+ if host
11
+ raise ArgumentError.new "host must be Beaker::Host, not #{host.class}" if !host.is_a?(Beaker::Host)
12
+ connection = Beaker::Http::Connection.new(host.options)
13
+ connection.configure_private_key_and_cert_with_puppet(host)
14
+ connection
15
+ else
16
+ Beaker::Http::Connection.new(options)
17
+ end
18
+ end
19
+
20
+ # Make a single http request and discard the http connection object. Returns a Faraday::Response
21
+ # object that can be introspected for all response information.
22
+ #
23
+ # @param url [String] String that will be parsed into a URI object.
24
+ # @param request_method [Symbol] Represents any valid http verb.
25
+ # @param cert [OpenSSL::X509::Certificate] Certifcate for authentication.
26
+ # @param key [OpenSSL::PKey::RSA] Private Key for authentication.
27
+ # @param body [String, Hash] For requests that can send a body. Strings are sent unformatted and
28
+ # Hashes are JSON.parsed by the Faraday Middleware.
29
+ # @param [Hash] options Hash of options extra options for the request
30
+ # @option options [Boolean] :read_timeout How long to wait before closing the connection.
31
+ # @return [Faraday::Response]
32
+ def http_request(url, request_method, cert=nil, key=nil, body=nil, options={})
33
+ connection = generate_new_http_connection
34
+
35
+
36
+ connection.url_prefix = URI.parse(url)
37
+
38
+ if cert
39
+ if cert.is_a?(OpenSSL::X509::Certificate)
40
+ connection.ssl['client_cert'] = cert
41
+ else
42
+ raise TypeError, "cert must be an OpenSSL::X509::Certificate object, not #{cert.class}"
43
+ end
44
+ end
45
+
46
+ if key
47
+ if key.is_a?(OpenSSL::PKey::RSA)
48
+ connection.ssl['client_key'] = key
49
+ else
50
+ raise TypeError, "key must be an OpenSSL::PKey:RSA object, not #{key.class}"
51
+ end
52
+ end
53
+
54
+ # ewwww
55
+ connection.ssl[:verify] = false
56
+
57
+ connection.connection.options.timeout = options[:read_timeout] if options[:read_timeout]
58
+
59
+ response = connection.send(request_method) { |conn| conn.body = body }
60
+ response
61
+ end
62
+ end
@@ -0,0 +1,49 @@
1
+ module Beaker
2
+ module Http
3
+ module Helpers
4
+
5
+ # Given a Beaker::Host object, introspect the host for the CA cert and save it to
6
+ # the coordinator's filesystem.
7
+ # @param host[Beaker::Host] host to ssh into and find the CA cert
8
+ # @return [String] File path to the CA cert saved on the coordinator
9
+ def get_host_cacert(host)
10
+ cacert_on_host= host.puppet['localcacert']
11
+ # puppet may not have laid down the cacert yet, so check to make sure
12
+ # the file exists
13
+ host.execute("test -f #{cacert_on_host}")
14
+ ca_cert = host.execute("cat #{cacert_on_host}", :silent => true)
15
+ cert_dir = Dir.mktmpdir("pe_certs")
16
+ ca_cert_file = File.join(cert_dir, "cacert.pem")
17
+ File.open(ca_cert_file, "w+") do |f|
18
+ f.write(ca_cert)
19
+ end
20
+ ca_cert_file
21
+ end
22
+
23
+ # Given a Beaker::Host object, introspect the host for the private key and save it to
24
+ # the coordinator's filesystem.
25
+ # @param host[Beaker::Host] host to ssh into and find the private key
26
+ # @return [String] A String of the private key
27
+ def get_host_private_key(host)
28
+ private_key = host.puppet['hostprivkey']
29
+ # puppet may not have laid down the private_key yet, so check to make sure
30
+ # the file exists
31
+ host.execute("test -f #{private_key}")
32
+ host.execute("cat #{private_key}", :silent => true)
33
+ end
34
+
35
+ # Given a Beaker::Host object, introspect the host for the host cert and save it to
36
+ # the coordinator's filesystem.
37
+ # @param host[Beaker::Host] host to ssh into and find the host cert
38
+ # @return [String] A String of the host cert
39
+ def get_host_cert(host)
40
+ hostcert = host.puppet['hostcert']
41
+ # puppet may not have laid down the hostcert yet, so check to make sure
42
+ # the file exists
43
+ host.execute("test -f #{hostcert}")
44
+ host.execute("cat #{hostcert}", :silent => true)
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,93 @@
1
+ module Beaker
2
+ module Http
3
+
4
+ # == Beaker::Http::Connection object instantiation examples
5
+ # These examples are for using the Connection object directly. If you are trying to use
6
+ # this from within a test, consider using the
7
+ # {Beaker::DSL::Helpers::WebHelpers DSL constructors} instead.
8
+ # @see Beaker::DSL::Helpers::WebHelpers
9
+ class Connection
10
+ include Beaker::Http::Helpers
11
+ extend Forwardable
12
+
13
+ attr_reader :connection
14
+
15
+ # Beaker::Http::Connection objects can be instantiated with object that
16
+ # utilizes a object for easier setup during testing.
17
+ #
18
+ # @param [Hash] options Typically the global options provided by Beaker.
19
+ # @option options [Beaker::Logger] :logger
20
+ # @option options [Boolean] :log_http_bodies
21
+ def initialize(options)
22
+ @connection = create_default_connection(options)
23
+ end
24
+
25
+ def_delegators :connection, :get, :post, :put, :delete, :head, :patch, :url_prefix, :url_prefix=, :ssl
26
+
27
+ def create_default_connection(options)
28
+ Faraday.new do |conn|
29
+ conn.request :json
30
+
31
+ conn.response :follow_redirects
32
+ conn.response :raise_error
33
+ conn.response :json, :content_type => /\bjson$/
34
+
35
+ # We can supply a third argument, a Hash with key of :bodies set to true or false,
36
+ # to configure whether or not to log http bodies in requests and responses.
37
+ # However, to uncomplicate things, we will just use the default
38
+ # set in the middleware and not allow the http log level to be set
39
+ # independently of the beaker log level. If we find that we should allow setting
40
+ # of http bodies independent of the beaker log level, we should expose that setting
41
+ # here.
42
+ conn.response :faraday_beaker_logger, options[:logger]
43
+
44
+ conn.adapter :net_http
45
+ end
46
+ end
47
+
48
+ # If you would like to run tests that expect 400 or even 500 responses,
49
+ # apply this method to remove the <tt>:raise_error</tt> middleware.
50
+ def remove_error_checking
51
+ connection.builder.delete(Faraday::Response::RaiseError)
52
+ nil
53
+ end
54
+
55
+ def set_cacert(ca_file)
56
+ ssl['ca_file'] = ca_file
57
+ url_prefix.scheme = 'https'
58
+ end
59
+
60
+ def set_client_key(client_key)
61
+ ssl['client_key'] = client_key
62
+ end
63
+
64
+ def set_client_cert(client_cert)
65
+ ssl['client_cert'] = client_cert
66
+ end
67
+
68
+ # Use this method if you are connecting as a user to the system; it will
69
+ # provide the correct SSL context but not provide authentication.
70
+ def configure_cacert_with_puppet(host)
71
+ set_cacert(get_host_cacert(host))
72
+ connection.host = host.hostname
73
+ nil
74
+ end
75
+
76
+ # Use this method if you want to connect to the system using certificate
77
+ # based authentication. This method will provide the ssl context and use
78
+ # the private key and cert from the host provided for authentication.
79
+ def configure_private_key_and_cert_with_puppet(host)
80
+ configure_cacert_with_puppet(host)
81
+
82
+ client_key_raw = get_host_private_key(host)
83
+ client_cert_raw = get_host_cert(host)
84
+
85
+ ssl['client_key'] = OpenSSL::PKey.read(client_key_raw)
86
+ ssl['client_cert'] = OpenSSL::X509::Certificate.new(client_cert_raw)
87
+
88
+ nil
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,60 @@
1
+ module Beaker
2
+ module Http
3
+ class FaradayBeakerLogger < Faraday::Response::Middleware
4
+ extend Forwardable
5
+
6
+ DEFAULT_OPTIONS = { :bodies => true }
7
+
8
+ def initialize(app, logger, options = {} )
9
+ super(app)
10
+ @logger = logger
11
+ @options = DEFAULT_OPTIONS.merge(options)
12
+ end
13
+
14
+ def_delegators :@logger, :trace, :debug, :info, :notify, :warn
15
+
16
+ def call(env)
17
+ @start_time = Time.now
18
+ info "#{env.method.upcase}: #{env.url.to_s}"
19
+ debug "REQUEST HEADERS:\n#{dump_headers env.request_headers}"
20
+ debug "REQUEST BODY:\n#{dump_body env[:body]}" if env[:body] && log_body?(:request)
21
+ super
22
+ end
23
+
24
+ def on_complete(env)
25
+ info "RESPONSE CODE: #{env.status.to_s}"
26
+ debug "ELAPSED TIME: #{Time.now - @start_time}"
27
+ debug "RESPONSE HEADERS:\n#{dump_headers env.response_headers}"
28
+ debug "RESPONSE BODY:\n#{dump_body env[:body]}" if env[:body] && log_body?(:response)
29
+ end
30
+ private
31
+
32
+ def dump_headers(headers)
33
+ headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
34
+ end
35
+
36
+ def pretty_inspect(body)
37
+ require 'pp' unless body.respond_to?(:pretty_inspect)
38
+ body.pretty_inspect
39
+ end
40
+
41
+ def dump_body(body)
42
+ if body.respond_to?(:to_str)
43
+ body.to_str
44
+ else
45
+ pretty_inspect(body)
46
+ end
47
+ end
48
+
49
+ def log_body?(type)
50
+ case @options[:bodies]
51
+ when Hash then @options[:bodies][type]
52
+ else @options[:bodies]
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+
60
+ Faraday::Response.register_middleware :faraday_beaker_logger => lambda { Beaker::Http::FaradayBeakerLogger }
@@ -0,0 +1,7 @@
1
+ module Beaker
2
+ module Http
3
+ module Version
4
+ STRING = '0.2.0'
5
+ end
6
+ end
7
+ end
@@ -9,7 +9,7 @@ module Scooter
9
9
  @version = 'v1'
10
10
  end
11
11
 
12
- #jobs endpoints
12
+ # jobs endpoints
13
13
  def get_last_jobs(limit=nil, offset=nil, order_by=nil, order=nil)
14
14
  path = "#{@version}/jobs"
15
15
  @connection.get(path) do |request|
@@ -20,6 +20,16 @@ module Scooter
20
20
  end
21
21
  end
22
22
 
23
+ # plan_jobs endpoints
24
+ def get_last_plan_jobs(limit=nil, offset=nil, results=nil)
25
+ path = "#{@version}/plan_jobs"
26
+ @connection.get(path) do |request|
27
+ request.params['limit'] = limit if limit
28
+ request.params['offset'] = offset if offset
29
+ request.params['results'] = results if results
30
+ end
31
+ end
32
+
23
33
  def get_job(job_id)
24
34
  @connection.get("#{@version}/jobs/#{job_id}")
25
35
  end
@@ -78,6 +88,12 @@ module Scooter
78
88
  end
79
89
  end
80
90
 
91
+ def post_schedule_plan(payload)
92
+ @connection.post("#{@version}/command/schedule_plan") do |req|
93
+ req.body = payload
94
+ end
95
+ end
96
+
81
97
  #inventory endpoints
82
98
  def get_inventory(node=nil)
83
99
  url = "#{@version}/inventory"
@@ -19,6 +19,11 @@ module Scooter
19
19
  get_last_jobs(n_jobs)
20
20
  end
21
21
 
22
+ # @return [Faraday::Response] response object from Faraday http client
23
+ def list_plan_jobs(n_jobs=nil)
24
+ get_last_plan_jobs(n_jobs)
25
+ end
26
+
22
27
  # @return [Faraday::Response] response object from Faraday http client
23
28
  def list_job_details(job_id)
24
29
  get_job(job_id)
@@ -84,9 +89,14 @@ module Scooter
84
89
  post_dumpling(dumpling)
85
90
  end
86
91
 
92
+ # Schedule a task or plan
87
93
  # @return [Faraday::Response] response object from Faraday http client
88
94
  def create_scheduled_job(payload)
89
- post_schedule_task(payload)
95
+ if payload.include?('task')
96
+ post_schedule_task(payload)
97
+ else
98
+ post_schedule_plan(payload)
99
+ end
90
100
  end
91
101
 
92
102
  # @return [Faraday::Response] response object from Faraday http client
@@ -1,5 +1,5 @@
1
1
  module Scooter
2
2
  module Version
3
- STRING = '4.3.2'
3
+ STRING = '4.5.0'
4
4
  end
5
5
  end
data/lib/scooter.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  require 'scooter/version'
2
2
  require 'beaker'
3
3
  require 'net/ldap'
4
- require 'beaker-http'
5
4
  require 'faraday'
6
5
  require 'faraday_middleware'
7
6
  require 'faraday-cookie_jar'
7
+ require 'forwardable'
8
+ require 'beaker-http/helpers/puppet_helpers'
9
+ require 'beaker-http/dsl/web_helpers'
10
+ require "beaker-http/http"
11
+ require 'beaker-http/middleware/response/faraday_beaker_logger'
8
12
 
9
13
  module Scooter
10
14
  %w( utilities httpdispatchers ldap ).each do |lib|
data/scooter.gemspec CHANGED
@@ -18,24 +18,24 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  #Development dependencies
21
- spec.add_development_dependency 'bundler', '~> 1.6'
22
- spec.add_development_dependency 'pry', '~> 0.9.12'
21
+ spec.add_development_dependency 'bundler', '~> 2'
22
+ spec.add_development_dependency 'pry', '~> 0.10'
23
23
  spec.add_development_dependency 'rake'
24
24
  spec.add_development_dependency 'rspec', '>= 3.0.0'
25
- spec.add_development_dependency 'beaker-abs', '~>0.3.0'
25
+ spec.add_development_dependency 'beaker-abs'
26
+ spec.add_development_dependency 'webmock', '~> 3.13'
26
27
 
27
28
  #Documentation dependencies
28
29
  spec.add_development_dependency 'yard', '~> 0.9.11'
29
30
  spec.add_development_dependency 'markdown', '~> 0'
30
- spec.add_development_dependency 'activesupport', '4.2.6'
31
+ spec.add_development_dependency 'activesupport', '4.2.8'
31
32
 
32
33
  #Run time dependencies
33
- spec.add_runtime_dependency 'beaker', '>= 3.0', '< 5.0' # known support for beaker 3.x and 4.x
34
- spec.add_runtime_dependency 'beaker-http', '~> 0.0'
35
- spec.add_runtime_dependency 'json', '~> 1.8'
34
+ spec.add_runtime_dependency 'beaker'
35
+ spec.add_runtime_dependency 'json'
36
36
  spec.add_runtime_dependency 'test-unit'
37
- spec.add_runtime_dependency 'net-ldap', '~> 0.6', '>= 0.6.1', '<= 0.12.1'
38
- spec.add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9.1'
39
- spec.add_runtime_dependency 'faraday_middleware', '~> 0.9'
40
- spec.add_runtime_dependency 'faraday-cookie_jar', '~> 0.0', '>= 0.0.6'
37
+ spec.add_runtime_dependency 'net-ldap', '~> 0.16'
38
+ spec.add_runtime_dependency 'faraday'
39
+ spec.add_runtime_dependency 'faraday_middleware', '~> 1.2'
40
+ spec.add_runtime_dependency 'faraday-cookie_jar', '>= 0.0.7'
41
41
  end
@@ -147,12 +147,8 @@ module Scooter
147
147
 
148
148
  describe '.get_classifier_events' do
149
149
  before do
150
- # find the index of the default Faraday::Adapter::NetHttp handler
151
- # and replace it with the Test adapter
152
- index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
153
- subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
154
- stub.get('activity-api/v1/events?service_id=classifier') { [200, {}] }
155
- end
150
+ stub_request(:get, /service_id=classifier/).
151
+ to_return(status: 200, body: {}.to_json, headers: {"Content-Type"=> "application/json"})
156
152
  end
157
153
  it 'gets classifier events' do
158
154
  expect { subject.get_classifier_events }.not_to raise_error
@@ -171,12 +167,8 @@ module Scooter
171
167
 
172
168
  describe '.get_rbac_events' do
173
169
  before do
174
- # find the index of the default Faraday::Adapter::NetHttp handler
175
- # and replace it with the Test adapter
176
- index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
177
- subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
178
- stub.get('activity-api/v1/events?service_id=rbac') { [200, {}] }
179
- end
170
+ stub_request(:get, /service_id=rbac/).
171
+ to_return(status: 200, body: {}.to_json, headers: {"Content-Type"=> "application/json"})
180
172
  end
181
173
  it 'gets rbac events' do
182
174
  expect { subject.get_rbac_events }.not_to raise_error
@@ -196,20 +188,17 @@ module Scooter
196
188
 
197
189
  describe '.activity_database_matches_self?' do
198
190
  before do
199
- # find the index of the default Faraday::Adapter::NetHttp handler
200
- # and replace it with the Test adapter
201
- index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
202
- subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
203
- stub.get('activity-api/v1/events?service_id=rbac') { |env| env[:url].to_s == "https://test.com:4433/activity-api/v1/events?service_id=rbac" ?
204
- [200, [], rbac_events] :
205
- [200, [], rbac_events['commits'].dup.push('another_array_item')] }
206
- stub.get('activity-api/v1/events?service_id=classifier') { |env| env[:url].to_s == "https://test.com:4433/activity-api/v1/events?service_id=classifier" ?
207
- [200, [], classifier_events] :
208
- [200, [], classifier_events.dup["commits"].push('another_array_item')] }
209
- end
191
+ stub_request(:get, 'https://test.com:4433/activity-api/v1/events?service_id=rbac').
192
+ to_return(status: 200, body: rbac_events.to_json, headers: {"Content-Type"=> "application/json"})
193
+ stub_request(:get, 'https://test2.com:4433/activity-api/v1/events?service_id=rbac').
194
+ to_return(status: 200, body: rbac_events.dup["commits"].push('another_array_item').to_json, headers: {"Content-Type"=> "application/json"})
195
+
196
+ stub_request(:get, 'https://test.com:4433/activity-api/v1/events?service_id=classifier').
197
+ to_return(status: 200, body: classifier_events.to_json, headers: {"Content-Type"=> "application/json"})
198
+ stub_request(:get, 'https://test2.com:4433/activity-api/v1/events?service_id=classifier').
199
+ to_return(status: 200, body: classifier_events.dup["commits"].push('another_array_item').to_json, headers: {"Content-Type"=> "application/json"})
200
+
210
201
  expect(subject).to receive(:is_resolvable).exactly(4).times.and_return(true)
211
- # expect(subject).to receive(:create_default_connection).with(any_args).twice.and_return(subject.connection)
212
- # expect(Scooter::Utilities::BeakerUtilities).to receive(:get_public_ip).and_return('public_ip')
213
202
  end
214
203
 
215
204
  it 'compare with self' do