8
8
from kubernetes .client .rest import ApiException
9
9
from termcolor import cprint
10
10
11
+ args = None
12
+
11
13
def annotate (api , kind : str , name : str , namespace : str , value : str ):
12
14
'''
13
15
Annotate a kube resource with its original number of replicas
@@ -19,7 +21,13 @@ def annotate(api, kind: str, name: str, namespace: str, value: str):
19
21
value = str (value )
20
22
21
23
body = {"metadata" : {"annotations" : {
22
- 'kubescaledown/originalReplicas' : str (value )}}}
24
+ 'kubescaledown/originalReplicas' : value }}}
25
+
26
+ if args .verbose :
27
+ if value is None :
28
+ print (f"Removing annotation kubescaledown/originalReplicas from { kind } { namespace } /{ name } " )
29
+ else :
30
+ print (f"Annotating { kind } { namespace } /{ name } with kubescaledown/originalReplicas: { value } " )
23
31
24
32
match kind :
25
33
case "Deployment" :
@@ -103,6 +111,9 @@ def upscale(api, kind: str, obj, dry_run: bool):
103
111
namespace = obj .metadata .namespace
104
112
name = obj .metadata .name
105
113
replicas = int (obj .spec .replicas )
114
+ if args .verbose :
115
+ print (f"Getting original replica count from { kind } { namespace } /{ name } " )
116
+
106
117
try :
107
118
original_replicas = int (
108
119
obj .metadata .annotations ['kubescaledown/originalReplicas' ])
@@ -111,6 +122,8 @@ def upscale(api, kind: str, obj, dry_run: bool):
111
122
except ValueError :
112
123
return
113
124
except KeyError :
125
+ if args .verbose :
126
+ print (f"{ kind } { namespace } /{ name } was not previously annotated" )
114
127
return
115
128
116
129
# Remove the annotation, and scale back up
@@ -133,6 +146,8 @@ def main():
133
146
help = "scale up to restore state" , action = 'store_true' )
134
147
parser .add_argument (
135
148
'--dry-run' , help = "don't actually scale anything" , action = 'store_true' )
149
+ parser .add_argument ('-v' , '--verbose' ,
150
+ help = "enable verbose output" , action = argparse .BooleanOptionalAction )
136
151
parser .add_argument ('-n' , '--namespace' ,
137
152
help = "namespace to operate on" , type = str )
138
153
parser .add_argument ("--deployments" , help = "scale Deployments" ,
@@ -141,6 +156,8 @@ def main():
141
156
default = True , action = argparse .BooleanOptionalAction )
142
157
parser .add_argument ("--storageclass" , help = "only scale pods that are consuming a specific storageclass" ,
143
158
type = str )
159
+ # pylint: disable=global-statement
160
+ global args
144
161
args = parser .parse_args ()
145
162
146
163
# connect to cluster
@@ -151,14 +168,20 @@ def main():
151
168
# Determine whether namespaced or global, and fetch list of Deployments
152
169
if args .namespace :
153
170
# do namespaced
171
+ if args .verbose :
172
+ print (f"Operating on namespace { args .namespace } " )
154
173
if args .deployments :
174
+ if args .verbose :
175
+ print (f"Getting deployments in namespace { args .namespace } " )
155
176
try :
156
177
deployments = apps_v1 .list_namespaced_deployment (
157
178
namespace = args .namespace )
158
179
except ApiException as e :
159
180
print (
160
181
f"Exception when calling AppsV1Api->list_namespaced_deployment: { e } \n " )
161
182
if args .statefulsets :
183
+ if args .verbose :
184
+ print (f"Getting statefulsets in namespace { args .namespace } " )
162
185
try :
163
186
statefulsets = apps_v1 .list_namespaced_stateful_set (
164
187
namespace = args .namespace )
@@ -167,13 +190,19 @@ def main():
167
190
f"Exception when calling AppsV1Api->list_namespaced_stateful_set: { e } \n " )
168
191
else :
169
192
# do global
193
+ if args .verbose :
194
+ print ("Operating on all namespaces" )
170
195
if args .deployments :
196
+ if args .verbose :
197
+ print ("Getting all deployments" )
171
198
try :
172
199
deployments = apps_v1 .list_deployment_for_all_namespaces ()
173
200
except ApiException as e :
174
201
print (
175
202
f"Exception when calling AppsV1Api->list_deployment_for_all_namespaces: { e } \n " )
176
203
if args .statefulsets :
204
+ if args .verbose :
205
+ print ("Getting all statefulsets" )
177
206
try :
178
207
statefulsets = apps_v1 .list_stateful_set_for_all_namespaces ()
179
208
except ApiException as e :
@@ -183,8 +212,14 @@ def main():
183
212
# remove any deployment or statefulset from the list that doesn't reference this storageclass
184
213
if args .storageclass :
185
214
215
+ if args .verbose :
216
+ print (f"Checking deployments and statefulsets for storageclass { args .storageclass } " )
217
+
218
+
186
219
# for deployments, get the PVCs from the Deployment and get the SC from the PVC
187
220
for deployment in deployments .items :
221
+ if args .verbose :
222
+ print (f"Working on deployment { deployment .metadata .name } /{ deployment .metadata .namespace } " )
188
223
to_be_scaled = False
189
224
190
225
# get full deployment details
@@ -235,16 +270,24 @@ def main():
235
270
if args .up :
236
271
if args .deployments :
237
272
for deployment in deployments .items :
273
+ if args .verbose :
274
+ print (f"Working on deployment { deployment .metadata .name } /{ deployment .metadata .namespace } " )
238
275
upscale (apps_v1 , "Deployment" , deployment , args .dry_run )
239
276
if args .statefulsets :
240
277
for statefulset in statefulsets .items :
278
+ if args .verbose :
279
+ print (f"Working on statefulset { statefulset .metadata .name } /{ statefulset .metadata .namespace } " )
241
280
upscale (apps_v1 , "StatefulSet" , statefulset , args .dry_run )
242
281
elif args .down :
243
282
if args .deployments :
244
283
for deployment in deployments .items :
284
+ if args .verbose :
285
+ print (f"Working on deployment { deployment .metadata .name } /{ deployment .metadata .namespace } " )
245
286
downscale (apps_v1 , "Deployment" , deployment , args .dry_run )
246
287
if args .statefulsets :
247
288
for statefulset in statefulsets .items :
289
+ if args .verbose :
290
+ print (f"Working on statefulset { statefulset .metadata .name } /{ statefulset .metadata .namespace } " )
248
291
downscale (apps_v1 , "StatefulSet" , statefulset , args .dry_run )
249
292
250
293
if __name__ == '__main__' :
0 commit comments