1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import os
20 import sys
21 import time
22 import base64
23
24 import pulp.client.utils as utils
25 import pulp.client.constants as constants
26 from pulp.client.core.basecore import BaseCore, systemExit
27 from pulp.client.connection import RepoConnection, RestlibException
28 from pulp.client.logutil import getLogger
29 from pulp.client.config import Config
30 CFG = Config()
31
32 import gettext
33 _ = gettext.gettext
34 log = getLogger(__name__)
35
36 -class repo(BaseCore):
38 usage = "repo [OPTIONS]"
39 shortdesc = "repository specifc actions to pulp server."
40 desc = ""
41 self.name = "repo"
42 self.actions = actions or {"create" : "Create a repo",
43 "update" : "Update a repo",
44 "list" : "List available repos",
45 "delete" : "Delete a repo",
46 "sync" : "Sync data to this repo from the feed",
47 "cancel_sync": "Cancel a running sync",
48 "upload" : "Upload package(s) to this repo",
49 "schedules" : "List all repo schedules", }
50 BaseCore.__init__(self, "repo", usage, shortdesc, desc)
51
53 self.pconn = RepoConnection(host=CFG.server.host or "localhost",
54 port=CFG.server.port or 443,
55 username=self.username,
56 password=self.password,
57 cert_file=self.cert_filename,
58 key_file=self.key_filename)
60 self.action = self._get_action()
61 if self.action == "create":
62 usage = "repo create [OPTIONS]"
63 self.setup_option_parser(usage, "", True)
64 self.parser.add_option("--id", dest="id",
65 help="Repository Id")
66 self.parser.add_option("--name", dest="name",
67 help="Common repository name")
68 self.parser.add_option("--arch", dest="arch",
69 help="Package arch the repo should support.")
70 self.parser.add_option("--feed", dest="feed",
71 help="Url feed to populate the repo")
72 self.parser.add_option("--cacert", dest="cacert",
73 help="Path location to CA Certificate.")
74 self.parser.add_option("--cert", dest="cert",
75 help="Path location to Entitlement Certificate.")
76 self.parser.add_option("--key", dest="key",
77 help="Path location to Entitlement Cert Key.")
78 self.parser.add_option("--schedule", dest="schedule",
79 help="Schedule for automatically synchronizing the repository")
80 self.parser.add_option("--symlinks", action="store_true", dest="symlinks",
81 help="Use symlinks instead of copying bits locally. \
82 Applicable for local syncs")
83 if self.action == "sync":
84 usage = "repo sync [OPTIONS]"
85 self.setup_option_parser(usage, "", True)
86 self.parser.add_option("--id", dest="id",
87 help="Repository Id")
88 self.parser.add_option("--timeout", dest="timeout",
89 help="Sync Timeout")
90 if self.action == "cancel_sync":
91 usage = "repo cancel_sync [OPTIONS]"
92 self.setup_option_parser(usage, "", True)
93 self.parser.add_option("--id", dest="id",
94 help="Repository Id")
95 self.parser.add_option("--taskid", dest="taskid",
96 help="Task ID")
97 if self.action == "delete":
98 usage = "repo delete [OPTIONS]"
99 self.setup_option_parser(usage, "", True)
100 self.parser.add_option("--id", dest="id",
101 help="Repository Id")
102 if self.action == "list":
103 usage = "repo list [OPTIONS]"
104 self.setup_option_parser(usage, "", True)
105 if self.action == "upload":
106 usage = "repo upload [OPTIONS] <package>"
107 self.setup_option_parser(usage, "", True)
108 self.parser.add_option("--id", dest="id",
109 help="Repository Id")
110 self.parser.add_option("--dir", dest="dir",
111 help="Process packages from this directory")
112 if self.action == "schedules":
113 usage = "repo schedules"
114 self.setup_option_parser(usage, "", True)
115
131
133 if not self.options.id:
134 print("repo id required. Try --help")
135 sys.exit(0)
136 if not self.options.name:
137 self.options.name = self.options.id
138 if not self.options.arch:
139 self.options.arch = "noarch"
140
141 symlinks = False
142 if self.options.symlinks:
143 symlinks = self.options.symlinks
144
145 cert_data = None
146 if self.options.cacert and self.options.cert and self.options.key:
147 cert_data = {"ca" : utils.readFile(self.options.cacert),
148 "cert" : utils.readFile(self.options.cert),
149 "key" : utils.readFile(self.options.key)}
150
151 try:
152 repo = self.pconn.create(self.options.id, self.options.name, \
153 self.options.arch, self.options.feed, \
154 symlinks, self.options.schedule, cert_data=cert_data)
155 print _(" Successfully created Repo [ %s ]" % repo['id'])
156 except RestlibException, re:
157 log.error("Error: %s" % re)
158 systemExit(re.code, re.msg)
159 except Exception, e:
160 log.error("Error: %s" % e)
161 systemExit(e.code, e.msg)
162
164 try:
165 repos = self.pconn.repositories()
166 if not len(repos):
167 print _("No repos available to list")
168 sys.exit(0)
169 print """+-------------------------------------------+\n List of Available Repositories \n+-------------------------------------------+"""
170 for repo in repos:
171
172 print constants.AVAILABLE_REPOS_LIST % (repo["id"], repo["name"],
173 repo["source"], repo["arch"],
174 repo["sync_schedule"], repo["packages"])
175 except RestlibException, re:
176 log.error("Error: %s" % re)
177 systemExit(re.code, re.msg)
178 except Exception, e:
179 log.error("Error: %s" % e)
180 raise
181
183 if not self.options.id:
184 print("repo id required. Try --help")
185 sys.exit(0)
186 try:
187 task_object = self.pconn.sync(self.options.id, self.options.timeout)
188 state = "waiting"
189 print "Task created with ID::", task_object['id']
190 while state not in ["finished", "error", 'timed out', 'canceled']:
191 time.sleep(5)
192 status = self.pconn.sync_status(task_object['status_path'])
193 if status is None:
194 raise SyncError(_('No sync for repository [%s] found') % self.options.id)
195 state = status['state']
196 print "Sync Status::", state
197 packages = self.pconn.packages(self.options.id)
198 pkg_count = 0
199 if packages:
200 pkg_count = len(packages)
201 if state == "error":
202 raise SyncError(status['traceback'][-1])
203 else:
204 print _(" Sync Successful. Repo [ %s ] now has a total of [ %s ] packages" % (self.options.id, pkg_count))
205 except RestlibException, re:
206 log.info("REST Error.", exc_info=True)
207 systemExit(re.code, re.msg)
208 except SyncError, se:
209 log.info("Sync Error: ", exc_info=True)
210 systemExit("Error : %s" % se)
211 except Exception, e:
212 log.error("General Error: %s" % e)
213 raise
214
216 if not self.options.id:
217 print("repo id required. Try --help")
218 sys.exit(0)
219 if not self.options.taskid:
220 print("task id required. Try --help")
221 sys.exit(0)
222 try:
223 repos = self.pconn.cancel_sync(self.options.id, self.options.taskid)
224 print _(" Sync task %s cancelled") % self.options.taskid
225 except RestlibException, re:
226 log.error("Error: %s" % re)
227 systemExit(re.code, re.msg)
228 except Exception, e:
229 log.error("Error: %s" % e)
230 raise
231
233 if not self.options.id:
234 print("repo id required. Try --help")
235 sys.exit(0)
236 try:
237 self.pconn.delete(id=self.options.id)
238 print _(" Successful deleted Repo [ %s ] " % self.options.id)
239 except RestlibException, re:
240 print _(" Deleted operation failed on Repo [ %s ] " % \
241 self.options.id)
242 log.error("Error: %s" % re)
243 sys.exit(-1)
244 except Exception, e:
245 print _(" Deleted operation failed on Repo [ %s ]. " % \
246 self.options.id)
247 log.error("Error: %s" % e)
248 sys.exit(-1)
249
251 (self.options, files) = self.parser.parse_args()
252
253 files = files[2:]
254 if not self.options.id:
255 print("repo id required. Try --help")
256 sys.exit(0)
257 if self.options.dir:
258 files += utils.processDirectory(self.options.dir, "rpm")
259 if not files:
260 print("Need to provide atleast one file to perform upload")
261 sys.exit(0)
262 uploadinfo = {}
263 uploadinfo['repo'] = self.options.id
264 for frpm in files:
265 try:
266 pkginfo = utils.processRPM(frpm)
267 except FileError, e:
268 print('Error: %s' % e)
269 continue
270 if not pkginfo.has_key('nvrea'):
271 print("Package %s is Not an RPM Skipping" % frpm)
272 continue
273 pkgstream = base64.b64encode(open(frpm).read())
274 try:
275 status = self.pconn.upload(self.options.id, pkginfo, pkgstream)
276 if status:
277 print _(" Successful uploaded [%s] to Repo [ %s ] " % (pkginfo['pkgname'], self.options.id))
278 else:
279 print _(" Failed to Upload %s to Repo [ %s ] " % self.options.id)
280 except RestlibException, re:
281 log.error("Error: %s" % re)
282 raise
283 except Exception, e:
284 log.error("Error: %s" % e)
285 raise
286
288 print("""+-------------------------------------+\n Available Repository Schedules \n+-------------------------------------+""")
289
290 schedules = self.pconn.all_schedules()
291 for id in schedules.keys():
292 print(constants.REPO_SCHEDULES_LIST % (id, schedules[id]))
293
294
297
300