deb-murano/muranoapi/db/services/environments.py
Alexander Tivelkov b7c2aac9a2 Implemented AdvNetworking scenarios via Neutron
Added a new package ( io.murano.lib.networks.Neutron) to handle networking via Neutron
The package introduces a class 'NewNetwork' (io.murano.lib.networks.neutron.NewNetwork)
This class is capable of the following:
 - Create a new Network (L2 segment)
 - Use NetworkExplorer class to allocate an available CIDR
 - Create a new Subnet (L3 segment) in the created Network with the allocated CIDR
 - Use NetworkExplorer class to locate an available router
 - Use NetworkExplorer class to detect the default DNS nameserver
 - Uplink the created subnet to the located router

Also, as this class extends io.murano.resources.Network, it implements the addHostToNetwork method
The implementation creates a Neutron Port and connects that port to a created network and intance

 This commit also modifies the environment-creation logic of the API, allowing to add default networks
 to the Environment object.
 This is a temporary solution: in future the instantiation of this object(s) should be done in MuranoPL

 This commit concludes the minimum set of functionality needed to implement AdvancedNetworking
 in 0.4.x feature set.

 Closes-bug: #1308921

Change-Id: I885620099995b0d402a23def3ff428fb902973d2
2014-04-29 13:02:11 +04:00

223 lines
7.5 KiB
Python

# Copyright (c) 2013 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import collections
from muranoapi.common import rpc
from muranoapi.common import uuidutils
from muranoapi.db import models
from muranoapi.db.services import sessions
from muranoapi.db import session as db_session
EnvironmentStatus = collections.namedtuple('EnvironmentStatus', [
'ready', 'pending', 'deploying'
])(
ready='ready', pending='pending', deploying='deploying'
)
DEFAULT_NETWORKS = {
'environment': 'io.murano.lib.networks.neutron.NewNetwork',
# 'flat': 'io.murano.lib.networks.ExistingNetworkConnector'
}
class EnvironmentServices(object):
@staticmethod
def get_environments_by(filters):
"""
Returns list of environments
:param filters: property filters
:return: Returns list of environments
"""
unit = db_session.get_session()
environments = unit.query(models.Environment).\
filter_by(**filters).all()
for env in environments:
env['status'] = EnvironmentServices.get_status(env['id'])
return environments
@staticmethod
def get_status(environment_id):
"""
Environment can have one of three distinguished statuses:
- Deploying: there is at least one session with status `deploying`;
- Pending: there is at least one session with status `open`;
- Ready: there is no sessions in status `deploying` or `open`.
:param environment_id: Id of environment for which we checking status.
:return: Environment status
"""
#Deploying: there is at least one valid session with status `deploying`
deploying = sessions.SessionServices.get_sessions(
environment_id,
sessions.SessionState.deploying)
if len(deploying) > 0:
return 'deploying'
#Pending: there is at least one valid session with status `open`;
open = sessions.SessionServices.get_sessions(
environment_id,
sessions.SessionState.open)
if len(open) > 0:
return 'pending'
#Ready: there are no sessions in status `deploying` or `open`
return 'ready'
@staticmethod
def create(environment_params, tenant_id):
#tagging environment by tenant_id for later checks
"""
Creates environment with specified params, in particular - name
:param environment_params: Dict, e.g. {'name': 'env-name'}
:param tenant_id: Tenant Id
:return: Created Environment
"""
objects = {'?': {
'id': uuidutils.generate_uuid(),
}}
objects.update(environment_params)
objects.update(
EnvironmentServices.generate_default_networks(objects['name']))
objects['?']['type'] = 'io.murano.Environment'
environment_params['tenant_id'] = tenant_id
data = {
'Objects': objects,
'Attributes': []
}
environment = models.Environment()
environment.update(environment_params)
unit = db_session.get_session()
with unit.begin():
unit.add(environment)
#saving environment as Json to itself
environment.update({'description': data})
environment.save(unit)
return environment
@staticmethod
def delete(environment_id, token):
"""
Deletes environment and notify orchestration engine about deletion
:param environment_id: Environment that is going to be deleted
:param token: OpenStack auth token
"""
unit = db_session.get_session()
environment = unit.query(models.Environment).get(environment_id)
#preparing data for removal from conductor
env = environment.description
env['Objects'] = None
data = {
'model': env,
'token': token,
'tenant_id': environment.tenant_id
}
rpc.engine().handle_task(data)
with unit.begin():
unit.delete(environment)
@staticmethod
def get_environment_description(environment_id, session_id=None,
inner=True):
"""
Returns environment description for specified environment. If session
is specified and not in deploying state function returns modified
environment description, otherwise returns actual environment desc.
:param environment_id: Environment Id
:param session_id: Session Id
:param inner: return contents of environment rather than whole
Object Model structure
:return: Environment Description Object
"""
unit = db_session.get_session()
if session_id:
session = unit.query(models.Session).get(session_id)
if sessions.SessionServices.validate(session):
if session.state != sessions.SessionState.deployed:
env_description = session.description
else:
env = unit.query(models.Environment)\
.get(session.environment_id)
env_description = env.description
else:
env = unit.query(models.Environment)\
.get(session.environment_id)
env_description = env.description
else:
env = (unit.query(models.Environment).get(environment_id))
env_description = env.description
if not inner:
return env_description
else:
return env_description['Objects']
@staticmethod
def save_environment_description(session_id, environment, inner=True):
"""
Saves environment description to specified session
:param session_id: Session Id
:param environment: Environment Description
:param inner: save modifications to only content of environment
rather than whole Object Model structure
"""
unit = db_session.get_session()
session = unit.query(models.Session).get(session_id)
if inner:
data = session.description.copy()
data['Objects'] = environment
session.description = data
else:
session.description = environment
session.save(unit)
@staticmethod
def generate_default_networks(env_name):
# TODO(ativelkov):
# This is a temporary workaround. Need to find a better way:
# These objects have to be created in runtime when the environment is
# deployed for the first time. Currently there is no way to persist
# such changes, so we have to create the objects on the API side
return {
'defaultNetworks': {
'environment': {
'?': {
'id': uuidutils.generate_uuid(),
'type': DEFAULT_NETWORKS['environment']
},
'name': env_name + '-network'
},
'flat': None
}
}