~andrewjbeach/juju-ci-tools/make-local-patcher

« back to all changes in this revision

Viewing changes to winazure.py

  • Committer: John George
  • Date: 2015-01-14 22:03:47 UTC
  • mto: This revision was merged to the branch mainline in revision 798.
  • Revision ID: john.george@canonical.com-20150114220347-e8q5wezs1qg9a00u
Added support for setting the juju path, series and agent_url.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
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
6
 
 
7
 
from __future__ import print_function
8
 
 
9
 
from argparse import ArgumentParser
10
 
from datetime import (
11
 
    datetime,
12
 
    timedelta,
13
 
)
14
 
import fnmatch
15
 
import os
16
 
import sys
17
 
from time import sleep
18
 
 
19
 
from azure.servicemanagement import (
20
 
    AZURE_MANAGEMENT_CERTFILE,
21
 
    AZURE_MANAGEMENT_SUBSCRIPTIONID,
22
 
    ServiceManagementService,
23
 
)
24
 
from utility import until_timeout
25
 
 
26
 
 
27
 
OLD_MACHINE_AGE = 12
28
 
DATETIME_PATTERN = '%Y-%m-%dT%H:%M:%SZ'
29
 
SUCCEEDED = 'Succeeded'
30
 
 
31
 
 
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 == '')
36
 
        if unused:
37
 
            if verbose:
38
 
                print("Deleting {}".format(disk.name))
39
 
            if not dry_run:
40
 
                sms.delete_disk(disk.name, delete_vhd=True)
41
 
        else:
42
 
            if verbose:
43
 
                print("Skipping {}".format(disk.name))
44
 
 
45
 
 
46
 
def list_services(sms, glob='*', verbose=False):
47
 
    services = []
48
 
    all_services = sms.list_hosted_services()
49
 
    for service in all_services:
50
 
        if not fnmatch.fnmatch(service.service_name, glob):
51
 
            continue
52
 
        if verbose:
53
 
            print(service.service_name)
54
 
        services.append(service)
55
 
    return services
56
 
 
57
 
 
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)
62
 
        age = now - created
63
 
        if age > ago:
64
 
            hours_old = (age.seconds / 3600) + (age.days * 24)
65
 
            if verbose:
66
 
                print('{} is {} hours old:'.format(deployment.name, hours_old))
67
 
                print('  {}'.format(deployment.created_time))
68
 
            return True
69
 
    return False
70
 
 
71
 
 
72
 
def wait_for_success(sms, request, pause=3, verbose=False):
73
 
    for ignored in until_timeout(600):
74
 
        if verbose:
75
 
            print('.', end='')
76
 
            sys.stdout.flush()
77
 
        sleep(pause)
78
 
        op = sms.get_operation_status(request.request_id)
79
 
        if op.status == SUCCEEDED:
80
 
            break
81
 
 
82
 
 
83
 
def delete_service(sms, service, deployments,
84
 
                   pause=3, dry_run=False, verbose=False):
85
 
    for deployment in deployments:
86
 
        if verbose:
87
 
            print("Deleting deployment {}".format(deployment.name))
88
 
        if not dry_run:
89
 
            request = sms.delete_deployment(
90
 
                service.service_name, deployment.name)
91
 
            wait_for_success(sms, request, pause=pause, verbose=verbose)
92
 
    if verbose:
93
 
        print("Deleting service {}".format(service.service_name))
94
 
    if not dry_run:
95
 
        sms.delete_hosted_service(service.service_name)
96
 
 
97
 
 
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,
108
 
                                 verbose=verbose):
109
 
            if len(properties.deployments) == 0 and verbose:
110
 
                print("{} does not have deployements".format(name))
111
 
            continue
112
 
        delete_service(
113
 
            sms, service, properties.deployments,
114
 
            pause=pause, dry_run=dry_run, verbose=verbose)
115
 
 
116
 
 
117
 
def parse_args(args=None):
118
 
    """Return the argument parser for this program."""
119
 
    parser = ArgumentParser('Query and manage azure.')
120
 
    parser.add_argument(
121
 
        '-d', '--dry-run', action='store_true', default=False,
122
 
        help='Do not make changes.')
123
 
    parser.add_argument(
124
 
        '-v', '--verbose', action="store_true", help='Increse verbosity.')
125
 
    parser.add_argument(
126
 
        "-c", "--cert-file", dest="certificate_path",
127
 
        help="The certificate path. Environment: $AZURE_MANAGEMENT_CERTFILE.",
128
 
        default=os.environ.get(AZURE_MANAGEMENT_CERTFILE))
129
 
    parser.add_argument(
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(
144
 
        'delete-services',
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.")
156
 
    return args
157
 
 
158
 
 
159
 
def main(argv):
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':
167
 
        delete_services(
168
 
            sms, glob=args.filter, old_age=args.old_age,
169
 
            dry_run=args.dry_run, verbose=args.verbose)
170
 
    return 0
171
 
 
172
 
 
173
 
if __name__ == '__main__':
174
 
    sys.exit(main(sys.argv[1:]))