2
# The azure lib checks the environment for two vars that can be sourced
3
# or defined before the command.
4
# export AZURE_MANAGEMENT_SUBSCRIPTIONID=ID
5
# export AZURE_MANAGEMENT_CERTFILE=path/to/azure.pem
7
from __future__ import print_function
9
from argparse import ArgumentParser
10
from datetime import (
17
from time import sleep
19
from azure.servicemanagement import (
20
AZURE_MANAGEMENT_CERTFILE,
21
AZURE_MANAGEMENT_SUBSCRIPTIONID,
22
ServiceManagementService,
24
from utility import until_timeout
28
DATETIME_PATTERN = '%Y-%m-%dT%H:%M:%SZ'
29
SUCCEEDED = 'Succeeded'
32
def delete_unused_disks(sms, dry_run=False, verbose=False):
33
for disk in sms.list_disks():
34
unused = (not disk.attached_to or
35
disk.attached_to.hosted_service_name == '')
38
print("Deleting {}".format(disk.name))
40
sms.delete_disk(disk.name, delete_vhd=True)
43
print("Skipping {}".format(disk.name))
46
def list_services(sms, glob='*', verbose=False):
48
all_services = sms.list_hosted_services()
49
for service in all_services:
50
if not fnmatch.fnmatch(service.service_name, glob):
53
print(service.service_name)
54
services.append(service)
58
def is_old_deployment(deployments, now, ago, verbose=False):
59
for deployment in deployments:
60
created = datetime.strptime(
61
deployment.created_time, DATETIME_PATTERN)
64
hours_old = (age.seconds / 3600) + (age.days * 24)
66
print('{} is {} hours old:'.format(deployment.name, hours_old))
67
print(' {}'.format(deployment.created_time))
72
def wait_for_success(sms, request, pause=3, verbose=False):
73
for ignored in until_timeout(600):
78
op = sms.get_operation_status(request.request_id)
79
if op.status == SUCCEEDED:
83
def delete_service(sms, service, deployments,
84
pause=3, dry_run=False, verbose=False):
85
for deployment in deployments:
87
print("Deleting deployment {}".format(deployment.name))
89
request = sms.delete_deployment(
90
service.service_name, deployment.name)
91
wait_for_success(sms, request, pause=pause, verbose=verbose)
93
print("Deleting service {}".format(service.service_name))
95
sms.delete_hosted_service(service.service_name)
98
def delete_services(sms, glob='*', old_age=OLD_MACHINE_AGE,
99
pause=3, dry_run=False, verbose=False):
100
now = datetime.utcnow()
101
ago = timedelta(hours=old_age)
102
services = list_services(sms, glob=glob, verbose=False)
103
for service in services:
104
name = service.service_name
105
properties = sms.get_hosted_service_properties(
106
name, embed_detail=True)
107
if not is_old_deployment(properties.deployments, now, ago,
109
if len(properties.deployments) == 0 and verbose:
110
print("{} does not have deployements".format(name))
113
sms, service, properties.deployments,
114
pause=pause, dry_run=dry_run, verbose=verbose)
117
def parse_args(args=None):
118
"""Return the argument parser for this program."""
119
parser = ArgumentParser('Query and manage azure.')
121
'-d', '--dry-run', action='store_true', default=False,
122
help='Do not make changes.')
124
'-v', '--verbose', action="store_true", help='Increse verbosity.')
126
"-c", "--cert-file", dest="certificate_path",
127
help="The certificate path. Environment: $AZURE_MANAGEMENT_CERTFILE.",
128
default=os.environ.get(AZURE_MANAGEMENT_CERTFILE))
130
'-s', '--subscription-id', dest='subscription_id',
131
help=("The subscription id to make requests with. "
132
"Environment: $AZURE_MANAGEMENT_SUBSCRIPTIONID."),
133
default=os.environ.get(AZURE_MANAGEMENT_SUBSCRIPTIONID))
134
subparsers = parser.add_subparsers(help='sub-command help', dest="command")
135
subparsers.add_parser(
136
'delete-unused-disks',
137
help='Delete unsed disks and files left behind by services.')
138
ls_parser = subparsers.add_parser(
139
'list-services', help='List running services.')
140
ls_parser.add_argument(
141
'filter', default='*', nargs='?',
142
help='A glob pattern to match services to.')
143
ds_parser = subparsers.add_parser(
145
help='delete running services and their deployments.')
146
ds_parser.add_argument(
147
'-o', '--old-age', default=OLD_MACHINE_AGE, type=int,
148
help='Set old machine age to n hours.')
149
ds_parser.add_argument(
150
'filter', help='An exact name or glob pattern to match services to.')
151
args = parser.parse_args(args)
152
if not args.certificate_path or not args.certificate_path.endswith('.pem'):
153
print("$AZURE_MANAGEMENT_CERTFILE is not a pem file.")
154
if not args.subscription_id:
155
print("$AZURE_MANAGEMENT_SUBSCRIPTIONID was not provided.")
160
args = parse_args(argv)
161
sms = ServiceManagementService(args.subscription_id, args.certificate_path)
162
if args.command == 'delete-unused-disks':
163
delete_unused_disks(sms, dry_run=args.dry_run, verbose=args.verbose)
164
elif args.command == 'list-services':
165
list_services(sms, glob=args.filter, verbose=args.verbose)
166
elif args.command == 'delete-services':
168
sms, glob=args.filter, old_age=args.old_age,
169
dry_run=args.dry_run, verbose=args.verbose)
173
if __name__ == '__main__':
174
sys.exit(main(sys.argv[1:]))