Revision 475d4a85

/dev/null
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
import itertools
35
import warnings
36
import functools
37

  
38
from optparse import make_option
39

  
40
from django.core.management.base import NoArgsCommand, CommandError, BaseCommand
41
from django.db import transaction
42
from django.conf import settings
43

  
44
from synnefo.api.util import get_existing_users
45
from synnefo.lib.utils import case_unique
46
from synnefo.db.models import Network, VirtualMachine
47
from synnefo.userdata.models import PublicKeyPair
48

  
49
from snf_django.lib import astakos
50

  
51
def warn(*msgs):
52
    print "WARNING: %s" % ' '.join(msgs)
53

  
54
get_displayname = functools.partial(astakos.get_displayname,
55
                                 settings.CYCLADES_SERVICE_TOKEN,
56
                                 url=settings.ASTAKOS_URL.replace('im/authenticate',
57
                                                                 'service/api/user_catalogs'))
58
get_user_uuid = functools.partial(astakos.get_user_uuid,
59
                                 settings.CYCLADES_SERVICE_TOKEN,
60
                                 url=settings.ASTAKOS_URL.replace('im/authenticate',
61
                                                                 'service/api/user_catalogs'))
62

  
63
def _validate_db_state(usernames):
64

  
65
    usernames = filter(bool, usernames)
66
    invalid_case_users = case_unique(usernames)
67
    if invalid_case_users:
68
        invalid_case_users.append(invalid_case_users[0].lower())
69
        raise CommandError("Duplicate case insensitive user identifiers exist %r" % invalid_case_users)
70

  
71
    uuidusers = filter(lambda uid:'@' in uid or uid == None, usernames)
72
    if len(uuidusers) != len(usernames):
73
        warn('It seems that mixed uuid/email user identifiers exist in database.')
74
        return False
75

  
76
    return True
77

  
78

  
79
@transaction.commit_manually
80
def delete_user(username, only_stats=True, dry=True):
81
    vms = VirtualMachine.objects.filter(userid__exact=username)
82
    networks = Network.objects.filter(userid__exact=username)
83
    keys = PublicKeyPair.objects.filter(user__exact=username)
84

  
85
    if not len(list(itertools.ifilter(bool, map(lambda q: q.count(), [vms,
86
                                                                      networks,
87
                                                                      keys])))):
88
        print "No entries exist for '%s'" % username
89
        return -1
90

  
91
    if only_stats:
92
        print "The following entries will be deleted if you decide to remove this user"
93
        print "%d Virtual Machines" % vms.exclude(operstate='DESTROYED').count()
94
        print "%d Destroyed Virtual Machines" % vms.filter(operstate='DESTROYED').count()
95
        print "%d Networks" % networks.count()
96
        print "%d PublicKeyPairs" % keys.count()
97
        return
98

  
99
    for o in itertools.chain(vms, networks):
100
        o.delete()
101

  
102
    for key in keys:
103
        key.delete()
104

  
105
    if dry:
106
        print "Skipping database commit."
107
        transaction.rollback()
108
    else:
109
        transaction.commit()
110
        print "User entries removed."
111

  
112

  
113
@transaction.commit_on_success
114
def merge_user(username):
115
    vms = VirtualMachine.objects.filter(userid__iexact=username)
116
    networks = Network.objects.filter(userid__iexact=username)
117
    keys = PublicKeyPair.objects.filter(user__iexact=username)
118

  
119
    for o in itertools.chain(vms, networks):
120
        o.userid = username.lower()
121
        o.save()
122

  
123
    for key in keys:
124
        key.user = username.lower()
125
        key.save()
126

  
127

  
128
def migrate_user(username, uuid):
129
    """
130
    Warn: no transaction handling. Consider wrapping within another function.
131
    """
132
    vms = VirtualMachine.objects.filter(userid__exact=username)
133
    networks = Network.objects.filter(userid__exact=username)
134
    keys = PublicKeyPair.objects.filter(user__exact=username)
135

  
136
    for o in itertools.chain(vms, networks):
137
        o.userid = uuid or o.userid
138
        o.save()
139

  
140
    for key in keys:
141
        key.user = uuid
142
        key.save()
143

  
144

  
145
@transaction.commit_manually
146
def migrate_users(usernames, dry=True):
147
    usernames = filter(bool, usernames)
148
    count = 0
149
    for u in usernames:
150
        if not '@' in u:
151
            warn('Skipping %s. It doesn\'t seem to be an email' % u)
152
            continue
153

  
154
        try:
155
            uuid = get_user_uuid(u)
156
            print "%s -> %s" % (u, uuid)
157
            if not uuid:
158
                raise Exception("No uuid for %s" % u)
159
            migrate_user(u, uuid)
160
            count += 1
161
        except Exception, e:
162
            print "ERROR: User id migration failed (%s)" % e
163

  
164
    if dry:
165
        print "Skipping database commit."
166
        transaction.rollback()
167
    else:
168
        transaction.commit()
169
        print "Migrated %d users" % count
170

  
171

  
172
class Command(NoArgsCommand):
173
    help = "Quotas migration helper"
174

  
175
    option_list = BaseCommand.option_list + (
176
        make_option('--strict',
177
                    dest='strict',
178
                    action="store_false",
179
                    default=True,
180
                    help="Exit on warnings."),
181
        make_option('--validate-db',
182
                    dest='validate',
183
                    action="store_true",
184
                    default=True,
185
                    help=("Check if cyclades database contents are valid for "
186
                          "migration.")),
187
        make_option('--migrate-users',
188
                    dest='migrate_users',
189
                    action="store_true",
190
                    default=False,
191
                    help=("Convert emails to uuids for all users stored in "
192
                          "database.")),
193
        make_option('--merge-user',
194
                    dest='merge_user',
195
                    default=False,
196
                    help="Merge case insensitive duplicates of a user."),
197
        make_option('--delete-user',
198
                    dest='delete_user',
199
                    action='store',
200
                    default=False,
201
                    help="Delete user entries."),
202
        make_option('--user-entries',
203
                    dest='user_entries',
204
                    action='store',
205
                    default=False,
206
                    help="Display user summary."),
207
        make_option('--dry',
208
                    dest='dry',
209
                    action="store_true",
210
                    default=False,
211
                    help="Do not commit database changes. Do not communicate "
212
                         "with quotaholder"),
213
        make_option('--user',
214
                    dest='user',
215
                    action="store",
216
                    default=False,)
217
    )
218

  
219
    def resolve_conflicts(self, options):
220
        conflicting = map(options.get, ['migrate_users',
221
                                        'merge_user'])
222
        if len(filter(bool, conflicting)) > 1:
223
            raise CommandError('You can use only one of --validate,'
224
                               '--migrate-users')
225

  
226
    def handle(self, *args, **options):
227
        self.resolve_conflicts(options)
228
        self.strict = options.get('strict')
229
        self.dry = options.get('dry')
230

  
231
        if options.get('validate') and not options.get('merge_user') and not \
232
                options.get('delete_user') and not options.get('user_entries'):
233
            usernames = get_existing_users()
234
            _validate_db_state(usernames)
235

  
236
        if options.get('migrate_users'):
237
            migrate_users(usernames, dry=self.dry)
238

  
239
        if options.get('merge_user'):
240
            merge_user(options.get('merge_user'))
241
            print "Merge finished."
242

  
243
        if options.get('delete_user'):
244
            entries = delete_user(options.get('delete_user'), only_stats=True)
245
            if entries == -1:
246
                return
247

  
248
            confirm = raw_input("Type 'yes of course' if you are sure you want"
249
                                " to remove those entries: ")
250
            if not confirm == 'yes of course':
251
                return
252
            else:
253
                delete_user(options.get('delete_user'), only_stats=False,
254
                            dry=self.dry)
255

  
256
        if options.get('user_entries'):
257
            delete_user(options.get('user_entries'))
/dev/null
1
# Copyright 2012 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 itertools import product
35
from optparse import make_option
36

  
37
from django.core.management.base import BaseCommand, CommandError
38

  
39
from synnefo.db.models import Flavor
40

  
41

  
42
class Command(BaseCommand):
43
    output_transaction = True
44

  
45
    option_list = BaseCommand.option_list + (
46
        make_option("-n", "--dry-run", dest="dry_run", action="store_true"),
47
    )
48
    args = "<cpu>[,<cpu>,...] " \
49
           "<ram>[,<ram>,...] " \
50
           "<disk>[,<disk>,...] " \
51
           "<disk template>[,<disk template>,...]"
52
    help = "Create one or more flavors.\n\nThe flavors that will be created"\
53
           " are those belonging to the cartesian product of the arguments"
54

  
55
    def handle(self, *args, **options):
56
        if len(args) != 4:
57
            raise CommandError("Invalid number of arguments")
58

  
59
        cpus = args[0].split(',')
60
        rams = args[1].split(',')
61
        disks = args[2].split(',')
62
        templates = args[3].split(',')
63

  
64
        flavors = []
65
        for cpu, ram, disk, template in product(cpus, rams, disks, templates):
66
            try:
67
                flavors.append((int(cpu), int(ram), int(disk), template))
68
            except ValueError:
69
                raise CommandError("Invalid values")
70

  
71
        for cpu, ram, disk, template in flavors:
72
            if options["dry_run"]:
73
                flavor = Flavor(cpu=cpu, ram=ram, disk=disk,
74
                                disk_template=template)
75
                self.stdout.write("Creating flavor '%s'\n" % (flavor.name,))
76
            else:
77
                flavor, created = \
78
                    Flavor.objects.get_or_create(cpu=cpu, ram=ram, disk=disk,
79
                                                 disk_template=template)
80
                if created:
81
                    self.stdout.write("Created flavor '%s'\n" % (flavor.name,))
82
                else:
83
                    self.stdout.write("Flavor '%s' already exists\n"
84
                                      % flavor.name)
85
                    if flavor.deleted:
86
                        msg = "Flavor '%s' is marked as deleted. Use"\
87
                        " 'snf-manage flavor-modify' to restore this flavor\n"\
88
                        % flavor.name
89
                        self.stdout.write(msg)
/dev/null
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 snf_django.management.commands import ListCommand
35
from synnefo.db.models import Flavor, VirtualMachine
36

  
37

  
38
class Command(ListCommand):
39
    help = "List available server flavors"
40

  
41
    object_class = Flavor
42
    deleted_field = "deleted"
43

  
44
    def get_vms(flavor):
45
        return VirtualMachine.objects.filter(flavor=flavor, deleted=False)\
46
                                     .count()
47

  
48
    FIELDS = {
49
        "id": ("id", "Flavor's unique ID"),
50
        "name": ("name", "Flavor's unique name"),
51
        "cpu": ("cpu", "Number of CPUs"),
52
        "ram": ("ram", "Size(MB) of RAM"),
53
        "disk": ("disk", "Size(GB) of disk"),
54
        "template": ("disk_template", "Disk template"),
55
        "vms": (get_vms, "Number of active servers using this flavor")
56
    }
57

  
58
    fields = ["id", "name", "cpu", "ram", "disk", "template", "vms"]
/dev/null
1
# Copyright 2012 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 django.core.management.base import BaseCommand, CommandError
37
from synnefo.management.common import get_flavor
38
from snf_django.management.utils import parse_bool
39

  
40

  
41
from logging import getLogger
42
log = getLogger(__name__)
43

  
44

  
45
class Command(BaseCommand):
46
    args = "<flavor id>"
47
    help = "Modify a flavor"
48

  
49
    option_list = BaseCommand.option_list + (
50
        make_option(
51
            "--deleted",
52
            dest="deleted",
53
            metavar="True|False",
54
            choices=["True", "False"],
55
            default=None,
56
            help="Mark/unmark a flavor as deleted"),
57
    )
58

  
59
    def handle(self, *args, **options):
60
        if len(args) != 1:
61
            raise CommandError("Please provide a flavor ID")
62

  
63
        flavor = get_flavor(args[0])
64

  
65
        deleted = options['deleted']
66
        if deleted:
67
            deleted = parse_bool(deleted)
68
            log.info("Marking flavor %s as deleted=%s", flavor, deleted)
69
            flavor.deleted = deleted
70
            flavor.save()
71
        else:
72
            log.info("Nothing changed!")
/dev/null
1
# Copyright 2012 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 django.core.management.base import BaseCommand, CommandError
37
from synnefo.management import common
38
from synnefo.logic import servers
39

  
40

  
41
class Command(BaseCommand):
42
    help = "Attach a floating IP to a VM or router"
43

  
44
    option_list = BaseCommand.option_list + (
45
        make_option(
46
            '--machine',
47
            dest='machine',
48
            default=None,
49
            help='The server id the floating-ip will be attached to'),
50
    )
51

  
52
    @common.convert_api_faults
53
    def handle(self, *args, **options):
54
        if not args or len(args) > 1:
55
            raise CommandError("Command accepts exactly one argument")
56

  
57
        floating_ip_id = args[0]  # this is the floating-ip address
58
        device = options['machine']
59

  
60
        if not device:
61
            raise CommandError('Please give either a server or a router id')
62

  
63
        #get the vm
64
        vm = common.get_vm(device)
65
        floating_ip = common.get_floating_ip_by_id(floating_ip_id,
66
                                                   for_update=True)
67
        servers.create_port(vm.userid, floating_ip.network,
68
                            use_ipaddress=floating_ip, machine=vm)
69

  
70
        self.stdout.write("Attached %s to %s.\n" % (floating_ip, vm))
/dev/null
1
# Copyright 2012 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 django.core.management.base import BaseCommand, CommandError
37
from synnefo.management.common import convert_api_faults
38
from synnefo.logic import ips
39
from synnefo.api import util
40

  
41

  
42
class Command(BaseCommand):
43
    help = "Allocate a new floating IP"
44

  
45
    option_list = BaseCommand.option_list + (
46
        make_option(
47
            '--pool',
48
            dest='pool',
49
            help="The ID of the floating IP pool(network) to allocate the"
50
                 " address from"),
51
        make_option(
52
            '--address',
53
            dest='address',
54
            help="The address to be allocated"),
55
        make_option(
56
            '--owner',
57
            dest='owner',
58
            default=None,
59
            help='The owner of the floating IP'),
60
    )
61

  
62
    @convert_api_faults
63
    def handle(self, *args, **options):
64
        if args:
65
            raise CommandError("Command doesn't accept any arguments")
66

  
67
        network_id = options['pool']
68
        address = options['address']
69
        owner = options['owner']
70

  
71
        if not owner:
72
            raise CommandError("'owner' is required for floating IP creation")
73

  
74
        if network_id is not None:
75
            network = util.get_network(network_id, owner, for_update=True,
76
                                       non_deleted=True)
77
        else:
78
            network = None
79

  
80
        floating_ip = ips.create_floating_ip(userid=owner,
81
                                             network=network,
82
                                             address=address)
83

  
84
        self.stdout.write("Created floating IP '%s'.\n" % floating_ip)
/dev/null
1
# Copyright 2012 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 django.core.management.base import BaseCommand, CommandError
37
from synnefo.management import common
38
from synnefo.logic import servers
39

  
40

  
41
class Command(BaseCommand):
42
    help = "Dettach a floating IP from a VM or router"
43

  
44
    @common.convert_api_faults
45
    def handle(self, *args, **options):
46
        if not args or len(args) > 1:
47
            raise CommandError("Command accepts exactly one argument")
48

  
49
        floating_ip_id = args[0]
50

  
51
        #get the floating-ip
52
        floating_ip = common.get_floating_ip_by_id(floating_ip_id,
53
                                                   for_update=True)
54

  
55
        if not floating_ip.nic:
56
            raise CommandError('This floating IP is not attached to a device')
57

  
58
        nic = floating_ip.nic
59
        vm = nic.machine
60
        servers.delete_port(nic)
61
        self.stdout.write("Dettached floating IP %s from  %s.\n"
62
                          % (floating_ip_id, vm))
/dev/null
1
# Copyright 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 django.db import transaction
37
from django.core.management.base import CommandError
38
from snf_django.management.commands import RemoveCommand
39
from synnefo.management import common
40
from synnefo.logic import ips
41

  
42

  
43
class Command(RemoveCommand):
44
    args = "<Floating-IP ID> [<Floating-IP ID> ...]"
45
    help = "Release a floating IP"
46

  
47
    @common.convert_api_faults
48
    @transaction.commit_on_success
49
    def handle(self, *args, **options):
50
        if not args:
51
            raise CommandError("Please provide a floating-ip ID")
52

  
53
        force = options['force']
54
        message = "floating IPs" if len(args) > 1 else "floating IP"
55
        self.confirm_deletion(force, message, args)
56

  
57
        for floating_ip_id in args:
58
            self.stdout.write("\n")
59
            try:
60
                floating_ip = common.get_floating_ip_by_id(floating_ip_id,
61
                                                           for_update=True)
62
                ips.delete_floating_ip(floating_ip)
63
                self.stdout.write("Deleted floating IP '%s'.\n" %
64
                                  floating_ip_id)
65
            except CommandError as e:
66
                self.stdout.write("Error -- %s\n" % e.message)
/dev/null
1
# Copyright 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

  
35
from snf_django.management.commands import ListCommand
36
from synnefo.db.models import IPAddressLog
37
from optparse import make_option
38

  
39
from logging import getLogger
40
log = getLogger(__name__)
41

  
42

  
43
class Command(ListCommand):
44
    help = "Information about a floating IP"
45

  
46
    option_list = ListCommand.option_list + (
47
        make_option(
48
            '--address',
49
            dest='address',
50
            help="Display IP history only for this address"),
51
        make_option(
52
            '--server',
53
            dest='server',
54
            help="Display IP history only for this server"),
55
        make_option(
56
            '--active',
57
            dest="active",
58
            action="store_true",
59
            default=False,
60
            help="Display only IPs that are currently in use")
61
    )
62

  
63
    object_class = IPAddressLog
64
    order_by = "allocated_at"
65

  
66
    FIELDS = {
67
        "address": ("address", "The IP address"),
68
        "server": ("server_id", "The the server connected to"),
69
        "network": ("network_id", "The id of the network"),
70
        "allocated_at": ("allocated_at", "Datetime IP allocated to server"),
71
        "released_at": ("released_at", "Datetime IP released from server"),
72
        "active": ("active", "Whether IP still allocated to server"),
73
    }
74

  
75
    fields = ["address", "server", "network", "allocated_at", "released_at"]
76

  
77
    def handle_args(self, *args, **options):
78
        if options["address"]:
79
            self.filters["address"] = options["address"]
80
        if options["server"]:
81
            self.filters["server_id"] = options["server"]
82
        if options["active"]:
83
            self.filters["active"] = True
/dev/null
1
# Copyright 2012 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 django.core.management.base import BaseCommand, CommandError
37
from synnefo.management.common import convert_api_faults
38
from snf_django.management.utils import parse_bool
39

  
40
from synnefo.db.models import Network
41
from synnefo.logic import networks, subnets
42
from synnefo.management import pprint
43

  
44
import ipaddr
45

  
46
NETWORK_FLAVORS = Network.FLAVORS.keys()
47

  
48

  
49
class Command(BaseCommand):
50
    can_import_settings = True
51
    output_transaction = True
52

  
53
    help = "Create a new network"
54

  
55
    option_list = BaseCommand.option_list + (
56
        make_option(
57
            '--name',
58
            dest='name',
59
            help="Name of the network"),
60
        make_option(
61
            '--owner',
62
            dest='owner',
63
            help="The owner of the network"),
64
        make_option(
65
            '--subnet',
66
            dest='subnet',
67
            default=None,
68
            # required=True,
69
            help='IPv4 subnet of the network'),
70
        make_option(
71
            '--gateway',
72
            dest='gateway',
73
            default=None,
74
            help='IPv4 gateway of the network'),
75
        make_option(
76
            '--subnet6',
77
            dest='subnet6',
78
            default=None,
79
            help='IPv6 subnet of the network'),
80
        make_option(
81
            '--gateway6',
82
            dest='gateway6',
83
            default=None,
84
            help='IPv6 gateway of the network'),
85
        make_option(
86
            '--dhcp',
87
            dest='dhcp',
88
            default="False",
89
            choices=["True", "False"],
90
            metavar="True|False",
91
            help='Automatically assign IPs'),
92
        make_option(
93
            '--public',
94
            dest='public',
95
            action='store_true',
96
            default=False,
97
            help='Network is public'),
98
        make_option(
99
            '--flavor',
100
            dest='flavor',
101
            default=None,
102
            choices=NETWORK_FLAVORS,
103
            help='Network flavor. Choices: ' + ', '.join(NETWORK_FLAVORS)),
104
        make_option(
105
            '--mode',
106
            dest='mode',
107
            default=None,
108
            help="Overwrite flavor connectivity mode."),
109
        make_option(
110
            '--link',
111
            dest='link',
112
            default=None,
113
            help="Overwrite flavor connectivity link."),
114
        make_option(
115
            '--mac-prefix',
116
            dest='mac_prefix',
117
            default=None,
118
            help="Overwrite flavor connectivity MAC prefix"),
119
        make_option(
120
            '--tags',
121
            dest='tags',
122
            default=None,
123
            help='The tags of the Network (comma separated strings)'),
124
        make_option(
125
            '--floating-ip-pool',
126
            dest='floating_ip_pool',
127
            default="False",
128
            choices=["True", "False"],
129
            metavar="True|False",
130
            help="Use the network as a Floating IP pool."),
131
        make_option(
132
            '--allocation-pool',
133
            dest='allocation_pools',
134
            action='append',
135
            help="IP allocation pools to be used for assigning IPs to"
136
                 " VMs. Can be used multiple times. Syntax: \n"
137
                 "192.168.42.220,192.168.42.240. Starting IP must proceed "
138
                 "ending IP. If no allocation pools are given, the whole "
139
                 "subnet range is used, excluding the gateway IP, the "
140
                 "broadcast address and the network address"),
141
    )
142

  
143
    @convert_api_faults
144
    def handle(self, *args, **options):
145
        if args:
146
            raise CommandError("Command doesn't accept any arguments")
147

  
148
        name = options['name']
149
        subnet = options['subnet']
150
        gateway = options['gateway']
151
        subnet6 = options['subnet6']
152
        gateway6 = options['gateway6']
153
        public = options['public']
154
        flavor = options['flavor']
155
        mode = options['mode']
156
        link = options['link']
157
        mac_prefix = options['mac_prefix']
158
        tags = options['tags']
159
        userid = options["owner"]
160
        allocation_pools = options["allocation_pools"]
161
        floating_ip_pool = parse_bool(options["floating_ip_pool"])
162
        dhcp = parse_bool(options["dhcp"])
163

  
164
        if name is None:
165
            name = ""
166
        if flavor is None:
167
            raise CommandError("flavor is required")
168

  
169
        if ((subnet is None) and (subnet6 is None)) and dhcp is not False:
170
            raise CommandError("Cannot set DHCP without subnet or subnet6")
171

  
172
        if subnet is None and gateway is not None:
173
            raise CommandError("Cannot use gateway without subnet")
174
        if subnet is None and allocation_pools is not None:
175
            raise CommandError("Cannot use allocation-pools without subnet")
176
        if subnet6 is None and gateway6 is not None:
177
            raise CommandError("Cannot use gateway6 without subnet6")
178

  
179
        if not (userid or public):
180
            raise CommandError("'owner' is required for private networks")
181

  
182
        network = networks.create(userid=userid, name=name, flavor=flavor,
183
                                  public=public, mode=mode,
184
                                  link=link, mac_prefix=mac_prefix, tags=tags,
185
                                  floating_ip_pool=floating_ip_pool)
186

  
187
        if subnet is not None:
188
            alloc = None
189
            if allocation_pools is not None:
190
                alloc = subnets.parse_allocation_pools(allocation_pools)
191
                alloc.sort()
192
            name = "IPv4 Subnet of Network %s" % network.id
193
            subnets.create_subnet(network.id, cidr=subnet, name=name,
194
                                  ipversion=4, gateway=gateway, dhcp=dhcp,
195
                                  user_id=userid,
196
                                  allocation_pools=alloc)
197

  
198
        if subnet6 is not None:
199
            name = "IPv6 Subnet of Network %s" % network.id
200
            subnets.create_subnet(network.id, cidr=subnet6, name=name,
201
                                  ipversion=6, gateway=gateway6,
202
                                  dhcp=dhcp, user_id=userid)
203

  
204
        self.stdout.write("Created network '%s' in DB:\n" % network)
205
        pprint.pprint_network(network, stdout=self.stdout)
206
        pprint.pprint_network_subnets(network, stdout=self.stdout)
207

  
208
        networks.create_network_in_backends(network)
209
        # TODO: Add --wait option to track job progress and report successful
210
        # creation in each backend.
211
        self.stdout.write("\nSuccessfully issued job to create network in"
212
                          " backends\n")
/dev/null
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 snf_django.management.commands import ListCommand
37
from synnefo.db.models import Network
38
from synnefo.settings import (CYCLADES_SERVICE_TOKEN as ASTAKOS_TOKEN,
39
                              ASTAKOS_AUTH_URL)
40

  
41
from logging import getLogger
42
log = getLogger(__name__)
43

  
44

  
45
class Command(ListCommand):
46
    help = "List networks"
47

  
48
    option_list = ListCommand.option_list + (
49
        make_option(
50
            '--public',
51
            action='store_true',
52
            dest='public',
53
            default=False,
54
            help="List only public networks"),
55
        make_option(
56
            '--ipv6',
57
            action='store_true',
58
            dest='ipv6',
59
            default=False,
60
            help="Include IPv6 information"),
61
    )
62

  
63
    object_class = Network
64
    select_related = []
65
    prefetch_related = ["subnets"]
66
    deleted_field = "deleted"
67
    user_uuid_field = "userid"
68
    astakos_auth_url = ASTAKOS_AUTH_URL
69
    astakos_token = ASTAKOS_TOKEN
70

  
71
    def get_machines(network):
72
        return network.machines.filter(deleted=False).count()
73

  
74
    def get_backends(network):
75
        return network.backend_networks.values_list("backend_id", flat=True)
76

  
77
    def get_subnet_ipv4(network):
78
        return _get_subnet_field(network, "cidr", 4)
79

  
80
    def get_subnet_ipv6(network):
81
        return _get_subnet_field(network, "cidr", 6)
82

  
83
    def get_gateway_ipv4(network):
84
        return _get_subnet_field(network, "gateway", 4)
85

  
86
    def get_gateway_ipv6(network):
87
        return _get_subnet_field(network, "gateway", 6)
88

  
89
    def get_subnets(network):
90
        return network.subnets.values_list('id', flat=True)
91

  
92
    FIELDS = {
93
        "id": ("id", "The ID of the network"),
94
        "name": ("name", "The name of the network"),
95
        "user.uuid": ("userid", "The UUID of the network's owner"),
96
        "public": ("public", "Whether network is public or private"),
97
        "flavor": ("flavor", "The network's flavor"),
98
        "state": ("state", "The network's state"),
99
        "subnets": (get_subnets, "The IDs of the associated subnets"),
100
        "subnet.ipv4":  (get_subnet_ipv4, "The IPv4 subnet of the network"),
101
        "gateway.ipv4": (get_gateway_ipv4, "The IPv4 gateway of the network"),
102
        "subnet.ipv6":  (get_subnet_ipv6, "The IPv6 subnet of the network"),
103
        "gateway.ipv6":  (get_gateway_ipv6, "The IPv6 gateway of the network"),
104
        "created": ("created", "The date the network was created"),
105
        "updated": ("updated", "The date the network was updated"),
106
        "deleted": ("deleted", "Whether the network is deleted or not"),
107
        "mode": ("mode", "The mode of the network"),
108
        "link": ("link", "The link of the network"),
109
        "mac_prefix": ("mac_prefix", "The network's MAC prefix"),
110
        "drained": ("drained", "Whether network is drained or not"),
111
        "vms": (get_machines, "Number of connected servers"),
112
        "backends": (get_backends, "IDs of Ganeti backends that the network is"
113
                                   " connected to"),
114
        "floating_ip_pool": ("floating_ip_pool",
115
                             "Whether the network is a floating IP pool"),
116
    }
117

  
118
    fields = ["id", "name", "user.uuid", "state", "public", "subnet.ipv4",
119
              "gateway.ipv4", "link", "mac_prefix",  "drained",
120
              "floating_ip_pool"]
121

  
122
    def handle_args(self, *args, **options):
123
        if options["public"]:
124
            self.filters["public"] = True
125
        if options["ipv6"]:
126
            self.fields.extend(["subnet.ipv6", "gateway.ipv6"])
127

  
128

  
129
def _get_subnet_field(network, field, version=4):
130
    for subnet in network.subnets.all():
131
        if subnet.ipversion == version:
132
            return getattr(subnet, field)
133
    return None
/dev/null
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 django.core.management.base import BaseCommand, CommandError
37

  
38
from synnefo.db.models import Backend
39
from synnefo.management.common import (get_network, get_backend)
40
from snf_django.management.utils import parse_bool
41
from synnefo.logic import networks, backend as backend_mod
42
from django.db import transaction
43

  
44

  
45
class Command(BaseCommand):
46
    args = "<network id>"
47
    help = "Modify a network."
48

  
49
    option_list = BaseCommand.option_list + (
50
        make_option(
51
            '--name',
52
            dest='name',
53
            metavar='NAME',
54
            help="Rename a network"),
55
        make_option(
56
            '--userid',
57
            dest='userid',
58
            help="Change the owner of the network."),
59
        make_option(
60
            "--drained",
61
            dest="drained",
62
            metavar="True|False",
63
            choices=["True", "False"],
64
            help="Set as drained to exclude for IP allocation."
65
                 " Only used for public networks."),
66
        make_option(
67
            "--floating-ip-pool",
68
            dest="floating_ip_pool",
69
            metavar="True|False",
70
            choices=["True", "False"],
71
            help="Convert network to a floating IP pool. During this"
72
                 " conversation the network will be created to all"
73
                 " available Ganeti backends."),
74
        make_option(
75
            '--add-reserved-ips',
76
            dest="add_reserved_ips",
77
            help="Comma seperated list of IPs to externally reserve."),
78
        make_option(
79
            '--remove-reserved-ips',
80
            dest="remove_reserved_ips",
81
            help="Comma seperated list of IPs to externally release."),
82
        make_option(
83
            "--add-to-backend",
84
            dest="add_to_backend",
85
            metavar="BACKEND_ID",
86
            help="Create a network to a Ganeti backend."),
87
        make_option(
88
            "--remove-from-backend",
89
            dest="remove_from_backend",
90
            metavar="BACKEND_ID",
91
            help="Remove a network from a Ganeti backend."),
92
    )
93

  
94
    @transaction.commit_on_success
95
    def handle(self, *args, **options):
96
        if len(args) != 1:
97
            raise CommandError("Please provide a network ID")
98

  
99
        network = get_network(args[0])
100

  
101
        new_name = options.get("name")
102
        if new_name is not None:
103
            old_name = network.name
104
            network = networks.rename(network, new_name)
105
            self.stdout.write("Renamed network '%s' from '%s' to '%s'.\n" %
106
                              (network, old_name, new_name))
107

  
108
        drained = options.get("drained")
109
        if drained is not None:
110
            drained = parse_bool(drained)
111
            network.drained = drained
112
            network.save()
113
            self.stdout.write("Set network '%s' as drained=%s.\n" %
114
                              (network, drained))
115

  
116
        new_owner = options.get("userid")
117
        if new_owner is not None:
118
            if "@" in new_owner:
119
                raise CommandError("Invalid owner UUID.")
120
            old_owner = network.userid
121
            network.userid = new_owner
122
            network.save()
123
            msg = "Changed the owner of network '%s' from '%s' to '%s'.\n"
124
            self.stdout.write(msg % (network, old_owner, new_owner))
125

  
126
        floating_ip_pool = options["floating_ip_pool"]
127
        if floating_ip_pool is not None:
128
            floating_ip_pool = parse_bool(floating_ip_pool)
129
            if floating_ip_pool is False and network.floating_ip_pool is True:
130
                if network.ips.filter(deleted=False, floating_ip=True)\
131
                              .exists():
132
                    msg = ("Cannot make network a non floating IP pool."
133
                           " There are still reserved floating IPs.")
134
                    raise CommandError(msg)
135
            network.floating_ip_pool = floating_ip_pool
136
            network.save()
137
            self.stdout.write("Set network '%s' as floating-ip-pool=%s.\n" %
138
                              (network, floating_ip_pool))
139
            if floating_ip_pool is True:
140
                for backend in Backend.objects.filter(offline=False):
141
                    bnet, jobs =\
142
                        backend_mod.ensure_network_is_active(backend,
143
                                                             network.id)
144
                    if jobs:
145
                        msg = ("Sent job to create network '%s' in backend"
146
                               " '%s'\n" % (network, backend))
147
                        self.stdout.write(msg)
148

  
149
        add_reserved_ips = options.get('add_reserved_ips')
150
        remove_reserved_ips = options.get('remove_reserved_ips')
151
        if add_reserved_ips or remove_reserved_ips:
152
            if add_reserved_ips:
153
                add_reserved_ips = add_reserved_ips.split(",")
154
                for ip in add_reserved_ips:
155
                    network.reserve_address(ip, external=True)
156
            if remove_reserved_ips:
157
                remove_reserved_ips = remove_reserved_ips.split(",")
158
                for ip in remove_reserved_ips:
159
                    network.release_address(ip, external=True)
160

  
161
        add_to_backend = options["add_to_backend"]
162
        if add_to_backend is not None:
163
            backend = get_backend(add_to_backend)
164
            bnet, jobs = backend_mod.ensure_network_is_active(backend,
165
                                                              network.id)
166
            if jobs:
167
                msg = "Sent job to create network '%s' in backend '%s'\n"
168
                self.stdout.write(msg % (network, backend))
169

  
170
        remove_from_backend = options["remove_from_backend"]
171
        if remove_from_backend is not None:
172
            backend = get_backend(remove_from_backend)
173
            if network.nics.filter(machine__backend=backend,
174
                                   machine__deleted=False).exists():
175
                msg = "Cannot remove. There are still connected VMs to this"\
176
                      " network"
177
                raise CommandError(msg)
178
            backend_mod.delete_network(network, backend, disconnect=True)
179
            msg = "Sent job to delete network '%s' from backend '%s'\n"
180
            self.stdout.write(msg % (network, backend))
/dev/null
1
# Copyright 2011-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29
#
30

  
31
from django.core.management.base import CommandError
32
from snf_django.management.commands import RemoveCommand
33
from snf_django.lib.api import faults
34
from synnefo.logic import networks
35
from synnefo.management.common import get_network, convert_api_faults
36

  
37

  
38
class Command(RemoveCommand):
39
    can_import_settings = True
40
    args = "<Network ID> [<Network ID> ...]"
41
    help = "Remove a network from the Database, and Ganeti"
42

  
43
    @convert_api_faults
44
    def handle(self, *args, **options):
45
        if not args:
46
            raise CommandError("Please provide a network ID")
47

  
48
        force = options['force']
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff