commit 6dd70a5ca4c69355010c2708a7436cb649c13977
Author: Christos Stavrakakis <cstavr@grnet.gr>
Date:   Thu Jul 12 16:48:13 2012 +0300

    New management command for creating a network
    
    Create a management command for creating networks. Also remove
    the initial_data.json, since it is currently not necessary.

diff --git a/snf-cyclades-app/synnefo/api/management/commands/listnetworks.py b/snf-cyclades-app/synnefo/api/management/commands/listnetworks.py
index c347851..e2ae9d6 100644
--- a/snf-cyclades-app/synnefo/api/management/commands/listnetworks.py
+++ b/snf-cyclades-app/synnefo/api/management/commands/listnetworks.py
@@ -99,6 +99,7 @@ class Command(BaseCommand):
         for network in networks:
             fields = [str(network.id),
                       network.name,
+                      network.type,
                       network.userid or '',
                       network.mac_prefix or '',
                       str(network.dhcp),
diff --git a/snf-cyclades-app/synnefo/api/management/commands/network-create.py b/snf-cyclades-app/synnefo/api/management/commands/network-create.py
new file mode 100644
index 0000000..b83c25e
--- /dev/null
+++ b/snf-cyclades-app/synnefo/api/management/commands/network-create.py
@@ -0,0 +1,154 @@
+# Copyright 2012 GRNET S.A. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+#   1. Redistributions of source code must retain the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above
+#      copyright notice, this list of conditions and the following
+#      disclaimer in the documentation and/or other materials
+#      provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# The views and conclusions contained in the software and
+# documentation are those of the authors and should not be
+# interpreted as representing official policies, either expressed
+# or implied, of GRNET S.A.
+
+from optparse import make_option
+
+from django.core.management.base import BaseCommand, CommandError
+
+from synnefo.db.models import Network
+from synnefo.api.util import network_specs_from_type
+from synnefo.logic.backend import create_network
+
+import ipaddr
+
+NETWORK_TYPES = ['PUBLIC_ROUTED', 'PRIVATE_MAC_FILTERED',
+                 'PRIVATE_PHYSICAL_VLAN', 'CUSTOM_ROUTED',
+                 'CUSTOM_BRIDGED']
+
+
+class Command(BaseCommand):
+    help = "Create a new network"
+
+    option_list = BaseCommand.option_list + (
+        make_option('--name',
+            dest='name',
+            help="Name of network"),
+        make_option('--owner',
+            dest='owner',
+            help="The owner of the network"),
+        make_option('--subnet',
+            dest='subnet',
+            default=None,
+            # required=True,
+            help='Subnet of the network'),
+        make_option('--gateway',
+            dest='gateway',
+            default=None,
+            help='Gateway of the network'),
+        make_option('--dhcp',
+            dest='dhcp',
+            action='store_true',
+            default=False,
+            help='Automatically assign IPs'),
+        make_option('--public',
+            dest='public',
+            action='store_true',
+            default=False,
+            help='Network is public'),
+        make_option('--type',
+            dest='type',
+            default='PRIVATE_MAC_FILTERED',
+            choices=NETWORK_TYPES,
+            help='Type of network. Choices: ' + ', '.join(NETWORK_TYPES)),
+        make_option('--subnet6',
+            dest='subnet6',
+            default=None,
+            help='IPv6 subnet of the network'),
+        make_option('--gateway6',
+            dest='gateway6',
+            default=None,
+            help='IPv6 gateway of the network'),
+        )
+
+    def handle(self, *args, **options):
+        if args:
+            raise CommandError("Command doesn't accept any arguments")
+
+        name = options['name']
+        subnet = options['subnet']
+
+        if not name:
+            raise CommandError("Name is required")
+        if not subnet:
+            raise CommandError("Subnet is required")
+
+        link, mac_prefix = network_specs_from_type(options['type'])
+
+        subnet, gateway, subnet6, gateway6 = validate_network_info(options)
+
+        if not link:
+            raise CommandError("Can not create network. No connectivity link")
+
+        network = Network.objects.create(
+                name=name,
+                userid=options['owner'],
+                subnet=subnet,
+                gateway=gateway,
+                dhcp=options['dhcp'],
+                type=options['type'],
+                public=options['public'],
+                link=link,
+                mac_prefix=mac_prefix,
+                gateway6=gateway6,
+                subnet6=subnet6,
+                state='PENDING')
+
+        create_network(network)
+
+
+def validate_network_info(options):
+    subnet = options['subnet']
+    gateway = options['gateway']
+    subnet6 = options['subnet6']
+    gateway6 = options['gateway6']
+
+    try:
+        ipaddr.IPv4Network(subnet)
+    except ValueError:
+        raise CommandError('Malformed subnet')
+    try:
+        gateway and ipaddr.IPv4Address(gateway) or None
+    except ValueError:
+        raise CommandError('Malformed gateway')
+
+    try:
+        subnet6 and ipaddr.IPv6Network(subnet6) or None
+    except ValueError:
+        raise CommandError('Malformed subnet6')
+
+    try:
+        gateway6 and ipaddr.IPv6Address(gateway6) or None
+    except ValueError:
+        raise CommandError('Malformed gateway6')
+
+    return subnet, gateway, subnet6, gateway6
diff --git a/snf-cyclades-app/synnefo/api/networks.py b/snf-cyclades-app/synnefo/api/networks.py
index 5c77eeb..ac9dbe3 100644
--- a/snf-cyclades-app/synnefo/api/networks.py
+++ b/snf-cyclades-app/synnefo/api/networks.py
@@ -40,13 +40,12 @@ from django.http import HttpResponse
 from django.template.loader import render_to_string
 from django.utils import simplejson as json
 
-from synnefo import settings
 from synnefo.api import util
 from synnefo.api.actions import network_actions
 from synnefo.api.common import method_not_allowed
-from synnefo.api.faults import (BadRequest, OverLimit,
-                                Unauthorized, NetworkInUse)
-from synnefo.db.models import Network, Pool, BridgePool, MacPrefixPool
+from synnefo.api.faults import (BadRequest, Unauthorized,
+                                NetworkInUse)
+from synnefo.db.models import Network
 from synnefo.logic import backend
 
 
@@ -169,21 +168,10 @@ def create_network(request):
     if type == 'PUBLIC_ROUTED':
         raise Unauthorized('Can not create a public network.')
 
-    mac_prefix = None
-    try:
-        if type == 'PRIVATE_MAC_FILTERED':
-            link = settings.PRIVATE_MAC_FILTERED_BRIDGE
-            mac_prefix = MacPrefixPool.get_available().value
-        elif type == 'PRIVATE_PHYSICAL_VLAN':
-            link = BridgePool.get_available().value
-        elif type == 'CUSTOM_ROUTED':
-            link = settings.CUSTOM_ROUTED_ROUTING_TABLE
-        elif type == 'CUSTOM_BRIDGED':
-            link = settings.CUSTOM_BRIDGED_BRIDGE
-        else:
-            raise BadRequest('Unknown network type')
-    except Pool.PoolExhausted:
-        raise OverLimit('Network count limit exceeded.')
+
+    link, mac_prefix = util.network_specs_from_type(type)
+    if not link:
+        raise Exception("Can not create network. No connectivity link.")
 
     network = Network.objects.create(
             name=name,
diff --git a/snf-cyclades-app/synnefo/api/util.py b/snf-cyclades-app/synnefo/api/util.py
index 050d73e..99e83f2 100644
--- a/snf-cyclades-app/synnefo/api/util.py
+++ b/snf-cyclades-app/synnefo/api/util.py
@@ -55,9 +55,12 @@ from django.utils import simplejson as json
 from django.utils.cache import add_never_cache_headers
 
 from synnefo.api.faults import (Fault, BadRequest, BuildInProgress,
-                                ItemNotFound, ServiceUnavailable, Unauthorized, BadMediaType)
+                                ItemNotFound, ServiceUnavailable, Unauthorized,
+                                BadMediaType, OverLimit)
 from synnefo.db.models import (Flavor, VirtualMachine, VirtualMachineMetadata,
-                               Network, NetworkInterface)
+                               Network, NetworkInterface, BridgePool,
+                               MacPrefixPool, Pool)
+
 from synnefo.lib.astakos import get_user
 from synnefo.plankton.backend import ImageBackend
 
@@ -354,3 +357,23 @@ def api_method(http_method=None, atom_allowed=False):
 
 def construct_nic_id(nic):
     return "-".join(["nic", unicode(nic.machine.id), unicode(nic.index)])
+
+
+def network_specs_from_type(network_type):
+    mac_prefix = None
+    try:
+        if network_type == 'PRIVATE_MAC_FILTERED':
+            link = settings.PRIVATE_MAC_FILTERED_BRIDGE
+            mac_prefix = MacPrefixPool.get_available().value
+        elif network_type == 'PRIVATE_PHYSICAL_VLAN':
+            link = BridgePool.get_available().value
+        elif network_type == 'CUSTOM_ROUTED':
+            link = settings.CUSTOM_ROUTED_ROUTING_TABLE
+        elif network_type == 'CUSTOM_BRIDGED':
+            link = settings.CUSTOM_BRIDGED_BRIDGE
+        else:
+            raise BadRequest('Unknown network network_type')
+    except Pool.PoolExhausted:
+        raise OverLimit('Network count limit exceeded.')
+
+    return link, mac_prefix
diff --git a/snf-cyclades-app/synnefo/db/fixtures/initial_data.json b/snf-cyclades-app/synnefo/db/fixtures/initial_data.json
deleted file mode 100644
index 906aac1..0000000
--- a/snf-cyclades-app/synnefo/db/fixtures/initial_data.json
+++ /dev/null
@@ -1,16 +0,0 @@
-[
-    {
-        "model": "db.Network",
-        "pk": 1,
-        "fields": {
-            "name": "public",
-            "created": "2011-04-01",
-            "updated": "2011-04-01",
-            "state": "ACTIVE",
-            "public": 1,
-            "link": "snf_public",
-            "dhcp": 1,
-            "type": "PUBLIC_ROUTED"
-        }
-    }
-]
