blob: a97d215fc226330096c0634e5229de612b07318f [file] [log] [blame]
Ales Komarek197f4432016-09-02 15:26:17 +02001# -*- coding: utf-8 -*-
2'''
3Module for fetching artifacts from Artifactory
4'''
5
6# Import python libs
7from __future__ import absolute_import
8import os
9import base64
10import logging
11
12# Import Salt libs
13import salt.utils
14import salt.ext.six.moves.http_client # pylint: disable=import-error,redefined-builtin,no-name-in-module
15from salt.ext.six.moves import urllib # pylint: disable=no-name-in-module
16from salt.ext.six.moves.urllib.error import HTTPError, URLError # pylint: disable=no-name-in-module
17
18import json
19import requests
20
21log = logging.getLogger(__name__)
22
23__virtualname__ = 'artifactory_repo'
24
25
26def __virtual__():
27
28 return True
29
30
31repo_config = {
32 "key": "local-repo1",
33 "rclass" : "local",
34 "packageType": "generic",
35 "description": "The local repository public description",
36}
37
38# "repoLayoutRef" : "maven-2-default",
39
40class ArtifactoryClient:
41
42 def __init__(self, config={}):
43
44 self.files = []
45
46 client_config = {
47 'artifactory_url': 'http://your-instance/artifactory/api',
48 'search_prop': 'search/prop',
49 'search_name': 'search/artifact',
50 'search_repos': 'repositories',
51 'username': 'your-user',
52 'password': 'password',
Filip Pytloun320b2f92016-09-13 13:37:13 +020053 'headers': {'Content-type': 'application/json'},
54 'ssl_verify': True
Ales Komarek197f4432016-09-02 15:26:17 +020055 }
56
57 client_config.update(config)
58
59 # Set instance variables for every value in party_config
60 for k, v in client_config.items():
61 setattr(self, '%s' % (k,), v)
62
63 def create_repository(self, name, config, **connection_args):
64 repositories = []
65
66 query = "%s/%s/%s" % (self.artifactory_url, self.search_repos, name)
67 auth = (self.username, self.password)
68
Filip Pytloun320b2f92016-09-13 13:37:13 +020069 r = requests.put(query, auth=auth, json=config, verify=self.ssl_verify)
Ales Komarek197f4432016-09-02 15:26:17 +020070 print(r.content)
71
72 raw_response = self.query_artifactory(query)
73 if raw_response is None:
74 return []
75 response = json.loads(raw_response.text)
76 for line in response:
77 for item in line:
78 repositories.append(line)
79
80 if repositories:
81 return repositories
82
83 return []
84
85
86 def get_repositories(self, repo_type=None, **connection_args):
87 repositories = []
88
89 if repo_type is None:
90 query = "%s/%s" % (self.artifactory_url, self.search_repos)
91 else:
92 query = "%s/%s?type=%s" % (self.artifactory_url,
93 self.search_repos, repo_type)
94
95 raw_response = self.query_artifactory(query)
96 if raw_response is None:
97 return []
98 response = json.loads(raw_response.text)
99 for line in response:
100 for item in line:
101 repositories.append(line)
102
103 if repositories:
104 return repositories
105
106 return []
107
108
109 def query_artifactory(self, query, query_type='get'):
110 """
111 Send request to Artifactory API endpoint.
112 @param: query - Required. The URL (including endpoint) to send to the Artifactory API
113 @param: query_type - Optional. CRUD method. Defaults to 'get'.
114 """
115
116 auth = (self.username, self.password)
117 query_type = query_type.lower()
118
119 if query_type == "get":
Filip Pytloun320b2f92016-09-13 13:37:13 +0200120 response = requests.get(query, auth=auth, headers=self.headers, verify=self.ssl_verify)
Ales Komarek197f4432016-09-02 15:26:17 +0200121 elif query_type == "put":
Filip Pytloun320b2f92016-09-13 13:37:13 +0200122 response = requests.put(query, data=query.split('?', 1)[1], auth=auth, headers=self.headers, verify=self.ssl_verify)
Ales Komarek197f4432016-09-02 15:26:17 +0200123 if query_type == "post":
124 pass
125
126 if not response.ok:
127 return None
128
129 return response
130
131 def query_file_info(self, filename):
132 """
133 Send request to Artifactory API endpoint for file details.
134 @param: filename - Required. The shortname of the artifact
135 """
136 query = "%s/storage/%s" % (self.artifactory_url, filename)
137
138 raw_response = self.query_artifactory(query)
139 if raw_response is None:
140 return raw_response
141 response = json.loads(raw_response.text)
142
143 return response
144
145 def find_by_properties(self, properties):
146 """
147 Look up an artifact, or artifacts, in Artifactory by using artifact properties.
148 @param: properties - List of properties to use as search criteria.
149 """
150 query = "%s/%s?%s" % (self.artifactory_url,
151 self.search_prop, urlencode(properties))
152 raw_response = self.query_artifactory(query)
153 if raw_response is None:
154 return raw_response
155
156 response = json.loads(raw_response.text)
157
158 for item in response['results']:
159 for k, v in item.items():
160 setattr(self, '%s' % (k,), v)
161
162 if not response['results']:
163 return None
164
165 artifact_list = []
166 for u in response['results']:
167 artifact_list.append(os.path.basename(u['uri']))
168
169 self.files = artifact_list
170 setattr(self, 'count', len(artifact_list))
171
172 return "OK"
173
174 def find(self, filename):
175 """
176 Look up an artifact, or artifacts, in Artifactory by
177 its filename.
178 @param: filename - Filename of the artifact to search.
179 """
180 query = "%s/%s?name=%s" % (self.artifactory_url,
181 self.search_name, filename)
182 raw_response = self.query_artifactory(query)
183 if raw_response is None:
184 return raw_response
185 response = json.loads(raw_response.text)
186 if len(response['results']) < 1:
187 return None
188
189 setattr(self, 'name', filename)
190 setattr(self, 'url', json.dumps(response))
191
192 return "OK"
193
194 def get_properties(self, filename, properties=None):
195 """
196 Get an artifact's properties, as defined in the Properties tab in
197 Artifactory.
198 @param: filename - Filename of artifact of which to get properties.
199 @param: properties - Optional. List of properties to help filter results.
200 """
201 if properties:
202 query = "%s?properties=%s" % (filename, ",".join(properties))
203 else:
204 query = "%s?properties" % filename
205
206 raw_response = self.query_artifactory(query)
207 if raw_response is None:
208 return raw_response
209 response = json.loads(raw_response.text)
210 for key, value in response.items():
211 setattr(self, '%s' % (key,), value)
212
213 return "OK"
214
215
216def _client(**connection_args):
217 '''
218 Set up artifactory credentials
219
220 '''
Filip Pytloune46da4f2016-09-13 13:23:17 +0200221
Ales Komarek197f4432016-09-02 15:26:17 +0200222 prefix = "artifactory"
223
224 # look in connection_args first, then default to config file
225 def get(key, default=None):
226 return connection_args.get('connection_' + key,
227 __salt__['config.get'](prefix, {})).get(key, default)
228
229 client_config = {
Filip Pytloun320b2f92016-09-13 13:37:13 +0200230 'artifactory_url': '%s://%s:%s/artifactory/api' % (get('proto', 'http'), get('host', 'localhost'), get('port', '8080')),
231 'ssl_verify': get('ssl_verify', True)
Ales Komarek197f4432016-09-02 15:26:17 +0200232 }
233
234 user = get('user', False)
235 password = get('password', False)
236 if user and password:
237 client_config['username'] = user
238 client_config['password'] = password
239
Filip Pytloune46da4f2016-09-13 13:23:17 +0200240 artifactory_client = ArtifactoryClient(client_config)
Ales Komarek197f4432016-09-02 15:26:17 +0200241
242 return artifactory_client
243
244
245def repo_list(repo_type=None, **connection_args):
246 '''
247 Return a list of available repositories
248
249 CLI Example:
250
251 .. code-block:: bash
252
253 salt '*' artifactory_repo.repo_list
254 salt '*' artifactory_repo.repo_list REMOTE
255 salt '*' artifactory_repo.repo_list LOCAL
256 '''
257 ret = {}
258
259 artifactory = _client(**connection_args)
260 repos = artifactory.get_repositories(repo_type)
261
262 for repo in repos:
263 if 'key' in repo:
264 ret[repo.get('key')] = repo
265 return ret
266
267
268def repo_get(name, **connection_args):
269 '''
270 Return a list of available repositories
271
272 CLI Example:
273
274 .. code-block:: bash
275
276 salt '*' artifactory_repo.repo_get reponame
277 '''
278
279 ret = {}
280
281 repos = repo_list(None, **connection_args)
282 if not name in repos:
283 return {'Error': "Error retrieving repository {0}".format(name)}
284 ret[name] = repos[name]
285 return ret
286
287
288def repo_create(name, repo_type="local", package="generic", url=None, **connection_args):
289 '''
290 Create a artifactory repository
291
292 :param name: new repo name
293 :param repo_type: new repo type
294 :param package: new repo package type
295 "gradle" | "ivy" | "sbt" | "nuget" | "gems" | "npm" | "bower" |
296 "debian" | "pypi" | "docker" | "vagrant" | "gitlfs" | "yum" |
297 "generic"
298
299
300 CLI Examples:
301
302 .. code-block:: bash
303
304 salt '*' artifactory_repo.repo_create projectname remote generic
Filip Pytloune46da4f2016-09-13 13:23:17 +0200305
Ales Komarek197f4432016-09-02 15:26:17 +0200306 '''
307 ret = {}
308
309 if url in connection_args and url == None:
310 url = connection_args['url']
311
312 repo = repo_get(name, **connection_args)
313
314 if repo and not "Error" in repo:
315 log.debug("Repository {0} exists".format(name))
316 return repo
317
318 repo_config = {
319 "key": name,
320 "rclass" : repo_type,
321 "packageType": package,
322 "description": "The local repository public description",
323 }
324
325 if repo_type == "remote":
326 repo_config['url'] = url
327
328 artifactory = _client(**connection_args)
329 artifactory.create_repository(name, repo_config)
330 return repo_get(name, **connection_args)