Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
itminedu
synnefo
Commits
bb60f402
Commit
bb60f402
authored
Oct 09, 2013
by
Dionysis Grigoropoulos
Committed by
Christos Stavrakakis
Oct 09, 2013
Browse files
cyclades: Add api/subnets.py
parent
0d6b2654
Changes
1
Hide whitespace changes
Inline
Side-by-side
snf-cyclades-app/synnefo/api/subnets.py
0 → 100644
View file @
bb60f402
# Copyright 2013 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
logging
import
getLogger
from
snf_django.lib
import
api
from
snf_django.lib.api
import
faults
from
django.http
import
HttpResponse
from
django.utils
import
simplejson
as
json
from
snf_django.lib.api
import
utils
from
models
import
Subnet
,
Network
from
synnefo.logic
import
networks
from
ipaddr
import
IPv4Network
,
IPv6Network
,
IPv4Address
log
=
getLogger
(
__name__
)
def
demux
(
request
):
if
request
.
method
==
'GET'
:
return
list_subnets
(
request
)
elif
request
.
method
==
'POST'
:
return
create_subnet
(
request
)
else
:
return
api
.
api_method_not_allowed
(
request
)
def
subnet_demux
(
request
,
sub_id
):
if
request
.
method
==
'GET'
:
return
get_subnet
(
request
,
sub_id
)
elif
request
.
method
==
'DELETE'
:
return
delete_subnet
(
request
,
sub_id
)
elif
request
.
method
==
'PUT'
:
return
update_subnet
(
request
,
sub_id
)
else
:
return
api
.
api_method_not_allowed
(
request
)
@
api
.
api_method
(
http_method
=
'GET'
,
user_required
=
True
,
logger
=
log
)
def
list_subnets
(
request
):
"""List all subnets of a user"""
log
.
debug
(
'list_subnets'
)
user_subnets
=
Subnet
.
objects
.
filter
(
network__userid
=
request
.
user_uniq
)
subnets_dict
=
[
subnet_to_dict
(
sub
)
for
sub
in
user_subnets
.
order_by
(
'id'
)]
data
=
json
.
dumps
({
'subnets'
:
subnets_dict
})
return
HttpResponse
(
data
,
status
=
200
)
@
api
.
api_method
(
http_method
=
'POST'
,
user_required
=
True
,
logger
=
log
)
def
create_subnet
(
request
):
"""Create a subnet"""
dictionary
=
utils
.
get_request_dict
(
request
)
log
.
info
(
'create subnet %s'
,
dictionary
)
user_id
=
request
.
user_uniq
try
:
subnet
=
dictionary
[
'subnet'
]
network_id
=
subnet
[
'network_id'
]
cidr
=
subnet
[
'cidr'
]
except
KeyError
:
raise
api
.
faults
.
BadRequest
(
"Malformed request"
)
try
:
network
=
Network
.
objects
.
get
(
id
=
network_id
)
except
Network
.
DoesNotExist
:
raise
api
.
faults
.
ItemNotFound
(
"No networks found with that id"
)
if
user_id
!=
network
.
userid
:
raise
api
.
faults
.
Unauthorized
(
"Unauthorized operation"
)
ipversion
=
subnet
.
get
(
'ip_version'
,
4
)
if
ipversion
not
in
[
4
,
6
]:
raise
api
.
faults
.
BadRequest
(
"Malformed IP version type"
)
# Returns the first available IP in the subnet
if
ipversion
==
6
:
potential_gateway
=
str
(
IPv6Network
(
cidr
).
network
+
1
)
check_number_of_subnets
(
network
,
6
)
else
:
potential_gateway
=
str
(
IPv4Network
(
cidr
).
network
+
1
)
check_number_of_subnets
(
network
,
4
)
gateway
=
subnet
.
get
(
'gateway_ip'
,
potential_gateway
)
if
ipversion
==
6
:
networks
.
validate_network_params
(
None
,
None
,
cidr
,
gateway
)
else
:
networks
.
validate_network_params
(
cidr
,
gateway
)
allocation_pools
=
subnet
.
get
(
'allocation_pools'
,
None
)
if
allocation_pools
:
if
ipversion
==
6
:
raise
api
.
faults
.
BadRequest
(
"Can't allocate an IP Pool in IPv6"
)
for
pool
in
allocation_pools
:
start
=
pool
[
'start'
]
end
=
pool
[
'end'
]
networks
.
validate_network_params
(
cidr
,
start
)
networks
.
validate_network_params
(
cidr
,
end
)
start
=
IPv4Address
(
start
)
end
=
IPv4Address
(
end
)
if
start
>=
end
:
raise
api
.
faults
.
BadRequest
(
"Invalid IP pool range"
)
else
:
# FIX ME
pass
dhcp
=
check_dhcp_value
(
subnet
.
get
(
'enable_dhcp'
,
True
))
name
=
check_name_length
(
subnet
.
get
(
'name'
,
None
))
dns
=
subnet
.
get
(
'dns_nameservers'
,
None
)
hosts
=
subnet
.
get
(
'host_routes'
,
None
)
# FIX ME
try
:
sub
=
Subnet
.
objects
.
create
(
name
=
name
,
network
=
network
,
cidr
=
cidr
,
ipversion
=
ipversion
,
gateway
=
gateway
,
dhcp
=
dhcp
,
host_routes
=
hosts
,
dns_nameservers
=
dns
)
except
:
raise
return
"Error"
subnet_dict
=
subnet_to_dict
(
sub
)
data
=
json
.
dumps
({
'subnet'
:
subnet_dict
})
return
HttpResponse
(
data
,
status
=
200
)
@
api
.
api_method
(
http_method
=
'GET'
,
user_required
=
True
,
logger
=
log
)
def
get_subnet
(
request
,
sub_id
):
"""Show info of a specific subnet"""
log
.
debug
(
'get_subnet %s'
,
sub_id
)
user_id
=
request
.
user_uniq
try
:
subnet
=
Subnet
.
objects
.
get
(
id
=
sub_id
)
except
Subnet
.
DoesNotExist
:
raise
api
.
faults
.
ItemNotFound
(
"Subnet not found"
)
if
subnet
.
network
.
userid
!=
user_id
:
raise
api
.
failts
.
Unauthorized
(
"You're not allowed to view this subnet"
)
subnet_dict
=
subnet_to_dict
(
subnet
)
data
=
json
.
dumps
({
'subnet'
:
subnet_dict
})
return
HttpResponse
(
data
,
status
=
200
)
@
api
.
api_method
(
http_method
=
'DELETE'
,
user_required
=
True
,
logger
=
log
)
def
delete_subnet
(
request
,
sub_id
):
"""
Delete a subnet, raises BadRequest
A subnet is deleted ONLY when the network that it belongs to is deleted
"""
raise
api
.
faults
.
BadRequest
(
"Deletion of a subnet is not supported"
)
@
api
.
api_method
(
http_method
=
'PUT'
,
user_required
=
True
,
logger
=
log
)
def
update_subnet
(
request
,
sub_id
):
"""
Update the fields of a subnet
Only the name can be updated, everything else returns BadRequest
"""
dictionary
=
utils
.
get_request_dict
(
request
)
log
.
info
(
'Update subnet %s'
,
dictionary
)
user_id
=
request
.
user_uniq
try
:
subnet
=
dictionary
[
'subnet'
]
except
KeyError
:
raise
api
.
faults
.
BadRequest
(
"Malformed request"
)
original_subnet
=
get_subnet_fromdb
(
sub_id
,
user_id
)
original_dict
=
subnet_to_dict
(
original_subnet
)
if
len
(
subnet
)
!=
1
:
raise
api
.
faults
.
BadRequest
(
"Only the name of subnet can be updated"
)
name
=
subnet
.
get
(
"name"
,
None
)
if
not
name
:
raise
api
.
faults
.
BadRequest
(
"Only the name of subnet can be updated"
)
#if subnet.get('ip_version', None):
# raise api.faults.BadRequest("Malformed request, ip_version cannot be "
# "updated")
#if subnet.get('cidr', None):
# raise api.faults.BadRequest("Malformed request, cidr cannot be "
# "updated")
#if subnet.get('allocation_pools', None):
# raise api.faults.BadRequest("Malformed request, allocation pools "
# "cannot be updated")
#
# Check if request contained host/dns information
#check_for_hosts_dns(subnet)
#
#name = subnet.get('name', original_dict['name'])
check_name_length
(
name
)
#dhcp = subnet.get('enable_dhcp', original_dict['enable_dhcp'])
#check_dhcp_value(dhcp)
#
#gateway = subnet.get('gateway_ip', original_dict['gateway_ip'])
#FIX ME, check if IP is in use
#if original_dict['ip_version'] == 6:
# networks.validate_network_params(None, None, original_dict['cidr'],
# gateway)
#else:
# networks.validate_network_params(original_dict['cidr'], gateway)
#
try
:
#original_subnet.gateway = gateway
original_subnet
.
name
=
name
#original_subnet.dhcp = dhcp
original_subnet
.
save
()
except
:
#Fix me
return
"Unknown Error"
subnet_dict
=
subnet_to_dict
(
original_subnet
)
data
=
json
.
dumps
({
'subnet'
:
subnet_dict
})
return
HttpResponse
(
data
,
status
=
200
)
#Utility functions
def
subnet_to_dict
(
subnet
):
"""Returns a dictionary containing the info of a subnet"""
# FIX ME, allocation pools
dictionary
=
dict
({
'id'
:
subnet
.
id
,
'network_id'
:
subnet
.
network
.
id
,
'name'
:
subnet
.
name
,
'tenant_id'
:
subnet
.
network
.
userid
,
'gateway_ip'
:
subnet
.
gateway
,
'ip_version'
:
subnet
.
ipversion
,
'cidr'
:
subnet
.
cidr
,
'enable_dhcp'
:
subnet
.
dhcp
,
'dns_nameservers'
:
subnet
.
dns_nameservers
,
'host_routes'
:
subnet
.
host_routes
,
'allocation_pools'
:
[]})
return
dictionary
def
check_number_of_subnets
(
network
,
version
):
"""Check if a user can add a subnet in a network"""
if
network
.
subnet_set
.
filter
(
ipversion
=
version
):
raise
api
.
faults
.
BadRequest
(
"Only one subnet of IPv4/IPv6 per "
"network is allowed"
)
def
check_dhcp_value
(
dhcp
):
"""Check if dhcp value is in acceptable values"""
if
dhcp
not
in
[
True
,
False
]:
raise
api
.
faults
.
BadRequest
(
"Malformed request, enable_dhcp must be "
"True or False"
)
return
dhcp
def
check_name_length
(
name
):
"""Check if the length of a name is within acceptable value"""
if
len
(
str
(
name
))
>
Subnet
.
SUBNET_NAME_LENGTH
:
raise
api
.
faults
.
BadRequest
(
"Subnet name too long"
)
return
name
def
check_for_hosts_dns
(
subnet
):
"""
Check if a request contains host_routes or dns_nameservers options
Expects the request in a dictionary format
"""
if
subnet
.
get
(
'host_routes'
,
None
):
raise
api
.
faults
.
BadRequest
(
"Setting host routes isn't supported"
)
if
subnet
.
get
(
'dns_nameservers'
,
None
):
raise
api
.
faults
.
BadRequest
(
"Setting dns nameservers isn't supported"
)
def
get_subnet_fromdb
(
subnet_id
,
user_id
,
for_update
=
False
):
"""
Return a Subnet instance or raise ItemNotFound.
This is the same as util.get_network
"""
try
:
subnet_id
=
int
(
subnet_id
)
if
for_update
:
return
Subnet
.
objects
.
select_for_update
().
get
(
id
=
subnet_id
,
network__userid
=
user_id
)
return
Subnet
.
objects
.
get
(
id
=
subnet_id
,
network__userid
=
user_id
)
except
(
ValueError
,
Subnet
.
DoesNotExist
):
raise
api
.
faults
.
ItemNotFound
(
'Subnet not found.'
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment