murano-dashboard/muranodashboard/environments/api.py
Valerii Kovalchuk 415c1e6417 Correct env status in the new session
In the dashboard it is possible to make some changes in the current
session, then close this session and open another one. The result
of this was that changes were not saved but env's status was
changed.
With this patch status of environment is 'Ready to deploy' only
in case when current services list is not equal to the list of
last deployed services.
UI tests to check this behaviour are added.

Change-Id: I925e1f1caf0795960b56cc88b887430dc4871742
Closes-bug: #1606891
2016-08-11 17:00:49 +03:00

387 lines
14 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.
from django.utils.translation import ugettext_lazy as _
from oslo_log import log as logging
import six
from muranoclient.common import exceptions as exc
from muranodashboard import api
from muranodashboard.common import utils
from muranodashboard.environments import consts
from muranodashboard.environments import topology
LOG = logging.getLogger(__name__)
def get_status_messages_for_service(request, service_id, environment_id):
client = api.muranoclient(request)
deployments = client.deployments.list(environment_id)
LOG.debug('Deployment::List {0}'.format(deployments))
result = '\n'
# TODO(efedorova): Add updated time to logs
if deployments:
for deployment in reversed(deployments):
reports = client.deployments.reports(
environment_id, deployment.id, service_id)
for report in reports:
result += report.created.replace('T', ' ') + ' - ' + \
report.text + '\n'
return result
def create_session(request, environment_id):
sessions = request.session.get('sessions', {})
id = api.muranoclient(request).sessions.configure(environment_id).id
sessions[environment_id] = id
request.session['sessions'] = sessions
return id
class Session(object):
@staticmethod
def get_or_create(request, environment_id):
"""Get an open session id
Gets id from already opened session for specified environment,
otherwise opens new session and returns its id
:param request:
:param environment_id:
:return: Session Id
"""
# We store opened sessions for each environment in dictionary per user
sessions = request.session.get('sessions', {})
if environment_id in sessions:
id = sessions[environment_id]
else:
id = create_session(request, environment_id)
return id
@staticmethod
def get_or_create_or_delete(request, environment_id):
"""Get an open session id
Gets id from session in open state for specified environment,
if state is deployed - this session will be deleted and new
would be created. If there are no any sessions new would be created.
Returns if of chosen or created session.
:param request:
:param environment_id:
:return: Session Id
"""
sessions = request.session.get('sessions', {})
client = api.muranoclient(request)
if environment_id in sessions:
id = sessions[environment_id]
try:
session_data = client.sessions.get(environment_id, id)
except exc.HTTPForbidden:
del sessions[environment_id]
LOG.debug("The environment is being deployed by other user."
"Creating a new session "
"for the environment {0}".format(environment_id))
return create_session(request, environment_id)
else:
if session_data.state in [consts.STATUS_ID_DEPLOY_FAILURE,
consts.STATUS_ID_READY]:
del sessions[environment_id]
LOG.debug("The existing session has been already deployed."
" Creating a new session "
"for the environment {0}".format(environment_id))
return create_session(request, environment_id)
else:
LOG.debug("Creating a new session")
return create_session(request, environment_id)
LOG.debug("Found active session "
"for the environment {0}".format(environment_id))
return id
@staticmethod
def get(request, environment_id):
"""Get an open session id
Gets id from already opened session for specified environment,
otherwise returns None
:param request:
:param environment_id:
:return: Session Id
"""
# We store opened sessions for each environment in dictionary per user
sessions = request.session.get('sessions', {})
session_id = sessions.get(environment_id, '')
if session_id:
LOG.debug("Using session_id {0} for the environment {1}".format(
session_id, environment_id))
else:
LOG.debug("Session for the environment {0} not found".format(
environment_id))
return session_id
@staticmethod
def set(request, environment_id, session_id):
"""Set an open session id
sets id from already opened session for specified environment.
:param request:
:param environment_id:
:param session_id
"""
# We store opened sessions for each environment in dictionary per user
sessions = request.session.get('sessions', {})
sessions[environment_id] = session_id
request.session['sessions'] = sessions
def _update_env(env, request):
# TODO(vakovalchuk): optimize latest deployment when limit is available
deployments = deployments_list(request, env.id)
if deployments:
latest_deployment = deployments[0]
deployed_services = {service['?']['id'] for service in
latest_deployment.description['services']}
else:
deployed_services = set()
if env.services:
current_services = {service['?']['id'] for service in env.services}
else:
current_services = set()
env.has_new_services = current_services != deployed_services
if not env.has_new_services and env.status == consts.STATUS_ID_PENDING:
env.status = consts.STATUS_ID_READY
if not env.has_new_services and env.version == 0:
if env.status == consts.STATUS_ID_READY:
env.status = consts.STATUS_ID_NEW
return env
def environments_list(request):
environments = []
client = api.muranoclient(request)
with api.handled_exceptions(request):
environments = client.environments.list()
LOG.debug('Environment::List {0}'.format(environments))
for index, env in enumerate(environments):
environments[index] = environment_get(request, env.id)
return environments
def environment_create(request, parameters):
# name is required param
body = {'name': parameters['name']}
if 'defaultNetworks' in parameters:
body['defaultNetworks'] = parameters['defaultNetworks']
env = api.muranoclient(request).environments.create(body)
LOG.debug('Environment::Create {0}'.format(env))
return env
def environment_delete(request, environment_id, abandon=False):
action = 'Abandon' if abandon else 'Delete'
LOG.debug('Environment::{0} <Id : {1}>'.format(action, environment_id))
return api.muranoclient(request).environments.delete(
environment_id, abandon)
def environment_get(request, environment_id):
session_id = Session.get(request, environment_id)
LOG.debug('Environment::Get <Id: {0}, SessionId: {1}>'.
format(environment_id, session_id))
client = api.muranoclient(request)
env = client.environments.get(environment_id, session_id)
acquired = getattr(env, 'acquired_by', None)
if acquired and acquired != session_id:
env = client.environments.get(environment_id, acquired)
Session.set(request, environment_id, acquired)
env = _update_env(env, request)
LOG.debug('Environment::Get {0}'.format(env))
return env
def environment_deploy(request, environment_id):
session_id = Session.get_or_create_or_delete(request, environment_id)
LOG.debug('Session::Get <Id: {0}>'.format(session_id))
env = api.muranoclient(request).sessions.deploy(environment_id, session_id)
LOG.debug('Environment::Deploy <EnvId: {0}, SessionId: {1}>'
''.format(environment_id, session_id))
return env
def environment_update(request, environment_id, name):
return api.muranoclient(request).environments.update(environment_id, name)
def action_allowed(request, environment_id):
env = environment_get(request, environment_id)
status = getattr(env, 'status', None)
return status not in ('deploying',)
def services_list(request, environment_id):
"""Get environment applications.
This function collects data from Murano API and modifies it only for
dashboard purposes. Those changes don't impact application
deployment parameters.
"""
def strip(msg, to=100):
return u'%s...' % msg[:to] if len(msg) > to else msg
services = []
# need to create new session to see services deployed be other user
session_id = Session.get(request, environment_id)
get_environment = api.muranoclient(request).environments.get
environment = get_environment(environment_id, session_id)
try:
client = api.muranoclient(request)
reports = client.environments.last_status(environment_id, session_id)
except exc.HTTPNotFound:
LOG.exception(_('Could not retrieve latest status for '
'the {0} environment').format(environment_id))
reports = {}
for service_item in environment.services or []:
service_data = service_item
service_id = service_data['?']['id']
if service_id in reports and reports[service_id]:
last_operation = strip(reports[service_id].text)
time = reports[service_id].updated
else:
last_operation = 'Component draft created' \
if environment.version == 0 else ''
try:
time = service_data['updated'][:-7]
except KeyError:
time = None
service_data['environment_id'] = environment_id
service_data['environment_version'] = environment.version
service_data['operation'] = last_operation
service_data['operation_updated'] = time
if service_data['?'].get('name'):
service_data['name'] = service_data['?']['name']
services.append(service_data)
LOG.debug('Service::List')
return [utils.Bunch(**service) for service in services]
def service_list_by_fqns(request, environment_id, fqns):
if environment_id is None:
return []
services = services_list(request, environment_id)
LOG.debug('Service::Instances::List')
return [service for service in services if service['?']['type'] in fqns]
def service_create(request, environment_id, parameters):
# we should be able to delete session
# if we what add new services to this environment
session_id = Session.get_or_create_or_delete(request, environment_id)
LOG.debug('Service::Create {0}'.format(parameters['?']['type']))
return api.muranoclient(request).services.post(environment_id,
path='/',
data=parameters,
session_id=session_id)
def service_delete(request, environment_id, service_id):
LOG.debug('Service::Delete <SrvId: {0}>'.format(service_id))
session_id = Session.get_or_create_or_delete(request, environment_id)
return api.muranoclient(request).services.delete(environment_id,
'/' + service_id,
session_id)
def service_get(request, environment_id, service_id):
services = services_list(request, environment_id)
LOG.debug("Return service detail for a specified id")
for service in services:
if service['?']['id'] == service_id:
return service
def extract_actions_list(service):
actions_data = service['?'].get('_actions', {})
def make_action_datum(action_id, _action):
return dict(_action.items() + [('id', action_id)])
return [make_action_datum(_id, action) for (_id, action) in
six.iteritems(actions_data) if action.get('enabled')]
def run_action(request, environment_id, action_id):
mc = api.muranoclient(request)
return mc.actions.call(environment_id, action_id)
def deployments_list(request, environment_id):
LOG.debug('Deployments::List')
deployments = api.muranoclient(request).deployments.list(environment_id)
LOG.debug('Environment::List {0}'.format(deployments))
return deployments
def deployment_reports(request, environment_id, deployment_id):
LOG.debug('Deployment::Reports::List')
reports = api.muranoclient(request).deployments.reports(environment_id,
deployment_id)
LOG.debug('Deployment::Reports::List {0}'.format(reports))
return reports
def get_deployment_start(request, environment_id, deployment_id):
deployments = api.muranoclient(request).deployments.list(environment_id)
LOG.debug('Get deployment start time')
for deployment in deployments:
if deployment.id == deployment_id:
return deployment.started.replace('T', ' ')
return None
def get_deployment_descr(request, environment_id, deployment_id):
deployments = api.muranoclient(request).deployments.list(environment_id)
LOG.debug('Get deployment description')
for deployment in deployments:
if deployment.id == deployment_id:
return deployment.description
return None
def load_environment_data(request, environment_id):
environment = environment_get(request, environment_id)
return topology.render_d3_data(request, environment)