Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / api / management / commands / server-list.py @ b1fb3aac

History | View | Annotate | Download (5.2 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

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

    
45

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

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

    
74
    object_class = VirtualMachine
75
    deleted_field = "deleted"
76
    user_uuid_field = "userid"
77
    astakos_url = ASTAKOS_BASE_URL
78
    astakos_token = ASTAKOS_TOKEN
79

    
80
    def get_public_ip(vm):
81
        try:
82
            return vm.nics.all()[0].ipv4
83
        except IndexError:
84
            return None
85

    
86
    def format_vm_state(vm):
87
        if vm.operstate == "BUILD":
88
            return "BUILD(" + str(vm.buildpercentage) + "%)"
89
        else:
90
            return vm.operstate
91

    
92
    FIELDS = {
93
        "id": ("id", "ID of the server"),
94
        "name": ("name", "Name of the server"),
95
        "user.uuid": ("userid", "The UUID of the server's owner"),
96
        "flavor": ("flavor.name", "The name of the server's flavor"),
97
        "backend": ("backend", "The Ganeti backend that hosts the VM"),
98
        "image.id": ("imageid", "The ID of the server's image"),
99
        "image.name": ("image", "The name of the server's image"),
100
        "state": (format_vm_state, "The current state of the server"),
101
        "ip": (get_public_ip, "The public IP of the server"),
102
        "created": ("created", "The date the server was created"),
103
        "deleted": ("deleted", "Whether the server is deleted or not"),
104
        "suspended": ("suspended", "Whether the server is administratively"
105
                      " suspended"),
106
    }
107

    
108
    fields = ["id", "name", "user.uuid", "state", "flavor", "image.id",
109
              "backend"]
110

    
111
    def handle_args(self, *args, **options):
112
        if options["suspended"]:
113
            self.filters["suspended"] = True
114

    
115
        if options["backend_id"]:
116
            backend = get_backend(options["backend_id"])
117
            self.filters["backend"] = backend.id
118

    
119
        if options["build"]:
120
            self.filters["operstate"] = "BUILD"
121

    
122
        if options["image_name"]:
123
            self.fields.replace("image.id", "image.name")
124

    
125
    def handle_db_objects(self, rows, *args, **kwargs):
126
        icache = ImageCache()
127
        for vm in rows:
128
            vm.image = icache.get_image(vm.imageid, vm.userid)
129

    
130

    
131
class ImageCache(object):
132
    def __init__(self):
133
        self.images = {}
134

    
135
    def get_image(self, imageid, userid):
136
        if not imageid in self.images:
137
            try:
138
                self.images[imageid] = get_image(imageid, userid)['name']
139
            except Exception as e:
140
                log.warning("Error getting image name from imageid %s: %s",
141
                            imageid, e)
142
                self.images[imageid] = imageid
143

    
144
        return self.images[imageid]