blob: 674d0fc5c71fe6a67591ec5342ac56008695dd00 [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',
53 'headers': {'Content-type': 'application/json'}
54 }
55
56 client_config.update(config)
57
58 # Set instance variables for every value in party_config
59 for k, v in client_config.items():
60 setattr(self, '%s' % (k,), v)
61
62 def create_repository(self, name, config, **connection_args):
63 repositories = []
64
65 query = "%s/%s/%s" % (self.artifactory_url, self.search_repos, name)
66 auth = (self.username, self.password)
67
68 r = requests.put(query, auth=auth, json=config)
69 print(r.content)
70
71 raw_response = self.query_artifactory(query)
72 if raw_response is None:
73 return []
74 response = json.loads(raw_response.text)
75 for line in response:
76 for item in line:
77 repositories.append(line)
78
79 if repositories:
80 return repositories
81
82 return []
83
84
85 def get_repositories(self, repo_type=None, **connection_args):
86 repositories = []
87
88 if repo_type is None:
89 query = "%s/%s" % (self.artifactory_url, self.search_repos)
90 else:
91 query = "%s/%s?type=%s" % (self.artifactory_url,
92 self.search_repos, repo_type)
93
94 raw_response = self.query_artifactory(query)
95 if raw_response is None:
96 return []
97 response = json.loads(raw_response.text)
98 for line in response:
99 for item in line:
100 repositories.append(line)
101
102 if repositories:
103 return repositories
104
105 return []
106
107
108 def query_artifactory(self, query, query_type='get'):
109 """
110 Send request to Artifactory API endpoint.
111 @param: query - Required. The URL (including endpoint) to send to the Artifactory API
112 @param: query_type - Optional. CRUD method. Defaults to 'get'.
113 """
114
115 auth = (self.username, self.password)
116 query_type = query_type.lower()
117
118 if query_type == "get":
119 response = requests.get(query, auth=auth, headers=self.headers)
120 elif query_type == "put":
121 response = requests.put(query, data=query.split('?', 1)[1], auth=auth, headers=self.headers)
122 if query_type == "post":
123 pass
124
125 if not response.ok:
126 return None
127
128 return response
129
130 def query_file_info(self, filename):
131 """
132 Send request to Artifactory API endpoint for file details.
133 @param: filename - Required. The shortname of the artifact
134 """
135 query = "%s/storage/%s" % (self.artifactory_url, filename)
136
137 raw_response = self.query_artifactory(query)
138 if raw_response is None:
139 return raw_response
140 response = json.loads(raw_response.text)
141
142 return response
143
144 def find_by_properties(self, properties):
145 """
146 Look up an artifact, or artifacts, in Artifactory by using artifact properties.
147 @param: properties - List of properties to use as search criteria.
148 """
149 query = "%s/%s?%s" % (self.artifactory_url,
150 self.search_prop, urlencode(properties))
151 raw_response = self.query_artifactory(query)
152 if raw_response is None:
153 return raw_response
154
155 response = json.loads(raw_response.text)
156
157 for item in response['results']:
158 for k, v in item.items():
159 setattr(self, '%s' % (k,), v)
160
161 if not response['results']:
162 return None
163
164 artifact_list = []
165 for u in response['results']:
166 artifact_list.append(os.path.basename(u['uri']))
167
168 self.files = artifact_list
169 setattr(self, 'count', len(artifact_list))
170
171 return "OK"
172
173 def find(self, filename):
174 """
175 Look up an artifact, or artifacts, in Artifactory by
176 its filename.
177 @param: filename - Filename of the artifact to search.
178 """
179 query = "%s/%s?name=%s" % (self.artifactory_url,
180 self.search_name, filename)
181 raw_response = self.query_artifactory(query)
182 if raw_response is None:
183 return raw_response
184 response = json.loads(raw_response.text)
185 if len(response['results']) < 1:
186 return None
187
188 setattr(self, 'name', filename)
189 setattr(self, 'url', json.dumps(response))
190
191 return "OK"
192
193 def get_properties(self, filename, properties=None):
194 """
195 Get an artifact's properties, as defined in the Properties tab in
196 Artifactory.
197 @param: filename - Filename of artifact of which to get properties.
198 @param: properties - Optional. List of properties to help filter results.
199 """
200 if properties:
201 query = "%s?properties=%s" % (filename, ",".join(properties))
202 else:
203 query = "%s?properties" % filename
204
205 raw_response = self.query_artifactory(query)
206 if raw_response is None:
207 return raw_response
208 response = json.loads(raw_response.text)
209 for key, value in response.items():
210 setattr(self, '%s' % (key,), value)
211
212 return "OK"
213
214
215def _client(**connection_args):
216 '''
217 Set up artifactory credentials
218
219 '''
220
221 prefix = "artifactory"
222
223 # look in connection_args first, then default to config file
224 def get(key, default=None):
225 return connection_args.get('connection_' + key,
226 __salt__['config.get'](prefix, {})).get(key, default)
227
228 client_config = {
229 'artifactory_url': 'http://%s:%s/artifactory/api' % (get('host', 'localhost'), get('port', '8080'))
230 }
231
232 user = get('user', False)
233 password = get('password', False)
234 if user and password:
235 client_config['username'] = user
236 client_config['password'] = password
237
238 artifactory_client = ArtifactoryClient(client_config)
239
240 return artifactory_client
241
242
243def repo_list(repo_type=None, **connection_args):
244 '''
245 Return a list of available repositories
246
247 CLI Example:
248
249 .. code-block:: bash
250
251 salt '*' artifactory_repo.repo_list
252 salt '*' artifactory_repo.repo_list REMOTE
253 salt '*' artifactory_repo.repo_list LOCAL
254 '''
255 ret = {}
256
257 artifactory = _client(**connection_args)
258 repos = artifactory.get_repositories(repo_type)
259
260 for repo in repos:
261 if 'key' in repo:
262 ret[repo.get('key')] = repo
263 return ret
264
265
266def repo_get(name, **connection_args):
267 '''
268 Return a list of available repositories
269
270 CLI Example:
271
272 .. code-block:: bash
273
274 salt '*' artifactory_repo.repo_get reponame
275 '''
276
277 ret = {}
278
279 repos = repo_list(None, **connection_args)
280 if not name in repos:
281 return {'Error': "Error retrieving repository {0}".format(name)}
282 ret[name] = repos[name]
283 return ret
284
285
286def repo_create(name, repo_type="local", package="generic", url=None, **connection_args):
287 '''
288 Create a artifactory repository
289
290 :param name: new repo name
291 :param repo_type: new repo type
292 :param package: new repo package type
293 "gradle" | "ivy" | "sbt" | "nuget" | "gems" | "npm" | "bower" |
294 "debian" | "pypi" | "docker" | "vagrant" | "gitlfs" | "yum" |
295 "generic"
296
297
298 CLI Examples:
299
300 .. code-block:: bash
301
302 salt '*' artifactory_repo.repo_create projectname remote generic
303
304 '''
305 ret = {}
306
307 if url in connection_args and url == None:
308 url = connection_args['url']
309
310 repo = repo_get(name, **connection_args)
311
312 if repo and not "Error" in repo:
313 log.debug("Repository {0} exists".format(name))
314 return repo
315
316 repo_config = {
317 "key": name,
318 "rclass" : repo_type,
319 "packageType": package,
320 "description": "The local repository public description",
321 }
322
323 if repo_type == "remote":
324 repo_config['url'] = url
325
326 artifactory = _client(**connection_args)
327 artifactory.create_repository(name, repo_config)
328 return repo_get(name, **connection_args)