Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / management / commands / server-list.py @ a6a70f40

History | View | Annotate | Download (5.7 kB)

1
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from optparse import make_option
35
from functools import partial
36

    
37
from snf_django.management.commands import ListCommand
38
from synnefo.db.models import VirtualMachine
39
from synnefo.management.common import get_backend
40
from synnefo.api.util import get_image
41
from synnefo.settings import (CYCLADES_SERVICE_TOKEN as ASTAKOS_TOKEN,
42
                              ASTAKOS_AUTH_URL)
43
from logging import getLogger
44
log = getLogger(__name__)
45

    
46

    
47
class Command(ListCommand):
48
    help = "List servers"
49

    
50
    option_list = ListCommand.option_list + (
51
        make_option(
52
            '--suspended',
53
            action='store_true',
54
            dest='suspended',
55
            default=False,
56
            help="List only suspended servers"),
57
        make_option(
58
            '--backend-id',
59
            dest='backend_id',
60
            help="List only servers of the specified backend"),
61
        make_option(
62
            "--build",
63
            action="store_true",
64
            dest="build",
65
            default=False,
66
            help="List only servers in the building state"),
67
        make_option(
68
            "--image-name",
69
            action="store_true",
70
            dest="image_name",
71
            default=False,
72
            help="Display image name instead of image ID"),
73
    )
74

    
75
    object_class = VirtualMachine
76
    deleted_field = "deleted"
77
    user_uuid_field = "userid"
78
    astakos_auth_url = ASTAKOS_AUTH_URL
79
    astakos_token = ASTAKOS_TOKEN
80

    
81
    def get_ips(version, vm):
82
        ips = []
83
        for nic in vm.nics.all():
84
            for ip in nic.ips.all():
85
                if ip.subnet.ipversion == version:
86
                    ips.append(ip.address)
87
        return ips
88

    
89
    def format_vm_state(vm):
90
        if vm.operstate == "BUILD":
91
            return "BUILD(" + str(vm.buildpercentage) + "%)"
92
        else:
93
            return vm.operstate
94

    
95
    FIELDS = {
96
        "id": ("id", "ID of the server"),
97
        "name": ("name", "Name of the server"),
98
        "user.uuid": ("userid", "The UUID of the server's owner"),
99
        "flavor": ("flavor.name", "The name of the server's flavor"),
100
        "backend": ("backend", "The Ganeti backend that hosts the VM"),
101
        "image.id": ("imageid", "The ID of the server's image"),
102
        "image.name": ("image", "The name of the server's image"),
103
        "state": (format_vm_state, "The current state of the server"),
104
        "ipv4": (partial(get_ips, 4),
105
                 "The IPv4 addresses of the server"),
106
        "ipv6": (partial(get_ips, 6),
107
                 "The IPv6 addresses of the server"),
108
        "created": ("created", "The date the server was created"),
109
        "deleted": ("deleted", "Whether the server is deleted or not"),
110
        "suspended": ("suspended", "Whether the server is administratively"
111
                      " suspended"),
112
        "project": ("project", "The project UUID"),
113
    }
114

    
115
    fields = ["id", "name", "user.uuid", "state", "flavor", "image.id",
116
              "backend"]
117

    
118
    def handle_args(self, *args, **options):
119
        if options["suspended"]:
120
            self.filters["suspended"] = True
121

    
122
        if options["backend_id"]:
123
            backend = get_backend(options["backend_id"])
124
            self.filters["backend"] = backend.id
125

    
126
        if options["build"]:
127
            self.filters["operstate"] = "BUILD"
128

    
129
        if options["image_name"]:
130
            self.fields = ["image.name" if x == "image.id" else x
131
                           for x in self.fields]
132

    
133
        if "ipv4" in self.fields or "ipv6" in self.fields:
134
            self.prefetch_related.append("nics__ips__subnet")
135

    
136
    def handle_db_objects(self, rows, *args, **kwargs):
137
        if "image.name" in self.fields:
138
            icache = ImageCache()
139
            for vm in rows:
140
                vm.image = icache.get_image(vm.imageid, vm.userid)
141

    
142

    
143
class ImageCache(object):
144
    def __init__(self):
145
        self.images = {}
146

    
147
    def get_image(self, imageid, userid):
148
        if not imageid in self.images:
149
            try:
150
                self.images[imageid] = get_image(imageid, userid)['name']
151
            except Exception as e:
152
                log.warning("Error getting image name from imageid %s: %s",
153
                            imageid, e)
154
                self.images[imageid] = imageid
155

    
156
        return self.images[imageid]