scooter 4.3.2 → 4.5.0

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.
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