Commit 9235ed31 authored by Maria Arsuaga Rios's avatar Maria Arsuaga Rios
Browse files

FTS-977: Removing old configurations

parent b8c19b07
Pipeline #159654 passed with stage
in 22 seconds
......@@ -41,8 +41,8 @@ class ConfigAudit(Base):
class LinkConfig(Base):
__tablename__ = 't_link_config'
source = Column(String(150), primary_key=True)
destination = Column(String(150), primary_key=True)
source = Column(String(150), primary_key=True, name='source_se')
destination = Column(String(150), primary_key=True, name='dest_se')
symbolicname = Column(String(255), unique=True)
min_active = Column(Integer)
max_active = Column(Integer)
......@@ -60,7 +60,7 @@ class Se(Base):
storage = Column(String(150), primary_key=True)
site = Column(String(45))
se_metadata = Column(String(255))
se_metadata = Column(String(255), name='metadata')
ipv6 = Column(Flag(negative='off', positive='on'), default='off')
udt = Column(Flag(negative='off', positive='on'))
debug_level = Column(Integer)
......@@ -90,47 +90,6 @@ class ShareConfig(Base):
return "%s: %s => %s" % (self.vo, self.source, self.destination)
class Group(Base):
__tablename__ = 't_group_members'
groupname = Column(String, primary_key=True)
def __str__(self):
return self.groupname
class Member(Base):
__tablename__ = 't_group_members'
__table_args__ = ({'extend_existing': True})
groupname = Column(String(255), primary_key=True)
member = Column(String(255), primary_key=True)
def __str__(self):
return "%s/%s" % (self.groupname, self.member)
class DebugConfig(Base):
__tablename__ = 't_debug'
source_se = Column(String(150), primary_key=True)
dest_se = Column(String(150), primary_key=True)
debug = Column(String(3), default='off')
debug_level = Column(Integer, default=1)
def __str__(self):
return "%s:%s %d" % (self.source_se, self.dest_se, self.debug_level)
if StrictVersion(sqlalchemy_version) < StrictVersion('0.6'):
__mapper_args__ = {
'allow_null_pks': True
}
else:
__mapper_args__ = {
'allow_partial_pks': True
}
class ServerConfig(Base):
__tablename__ = 't_server_config'
......@@ -142,15 +101,6 @@ class ServerConfig(Base):
show_user_dn = Column(Flag(negative='off', positive='on'), default='off')
class OptimizerConfig(Base):
__tablename__ = 't_optimize_mode'
auto_number = Column(Integer)
source_se = Column(String(150))
mode = Column(Integer, default=1, primary_key=True, name='mode_opt')
class OperationConfig(Base):
__tablename__ = 't_stage_req'
......
# Copyright notice:
#
# Copyright CERN 2013-2015
#
# Copyright Members of the EMI Collaboration, 2013.
# See www.eu-emi.eu for details on the copyright holders
#
# 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.
try:
import simplejson as json
except:
import json
import logging
from pylons import request
from urlparse import urlparse
from fts3.model import *
from fts3rest.controllers.config import audit_configuration
from fts3rest.lib.api import doc
from fts3rest.lib.base import BaseController, Session
from fts3rest.lib.helpers import jsonify, accept, get_input_as_dict
from fts3rest.lib.http_exceptions import *
from fts3rest.lib.middleware.fts3auth import authorize
from fts3rest.lib.middleware.fts3auth.constants import *
__controller__ = 'DebugConfigController'
log = logging.getLogger(__name__)
class DebugConfigController(BaseController):
"""
Operations on the config audit
"""
@doc.response(403, 'The user is not allowed to change the configuration')
@authorize(CONFIG)
@jsonify
def set_debug(self):
"""
Sets the debug level status for a storage
"""
input_dict = get_input_as_dict(request)
source = input_dict.get('source_se', None)
destin = input_dict.get('dest_se', None)
try:
level = int(input_dict.get('debug_level', 1))
except:
raise HTTPBadRequest('Invalid parameters')
if source:
source = urlparse(source)
if not source.scheme or not source.hostname:
raise HTTPBadRequest('Invalid storage')
source = "%s://%s" % (source.scheme, source.hostname)
if level:
src_debug = DebugConfig(
source_se=source,
dest_se='',
debug_level=level
)
Session.merge(src_debug)
audit_configuration(
'debug', 'Set debug for source %s to level %d' % (src_debug.source_se, src_debug.debug_level)
)
else:
Session.query(DebugConfig).filter(DebugConfig.source_se == source).delete()
audit_configuration(
'debug', 'Delete debug for source %s' % (source)
)
if destin:
destin = urlparse(destin)
if not destin.scheme or not destin.hostname:
raise HTTPBadRequest('Invalid storage')
destin = "%s://%s" % (destin.scheme, destin.hostname)
if level:
dst_debug = DebugConfig(
source_se='',
dest_se=destin,
debug_level=level
)
Session.merge(dst_debug)
audit_configuration(
'debug', 'Set debug for destination %s to level %d' % (dst_debug.dest_se, dst_debug.debug_level)
)
else:
Session.query(DebugConfig).filter(DebugConfig.dest_se == destin).delete()
audit_configuration('debug', 'Delete debug for destination %s' % (destin))
try:
Session.commit()
except:
Session.rollback()
raise
return input_dict
@doc.response(403, 'The user is not allowed to change the configuration')
@authorize(CONFIG)
def delete_debug(self, start_response):
"""
Removes a debug entry
"""
input_dict = get_input_as_dict(request, from_query=True)
source = input_dict.get('source_se', None)
destin = input_dict.get('dest_se', None)
if source:
source = str(source)
affected = Session.query(DebugConfig).filter(DebugConfig.source_se == source).delete()
if affected > 0:
audit_configuration('debug', 'Delete debug for source %s' % (source))
if destin:
destin = str(destin)
affected = Session.query(DebugConfig).filter(DebugConfig.dest_se == destin).delete()
if affected > 0:
audit_configuration('debug', 'Delete debug for destination %s' % (destin))
try:
Session.commit()
except:
Session.rollback()
raise
start_response('204 No Content', [])
return ['']
@doc.response(403, 'The user is not allowed to query the configuration')
@authorize(CONFIG)
@accept(html_template='/config/debug.html')
def list_debug(self):
"""
Return the debug settings
"""
return Session.query(DebugConfig).all()
......@@ -53,8 +53,8 @@ class LinkConfigController(BaseController):
"""
input_dict = get_input_as_dict(request)
source = input_dict.get('source', '*')
destination = input_dict.get('destination', '*')
source = input_dict.get('source_se', '*')
destination = input_dict.get('dest_se', '*')
symbolicname = input_dict.get('symbolicname', None)
if not symbolicname:
......@@ -64,11 +64,30 @@ class LinkConfigController(BaseController):
link_cfg = Session.query(LinkConfig).filter(LinkConfig.symbolicname == symbolicname).first()
try:
min_active = int(input_dict.get('min_active', 2))
max_active = int(input_dict.get('max_active', 2))
except Exception, e:
raise HTTPBadRequest('Active must be an integer (%s)' % str(e))
if not source or not destination:
raise HTTPBadRequest('Missing source and/or destination')
if min_active is None:
raise HTTPBadRequest('Missing min_active')
if max_active is None:
raise HTTPBadRequest('Missing max_active')
if min_active > max_active:
raise HTTPBadRequest('max_active is lower than min_active')
if not link_cfg:
link_cfg = LinkConfig(
source=source,
destination=destination,
symbolicname=symbolicname,
min_active = min_active,
max_active = max_active,
)
for key, value in input_dict.iteritems():
......
# Copyright notice:
#
# Copyright CERN 2013-2015
#
# Copyright Members of the EMI Collaboration, 2013.
# See www.eu-emi.eu for details on the copyright holders
#
# 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.
try:
import simplejson as json
except:
import json
import logging
from pylons import request
from fts3.model import *
from fts3rest.controllers.config import audit_configuration
from fts3rest.lib.api import doc
from fts3rest.lib.base import BaseController, Session
from fts3rest.lib.helpers import jsonify, accept, get_input_as_dict
from fts3rest.lib.http_exceptions import *
from fts3rest.lib.middleware.fts3auth import authorize
from fts3rest.lib.middleware.fts3auth.constants import *
__controller__ = 'SeGroupConfigController'
log = logging.getLogger(__name__)
class SeGroupConfigController(BaseController):
"""
Storage group configuration
"""
@doc.response(400, 'Invalid values passed in the request')
@doc.response(403, 'The user is not allowed to query the configuration')
@authorize(CONFIG)
@jsonify
def add_to_group(self):
"""
Add a SE to a group
"""
input_dict = get_input_as_dict(request)
member = input_dict.get('member', None)
groupname = input_dict.get('groupname', None)
if not member or not groupname:
raise HTTPBadRequest('Missing values')
# Check the member is in t_se
if not Session.query(Se).get(member):
se = Se(storage=member)
Session.merge(se)
new_member = Member(groupname=groupname, member=member)
audit_configuration('member-add', 'Added member %s to %s' % (member, groupname))
try:
Session.merge(new_member)
Session.commit()
except:
Session.rollback()
raise
return new_member
@doc.response(403, 'The user is not allowed to query the configuration')
@authorize(CONFIG)
@accept(html_template='/config/groups.html')
def get_all_groups(self):
"""
Get a list with all group names
"""
return Session.query(Member).order_by(Member.groupname).all()
@doc.response(403, 'The user is not allowed to query the configuration')
@doc.response(404, 'The group does not exist')
@authorize(CONFIG)
@jsonify
def get_group(self, group_name):
"""
Get the members of a group
"""
members = Session.query(Member).filter(Member.groupname == group_name).all()
if len(members) == 0:
raise HTTPNotFound('Group %s does not exist' % group_name)
return [m.member for m in members]
@doc.query_arg('member', 'Storage to remove. All group if left empty or absent', required=False)
@doc.response(204, 'Member removed')
@doc.response(403, 'The user is not allowed to query the configuration')
@doc.response(404, 'The group or the member does not exist')
@authorize(CONFIG)
def delete_from_group(self, group_name, start_response):
"""
Delete a member from a group. If the group is left empty, the group will be removed
"""
input_dict = get_input_as_dict(request, from_query=True)
storage = input_dict.get('member', None)
if storage:
Session.query(Member).filter((Member.groupname == group_name) & (Member.member == storage)).delete()
audit_configuration('group-delete', 'Member %s removed from group %s' % (storage, group_name))
else:
Session.query(Member).filter(Member.groupname == group_name).delete()
audit_configuration('group-delete', 'Group %s removed' % group_name)
try:
Session.commit()
except:
Session.rollback()
raise
start_response('204 No Content', [])
return ['']
/*
* Copyright 2015 CERN
*
* 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.
**/
/**
* Updates live the debug level
*/
function debugLevelSelect(debug)
{
var select = $("<select class='form-control'></select>");
$.each(["Verbose", "Very verbose", "Extremely verbose"], function(i, label) {
var option = $("<option></option>")
.text(label)
.attr("value", i + 1);
debug.debug_level = Math.max(1, debug.debug_level);
debug.debug_level = Math.min(3, debug.debug_level);
if (debug.debug_level == i + 1) {
option.attr("selected", "selected");
}
select.append(option);
});
select.change(function(e) {
var new_value = $(this).val();
var select = $(this);
select.prop("disabled", true);
$.ajax({
url: "/config/debug?",
type: "POST",
dataType: "json",
data: {source_se: debug.source_se, dest_se: debug.dest_se, debug_level: new_value}
})
.fail(function(jqXHR) {
errorMessage(jqXHR);
})
.always(function() {
select.prop("disabled", false);
});
});
return select;
}
/**
* Updates the list of debug settings
*/
function refreshDebugList()
{
var tbody = $("#debug-list");
$.ajax({
headers: {
Accept : "application/json",
},
url: "/config/debug?"
})
.done(function (data) {
tbody.empty();
$.each(data, function(i, debug) {
var tr = $("<tr></tr>");
var deleteBtn = $("<button class='btn btn-link' type='button'></button>")
.append("<i class='glyphicon glyphicon-trash'></i>");
deleteBtn.click(function() {
tr.css("background", "#d9534f");
$.ajax({
url: "/config/debug?source_se=" + encodeURIComponent(debug.source_se) + "&dest_se=" + encodeURIComponent(debug.dest_se),
type: "DELETE"
})
.done(function(data, textStatus, jqXHR) {
tr.fadeOut(300, function() {tr.remove();})
})
.fail(function(jqXHR) {
errorMessage(jqXHR);
tr.css("background", "#ffffff");
});
});
tbody.append(
tr.append($("<td></td>").append(deleteBtn))
.append($("<td></td>").append($("<span class='monospace'></span>").text(debug.vo)))
.append($("<td></td>").append($("<span class='monospace'></span>").text(debug.source_se)))
.append($("<td></td>").append($("<span class='monospace'></span>").text(debug.dest_se)))
.append($("<td></td>").append(debugLevelSelect(debug)))
);
});
})
.fail(function(jqXHR) {
errorMessage(jqXHR);
});
}
/**
* Initializes the debug view
*/
function setupDebug()
{
// Load list
refreshDebugList();
// Attach to the form
$("#debug-add-frm").submit(function(event) {
var payload = {
vo: $(this).find("[name=vo]").val(),
source_se: $(this).find("[name=source_se]").val(),
dest_se: $(this).find("[name=dest_se]").val(),
debug_level: $(this).find("[name=debug_level]").val(),
};
console.log(payload);
$.ajax({
url: "/config/debug?",
type: "POST",
dataType: "json",
contentType: "application/json",
data: JSON.stringify(payload)
})
.done(function(data, textStatus, jqXHR) {
refreshDebugList();
$("#debug-add-frm").trigger("reset");
})
.fail(function(jqXHR) {
errorMessage(jqXHR);
})
.always(function() {
$("#debug-add-frm-submit > i").attr("class", "glyphicon glyphicon-plus");
});
$("#debug-add-frm-submit > i").attr("class", "glyphicon glyphicon-refresh");
event.preventDefault();
});
// Autocomplete
$("#debug-add-field-source").autocomplete({
source: "/autocomplete/source"
});
$("#debug-add-field-destination").autocomplete({
source: "/autocomplete/destination"
});
}
/*
* Copyright 2015 CERN
*
* 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.
**/
/**
* Updates the list of configured groups
*/
function refreshGroupList()
{
var tbody = $("#group-list");
$.ajax({
headers: {
Accept : "application/json",
},
url: "/config/groups?",
})
.done(function(data, textStatus, jqXHR) {
tbody.empty();