This repository has been archived by the owner on Oct 12, 2021. It is now read-only.
/
spacewalk-remove-old-packages.py
266 lines (241 loc) · 11.8 KB
/
spacewalk-remove-old-packages.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#!/usr/bin/python
#
# Deletes older packages from a channel and from Spacewalk
# Author: Martin Zehetmayer <angrox@idle.at>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---------------
#
# This script deletes all old packages from one channel and - if wanted -
# deletes the files from storage as well.
#
# BE CAREFUL WITH THIS SCRIPT! TEST IT BEFORE USING IT IN PRODUCTION!
# I must point again at the "WITHOUT ANY WARRANTY" line :-)
#
# usage: spacewalk-remove-old-packages.py [options]
#
# options:
# -h, --help show this help message and exit
# -s SPW_SERVER, --spw-server=SPW_SERVER
# Spacewalk Server
# -u SPW_USER, --spw-user=SPW_USER
# Spacewalk User
# -p SPW_PASS, --spw-pass=SPW_PASS
# Spacewalk Password
# -f CFG_FILE, --config-file=CFG_FILE
# Config file for servers, users, passwords
# -c CHANNEL, --channel=CHANNEL
# Channel Label: ie."myown-rhel-6-x86_64"
# -A, --all-channels
# Delete packages from all channels. Overwrites the
# channel option
# -w, --without-channels
# Delete packages without channel. Overwrites the
# channel option
# -n, --dryrun No change is actually made, only print what would be
# done
#
#
# The configuration file must be parseable bei ConfigParser:
# Example:
#
# [Spacewalk]
# spw_server = spacewalk.example.com
# spw_user = api_user_1
# spw_pass = api_password_1
import xmlrpclib
import datetime
import ConfigParser
import sys
import os
import getpass
from subprocess import *
from optparse import OptionParser
from pprint import pprint
def parse_args():
parser = OptionParser()
parser.add_option("-s", "--spw-server", type="string", dest="spw_server",
help="Spacewalk Server (default: localhost)", default="localhost")
parser.add_option("-u", "--spw-user", type="string", dest="spw_user",
help="Spacewalk User")
parser.add_option("-p", "--spw-pass", type="string", dest="spw_pass",
help="Spacewalk Password")
parser.add_option("-c", "--config-file", type="string", dest="cfg_file",
help="Config file for servers, users, passwords")
parser.add_option("-C", "--channel", type="string", dest="channel",
help="Channel Label: ie.\"lhm-rhel-6-x86_64\"")
parser.add_option("-A", "--all-channels", action="store_true", dest="all_channel",
help="Delete packages from all channels. Overwrites the channel option")
parser.add_option("-w", "--without-channels", action="store_true", dest="wo_channel",
help="Delete packages without channel. Overwrites the channel option")
parser.add_option("-l", "--with-lucene-search", type="string", dest="lucene",
help="Search packages with the lucene search syntax (see the spacewalk/satellite documentation - API - packages.search - advanced) and tries to delete them")
parser.add_option("-m", "--max", type="int",
help="Limit number of packages removed to MAX. Default: no limit.")
parser.add_option("-n", "--dryrun", action="store_true", dest="dryrun",
help="No change is actually made, only print what would be done")
parser.add_option("-f", "--force", action="store_true", dest="force",
help="Disable check for whether a package is installed on any system (faster)")
parser.add_option("-d", "--debug", action="store_true", dest="debug",
help="Print more junk")
(options,args) = parser.parse_args()
return options
def cmp_dictarray(pkgs, id):
for pkg in pkgs:
for (key,val) in pkg.iteritems():
if val == id:
return True
return False
def main():
# Get the options
options = parse_args()
# read the config
if options.cfg_file:
config = ConfigParser.ConfigParser()
config.read (options.cfg_file)
if options.spw_server is None:
options.spw_server = config.get ('Spacewalk', 'spw_server')
if options.spw_user is None:
options.spw_user = config.get ('Spacewalk', 'spw_user')
if options.spw_pass is None:
options.spw_pass = config.get ('Spacewalk', 'spw_pass')
else:
#ask for username and password if emtpy
while str(options.spw_user) == 'None' or '': options.spw_user = raw_input("Spacewalk Username: ")
while str(options.spw_pass) == 'None' or '': options.spw_pass = getpass.getpass("Spacewalk Password: ")
if options.channel is None and options.wo_channel is None and options.lucene is None and options.all_channel is None:
print "Channel not given, aborting"
sys.exit(2)
spacewalk = xmlrpclib.Server("https://%s/rpc/api" % options.spw_server, verbose=0, allow_none=True)
spacekey = spacewalk.auth.login(options.spw_user, options.spw_pass)
to_delete=[]
to_delete_ids=[]
to_keep={}
# get all packages
if options.wo_channel is None and options.lucene is None and options.all_channel is None:
print "Getting all packages"
allpkgs = spacewalk.channel.software.listAllPackages(spacekey, options.channel)
print " - Amount: %d" % len(allpkgs)
# get newest packages
print "Getting newest packages"
newpkgs = spacewalk.channel.software.listLatestPackages(spacekey, options.channel)
print " - Amount: %d" % len(newpkgs)
for pkg in allpkgs:
if options.max:
if len(to_delete) > options.max:
print "Hit max number of packages, breaking from loop"
break
if len(to_delete_ids) > options.max:
print "Hit max number of packages, breaking from loop"
break
if options.force is not True:
is_installed = spacewalk.system.listSystemsWithPackage(spacekey,pkg['id'])
else:
is_installed = None
if options.debug:
print "Processing package "+pkg['name']+", "+pkg['version']+", installed anywhere ("+str(bool(is_installed))
if not cmp_dictarray(newpkgs, pkg['id']) and not is_installed:
print "Marked: %s-%s-%s (id %s)" % (pkg['name'], pkg['version'], pkg['release'], pkg['id'])
to_delete.append(pkg)
to_delete_ids.append(pkg['id'])
if options.debug:
print "List of packages to delete:"
pprint(to_delete)
print "List of package IDs to delete:"
pprint(to_delete_ids)
print "Removing packages from channel..."
if options.all_channel is not None:
print "Getting all channels"
allchannels1 = spacewalk.channel.listAllChannels(spacekey)
allchannels = sorted(allchannels1, key=lambda k: k['packages'],reverse=True)
print " - Amount: %d" % len(allchannels)
pprint(allchannels)
for chan in allchannels:
if options.max:
if len(to_delete) > options.max:
print "Hit max number of packages, breaking from loop"
break
if len(to_delete_ids) > options.max:
print "Hit max number of packages, breaking from loop"
break
print "Getting all packages from %s" % chan['label']
allpkgs = spacewalk.channel.software.listAllPackages(spacekey, chan['label'])
print " - Amount: %d" % len(allpkgs)
# get newest packages
print "Getting newest packages"
newpkgs = spacewalk.channel.software.listLatestPackages(spacekey, chan['label'])
print " - Amount: %d" % len(newpkgs)
for pkg in allpkgs:
is_installed = None
if options.max:
if len(to_delete) > options.max:
print "Hit max number of packages, breaking from loop"
break
if len(to_delete_ids) > options.max:
print "Hit max number of packages, breaking from loop"
break
if options.force is not True and pkg not in newpkgs:
# don't remove installed packages
is_installed = spacewalk.system.listSystemsWithPackage(spacekey,pkg['id'])
if options.debug:
print str(pkg['name'])+", version "+pkg['version']+" is installed on "+str(len(is_installed))+" systems"
else:
is_installed = None
if not cmp_dictarray(newpkgs, pkg['id']) and len(is_installed) == 0 and pkg['id'] not in to_delete_ids:
to_delete.append(pkg)
to_delete_ids.append(pkg['id'])
print "Marked: %s-%s-%s (id %s)" % (pkg['name'], pkg['version'], pkg['release'], pkg['id'])
pprint(to_delete)
pprint(to_delete_ids)
print "Removing packages from all channels..."
if options.wo_channel is not None:
print "Getting all packages without channel"
to_delete = spacewalk.channel.software.listPackagesWithoutChannel(spacekey)
if options.lucene is not None:
print "Getting all packages which match %s" % options.lucene
to_delete = spacewalk.packages.search.advanced(spacekey, options.lucene)
if options.max:
if len(to_delete) > options.max:
to_delete = to_delete[:options.max]
if len(to_delete_ids) > options.max:
to_delete_ids = to_delete_ids[:options.max]
pprint(to_delete)
print "Packages to remove: %s" % len(to_delete)
if len(to_delete) > 0:
if options.dryrun is None:
if options.wo_channel is None and options.all_channel is None:
print "Removing %d packages from channel %s" % (len(to_delete_ids), options.channel)
ret = spacewalk.channel.software.removePackages(spacekey, options.channel, to_delete_ids)
elif options.all_channel is not None:
print "Removing %d packages from channel %s" % (len(to_delete_ids), chan['label'])
ret = spacewalk.channel.software.removePackages(spacekey, chan['label'], to_delete_ids)
elif options.wo_channel is None and options.all_channel is None:
print "Dryrun: Removing %d packages from channel %s" % (len(to_delete_ids), options.channel)
print "Deleting packages from spacewalk (if packages could not be removed they are maybe in another channel too)"
for pkg in to_delete:
if options.dryrun is not None:
print "Dryrun: - Delete package %s-%s-%s (ID: %s)" % (pkg['name'], pkg['version'], pkg['release'], pkg['id'])
else:
print "Deleting package %s-%s-%s (ID: %s)" % (pkg['name'], pkg['version'], pkg['release'],pkg['id'])
try:
ret = spacewalk.packages.removePackage(spacekey, pkg['id'])
if ret != 1:
print " - Could not delete package %s-%s-%s (ID: %s)" % (pkg['name'], pkg['version'], pkg['release'],pkg['id'])
except:
print " - Could not delete package from Spacewalk"
## MAIN
if __name__ == "__main__":
main()