nexus_api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/nexus_api.rb ADDED
@@ -0,0 +1,372 @@
1
+ require 'nexus_api/version'
2
+ require 'nexus_api/docker_shell'
3
+ require 'nexus_api/docker_manager'
4
+ require 'nexus_api/nexus_connection'
5
+ require 'nexus_api/config_manager'
6
+ require 'json'
7
+ require 'pry'
8
+
9
+ # Nexus API docs:
10
+ # https://help.sonatype.com/repomanager3/rest-and-integration-api#app
11
+ # https://[NEXUS_URL]/#admin/system/api
12
+ module NexusAPI
13
+ class API
14
+ attr_accessor :connection
15
+ attr_accessor :docker
16
+ attr_accessor :team_config
17
+
18
+ TEAM_CONFIG = File.join(File.dirname(__dir__), 'team_configs/default.yaml').freeze
19
+
20
+ def initialize(username:, password:, hostname:, docker_pull_hostname: nil, docker_push_hostname: nil, team_config: nil)
21
+ @connection = NexusAPI::NexusConnection.new(
22
+ username: username,
23
+ password: password,
24
+ hostname: hostname,
25
+ )
26
+ if docker_pull_hostname.nil? || docker_push_hostname.nil?
27
+ @docker = nil
28
+ else
29
+ @docker = NexusAPI::DockerManager.new(
30
+ docker: NexusAPI::DockerShell.new,
31
+ options: {
32
+ 'username' => username,
33
+ 'password' => password,
34
+ 'pull_host' => docker_pull_hostname,
35
+ 'push_host' => docker_push_hostname,
36
+ }
37
+ )
38
+ end
39
+ team_config ||= TEAM_CONFIG
40
+ @team_config = NexusAPI::ConfigManager.new(config_path: team_config)
41
+ end
42
+
43
+
44
+ # ---ASSETS---
45
+ # GET /service/rest/v1/assets
46
+ def list_assets(repository: nil, paginate: false)
47
+ repository ||= @team_config.assets_repository
48
+ @connection.get_response(endpoint: "assets?repository=#{repository}", paginate: paginate)
49
+ end
50
+
51
+ # GET /service/rest/v1/assets/{id}
52
+ def list_asset(id:)
53
+ @connection.get_response(endpoint: "assets/#{id}")
54
+ end
55
+
56
+ # DELETE /service/rest/v1/assets/{id}
57
+
58
+
59
+ # ---BLOB STORE---
60
+ # GET /service/rest/v1/blobstores/{id}/quota-status
61
+
62
+
63
+ # ---COMPONENTS---
64
+ # GET /service/rest/v1/components
65
+ def list_components(repository: nil, paginate: false)
66
+ repository ||= @team_config.components_repository
67
+ @connection.get_response(endpoint: "components?repository=#{repository}", paginate: paginate)
68
+ end
69
+
70
+ # POST /service/rest/v1/components
71
+ def upload_maven_component(filename:, group_id:, artifact_id:, version:, repository: nil, tag: nil)
72
+ repository ||= @team_config.maven_repository
73
+ parameters = {
74
+ 'maven2.groupId' => group_id,
75
+ 'maven2.artifactId' => artifact_id,
76
+ 'maven2.version' => version,
77
+ 'maven2.asset1' => File.open(filename, 'r'),
78
+ 'maven2.asset1.extension' => filename.split('.').last,
79
+ }
80
+ parameters['maven2.tag'] = tag if tag
81
+ @connection.post(endpoint: "components?repository=#{repository}", parameters: parameters, headers: {})
82
+ end
83
+
84
+ def upload_npm_component(filename:, repository: nil, tag: nil)
85
+ repository ||= @team_config.npm_repository
86
+ parameters = {
87
+ 'npm.asset' => File.open(filename, 'r'),
88
+ }
89
+ parameters['npm.tag'] = tag if tag
90
+ @connection.post(endpoint: "components?repository=#{repository}", parameters: parameters, headers: {})
91
+ end
92
+
93
+ def upload_pypi_component(filename:, repository: nil, tag: nil)
94
+ repository ||= @team_config.pypi_repository
95
+ parameters = {
96
+ 'pypi.asset' => File.open(filename, 'r'),
97
+ }
98
+ parameters['pypi.tag'] = tag if tag
99
+ @connection.post(endpoint: "components?repository=#{repository}", parameters: parameters, headers: {})
100
+ end
101
+
102
+ def upload_raw_component(filename:, directory:, repository: nil, tag: nil)
103
+ repository ||= @team_config.raw_repository
104
+ parameters = {
105
+ 'raw.directory' => directory,
106
+ 'raw.asset1' => File.open(filename, 'r'),
107
+ 'raw.asset1.filename' => filename.split('/').last,
108
+ }
109
+ parameters['raw.tag'] = tag if tag
110
+ @connection.post(endpoint: "components?repository=#{repository}", parameters: parameters, headers: {})
111
+ end
112
+
113
+ def upload_rubygems_component(filename:, repository: nil, tag: nil)
114
+ repository ||= @team_config.rubygems_repository
115
+ parameters = {
116
+ 'rubygems.asset' => File.open(filename, 'r'),
117
+ }
118
+ parameters['rubygems.tag'] = tag if tag
119
+ @connection.post(endpoint: "components?repository=#{repository}", parameters: parameters, headers: {})
120
+ end
121
+
122
+ def upload_yum_component(filename:, directory:, repository: nil, tag: nil)
123
+ repository ||= @team_config.yum_repository
124
+ parameters = {
125
+ 'yum.directory' => directory,
126
+ 'yum.asset' => File.open(filename, 'r'),
127
+ 'yum.asset.filename' => filename.split('/').last,
128
+ }
129
+ parameters['yum.tag'] = tag if tag
130
+ @connection.post(endpoint: "components?repository=#{repository}", parameters: parameters, headers: {})
131
+ end
132
+
133
+ # GET /service/rest/v1/components/{id}
134
+ def list_component(id:)
135
+ @connection.get_response(endpoint: "components/#{id}")
136
+ end
137
+
138
+ # DELETE /service/rest/v1/components/{id}
139
+
140
+
141
+ # ---FORMATS---
142
+ # GET /service/rest/v1/formats/{format}/upload-specs
143
+ # GET /service/rest/v1/formats/upload-specs
144
+
145
+
146
+ # ---LIFECYCLE---
147
+ # PUT /service/rest/v1/lifecycle/bounce
148
+ # GET /service/rest/v1/lifecycle/phase
149
+ # PUT /service/rest/v1/lifecycle/phase
150
+
151
+
152
+ # ---MAINTENANCE---
153
+ # PUT /service/rest/v1/maintenance/{databaseName}/check
154
+ # PUT /service/rest/v1/maintenance/{databaseName}/reinstall
155
+ # PUT /service/rest/v1/maintenance/{databaseName}/repair
156
+ # GET /service/rest/v1/maintenance/{databaseName}/role
157
+ # PUT /service/rest/v1/maintenance/{databaseName}/role
158
+ # GET /service/rest/v1/maintenance/{databaseName}/status
159
+ # PUT /service/rest/v1/maintenance/{databaseName}/status
160
+
161
+
162
+ # ---NODES---
163
+ # GET /service/rest/v1/nodes
164
+ # PUT /service/rest/v1/nodes
165
+ # GET /service/rest/v1/nodes/supportzipdownload
166
+ # POST /service/rest/v1/nodes/supportzips
167
+
168
+
169
+ # ---READ-ONLY---
170
+ # GET /service/rest/v1/read-only
171
+ # POST /service/rest/v1/read-only/force-release
172
+ # POST /service/rest/v1/read-only/freeze
173
+ # POST /service/rest/v1/read-only/release
174
+
175
+
176
+ # ---REPOSITORIES--- (This endpoint does not paginate)
177
+ # GET /service/rest/v1/repositories
178
+ def list_repositories
179
+ @connection.get_response(endpoint: 'repositories')
180
+ end
181
+
182
+ def list_repository_names
183
+ list_repositories.map { |repo| repo['name'] }
184
+ end
185
+
186
+
187
+ # ---ROUTING-RULES---
188
+ # GET /service/rest/v1/beta/routing-rules
189
+ # POST /service/rest/v1/beta/routing-rules
190
+ # GET /service/rest/v1/beta/routing-rules/{name}
191
+ # PUT /service/rest/v1/beta/routing-rules/{name}
192
+ # DELETE /service/rest/v1/beta/routing-rules/{name}
193
+
194
+
195
+ # ---SCRIPT---
196
+ # GET /service/rest/v1/script
197
+ def list_scripts
198
+ @connection.get_response(endpoint: "script")
199
+ end
200
+
201
+ # POST /service/rest/v1/script
202
+ def upload_script(filename:)
203
+ file = File.read(filename)
204
+ @connection.post(endpoint: "script", parameters: file)
205
+ end
206
+
207
+ # GET /service/rest/v1/script/{name}
208
+ # PUT /service/rest/v1/script/{name}
209
+ # DELETE /service/rest/v1/script/{name}
210
+ def delete_script(name:)
211
+ @connection.delete(endpoint: "script/#{name}")
212
+ end
213
+
214
+ # POST /service/rest/v1/script/{name}/run
215
+ def run_script(name:)
216
+ @connection.post(endpoint: "script/#{name}/run", headers: {'Content-Type' => 'text/plain'})
217
+ end
218
+
219
+
220
+ # ---SEARCH---
221
+ # GET /service/rest/v1/search
222
+
223
+ # GET /service/rest/v1/search/assets
224
+ def search_asset(name:, format: nil, repository: nil, sha1: nil, version: nil, paginate: false)
225
+ repository ||= @team_config.search_repository
226
+ endpoint = "search/assets?q=#{name}"
227
+ endpoint += "&format=#{format}" unless format.nil?
228
+ endpoint += "&repository=#{repository}" unless repository.nil?
229
+ endpoint += "&sha1=#{sha1}" unless sha1.nil?
230
+ endpoint += "&version=#{version}" unless version.nil?
231
+ @connection.get_response(endpoint: endpoint, paginate: paginate)
232
+ end
233
+
234
+ # GET /service/rest/v1/search/assets/download
235
+
236
+
237
+ # ---SECURITY MANAGEMENT---
238
+ # GET /service/rest/v1/beta/security/user-sources
239
+
240
+
241
+ # ---SECURITY MANAGEMENT: USER TOKENS---
242
+ # DELETE /service/rest/v1/beta/security/user-tokens
243
+
244
+
245
+ # ---SECURITY MANAGEMENT: USERS---
246
+ # GET /service/rest/v1/beta/security/users
247
+ # POST /service/rest/v1/beta/security/users
248
+ # PUT /service/rest/v1/beta/security/users/{userId}
249
+ # DELETE /service/rest/v1/beta/security/users/{userId}
250
+ # PUT /service/rest/v1/beta/security/users/{userId}/change-password
251
+ # DELETE /service/rest/v1/beta/security/users/{userId}/user-token
252
+
253
+
254
+ # ---STAGING---
255
+ # POST /service/rest/v1/staging/delete
256
+ # POST /service/rest/v1/staging/move/{destination}
257
+
258
+
259
+ # ---STATUS---
260
+ # GET /service/rest/v1/status
261
+ def status
262
+ @connection.get(endpoint: 'status')
263
+ end
264
+
265
+ # GET /service/rest/v1/status/writable
266
+ def status_writable
267
+ @connection.get(endpoint: 'status/writable')
268
+ end
269
+
270
+
271
+ # ---SUPPORT---
272
+ # POST /service/rest/v1/support/supportzip
273
+
274
+
275
+ # ---TAGS---
276
+ # GET /service/rest/v1/tags
277
+ def list_tags(paginate: false)
278
+ @connection.get_response(endpoint: 'tags', paginate: paginate)
279
+ end
280
+
281
+ # POST /service/rest/v1/tags
282
+ def create_tag(name:)
283
+ parameters = JSON.dump({
284
+ 'name' => name,
285
+ })
286
+ @connection.post(endpoint: 'tags', parameters: parameters)
287
+ end
288
+
289
+ # GET /service/rest/v1/tags/{name}
290
+ # PUT /service/rest/v1/tags/{name}
291
+ # DELETE /service/rest/v1/tags/{name}
292
+ def delete_tag(name:)
293
+ @connection.delete(endpoint: "tags/#{name}")
294
+ end
295
+
296
+ # POST /service/rest/v1/tags/associate/{tagName}
297
+ def associate_tag(name:, sha1:, repository: nil)
298
+ repository ||= @team_config.tag_repository
299
+ search_query =
300
+ "?"\
301
+ "wait=true&"\
302
+ "repository=#{repository}&"\
303
+ "sha1=#{sha1}"
304
+ @connection.post(endpoint: "tags/associate/#{name}" + search_query)
305
+ end
306
+
307
+ # DELETE /service/rest/v1/tags/associate/{tagName}
308
+ def delete_associated_tag(name:, sha1:, repository: nil)
309
+ repository ||= @team_config.tag_repository
310
+ search_query =
311
+ "?"\
312
+ "repository=#{repository}&"\
313
+ "sha1=#{sha1}"
314
+ @connection.delete(endpoint: "tags/associate/#{name}" + search_query)
315
+ end
316
+
317
+
318
+ # ---TASKS---
319
+ # GET /service/rest/v1/tasks
320
+ # GET /service/rest/v1/tasks/{id}
321
+ # POST /service/rest/v1/tasks/{id}/run
322
+ # POST /service/rest/v1/tasks/{id}/stop
323
+
324
+
325
+ # ---CUSTOM FUNCTIONS---
326
+ def get_asset_size(asset_url:)
327
+ @connection.content_length(asset_url: asset_url)
328
+ end
329
+
330
+ def docker_ready?
331
+ if @docker.nil?
332
+ raise 'Docker push and pull endpoints not initialized!'
333
+ return false
334
+ end
335
+ true
336
+ end
337
+
338
+ def download_docker_component(image:, tag:)
339
+ @docker.download(image_name: image, tag: tag) if docker_ready?
340
+ end
341
+
342
+ def upload_docker_component(image:, tag:)
343
+ @docker.upload(image_name: image, tag: tag) if docker_ready?
344
+ end
345
+
346
+ def local_docker_image_exists?(image:, tag:)
347
+ @docker.exists?(image_name: image, tag: tag) if docker_ready?
348
+ end
349
+
350
+ def delete_local_docker_image(image:, tag:)
351
+ @docker.delete(image_name: image, tag: tag) if docker_ready?
352
+ end
353
+
354
+ def download(id:, name: nil)
355
+ asset = list_asset(id: id)
356
+ return false if asset == '' || asset.empty?
357
+ return false if asset["downloadUrl"].nil?
358
+ url = asset["downloadUrl"]
359
+ response = @connection.download(url: url)
360
+ if name
361
+ File.write(name, response.body)
362
+ else
363
+ File.write(url.split('/').last, response.body)
364
+ end
365
+ true
366
+ end
367
+
368
+ def paginate?
369
+ @connection.paginate?
370
+ end
371
+ end
372
+ end
data/nexus_api.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "nexus_api/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'nexus_api'
7
+ spec.version = NexusAPI::VERSION
8
+ spec.date = %q{2019-12-04}
9
+ spec.authors = ['Francis Levesque', 'Gavin Miller']
10
+ spec.email = ['francis.d.levesque@gmail.com', 'me@gavinmiller.io']
11
+
12
+ spec.summary = %q{nexus_api: provides access to Nexus through ruby!}
13
+ spec.homepage = "https://github.com/Cisco-AMP/nexus_api"
14
+ spec.license = 'MIT'
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.bindir = 'bin'
22
+ spec.executables = ['nexus_api']
23
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_runtime_dependency 'bundler', "~> 2"
27
+ spec.add_runtime_dependency 'docker-api', "~> 1.34.2"
28
+ spec.add_runtime_dependency 'dotenv', "~> 2.7.5"
29
+ spec.add_runtime_dependency 'pry', "~> 0.12.2"
30
+ spec.add_runtime_dependency 'rake', "~> 10.0"
31
+ spec.add_runtime_dependency 'rest-client', "~> 2.1.0"
32
+ spec.add_runtime_dependency 'thor', "~> 0.20.3"
33
+
34
+ spec.add_development_dependency 'rspec', "~> 3.0"
35
+ end
@@ -0,0 +1,6 @@
1
+ # Default set of repos for nexus_api to use
2
+
3
+ # Default repository for Nexus actions
4
+
5
+
6
+ # Default repository for file uploads
@@ -0,0 +1,18 @@
1
+ # Default set of repos for nexus_api to use
2
+ #
3
+ # NOTE: If you don't want to set a default for a certain
4
+ # case simply remove it from your config
5
+
6
+ # Default repository for Nexus actions
7
+ assets: default_assets_repo
8
+ components: default_components_repo
9
+ search: default_search_repo
10
+ tag: default_tag_repo
11
+
12
+ # Default repository for file uploads
13
+ maven: default_maven_repo
14
+ npm: default_npm_repo
15
+ pypi: default_pypi_repo
16
+ raw: default_raw_repo
17
+ rubygems: default_rubygems_repo
18
+ yum: default_yum_repo
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nexus_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Francis Levesque
8
+ - Gavin Miller
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-12-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '2'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '2'
28
+ - !ruby/object:Gem::Dependency
29
+ name: docker-api
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 1.34.2
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 1.34.2
42
+ - !ruby/object:Gem::Dependency
43
+ name: dotenv
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 2.7.5
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 2.7.5
56
+ - !ruby/object:Gem::Dependency
57
+ name: pry
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.12.2
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 0.12.2
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '10.0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '10.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rest-client
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: 2.1.0
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 2.1.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: thor
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: 0.20.3
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: 0.20.3
112
+ - !ruby/object:Gem::Dependency
113
+ name: rspec
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '3.0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '3.0'
126
+ description:
127
+ email:
128
+ - francis.d.levesque@gmail.com
129
+ - me@gavinmiller.io
130
+ executables:
131
+ - nexus_api
132
+ extensions: []
133
+ extra_rdoc_files: []
134
+ files:
135
+ - ".env.template"
136
+ - ".gitignore"
137
+ - ".rspec"
138
+ - ".ruby-version"
139
+ - CHANGELOG.md
140
+ - Gemfile
141
+ - Gemfile.lock
142
+ - LICENSE.txt
143
+ - README.md
144
+ - Rakefile
145
+ - bin/nexus_api
146
+ - bin/setup
147
+ - bin/test
148
+ - lib/nexus_api.rb
149
+ - lib/nexus_api/cli.rb
150
+ - lib/nexus_api/cli_commands/commands.rb
151
+ - lib/nexus_api/cli_commands/download.rb
152
+ - lib/nexus_api/cli_commands/list.rb
153
+ - lib/nexus_api/cli_commands/script.rb
154
+ - lib/nexus_api/cli_commands/search.rb
155
+ - lib/nexus_api/cli_commands/tag.rb
156
+ - lib/nexus_api/cli_commands/upload.rb
157
+ - lib/nexus_api/cli_utils.rb
158
+ - lib/nexus_api/config_manager.rb
159
+ - lib/nexus_api/docker_manager.rb
160
+ - lib/nexus_api/docker_shell.rb
161
+ - lib/nexus_api/nexus_connection.rb
162
+ - lib/nexus_api/version.rb
163
+ - nexus_api.gemspec
164
+ - team_configs/default.yaml
165
+ - team_configs/template.yaml
166
+ homepage: https://github.com/Cisco-AMP/nexus_api
167
+ licenses:
168
+ - MIT
169
+ metadata: {}
170
+ post_install_message:
171
+ rdoc_options: []
172
+ require_paths:
173
+ - lib
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ requirements: []
185
+ rubygems_version: 3.0.3
186
+ signing_key:
187
+ specification_version: 4
188
+ summary: 'nexus_api: provides access to Nexus through ruby!'
189
+ test_files: []