blob: df3ba4cebef530ae4dc9c3674c469dc1f27a7e67 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.ambari.server.controller.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.ClusterNotFoundException;
import org.apache.ambari.server.ConfigGroupNotFoundException;
import org.apache.ambari.server.DuplicateResourceException;
import org.apache.ambari.server.HostNotFoundException;
import org.apache.ambari.server.ParentObjectNotFoundException;
import org.apache.ambari.server.StaticallyInject;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.ConfigGroupRequest;
import org.apache.ambari.server.controller.ConfigGroupResponse;
import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
import org.apache.ambari.server.controller.spi.NoSuchResourceException;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.RequestStatus;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
import org.apache.ambari.server.controller.spi.ResourcePredicateEvaluator;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.orm.dao.HostDAO;
import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.security.authorization.AuthorizationHelper;
import org.apache.ambari.server.security.authorization.ResourceType;
import org.apache.ambari.server.security.authorization.RoleAuthorization;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ConfigFactory;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.configgroup.ConfigGroup;
import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Provider;
@StaticallyInject
public class ConfigGroupResourceProvider extends
AbstractControllerResourceProvider implements ResourcePredicateEvaluator {
private static final Logger configLogger = LoggerFactory.getLogger("configchange");
private static final Logger LOG = LoggerFactory.getLogger
(ConfigGroupResourceProvider.class);
public static final String CONFIG_GROUP = "ConfigGroup";
public static final String CLUSTER_NAME_PROPERTY_ID = "cluster_name";
public static final String ID_PROPERTY_ID = "id";
public static final String GROUP_NAME_PROPERTY_ID = "group_name";
public static final String TAG_PROPERTY_ID = "tag";
public static final String SERVICE_NAME_PROPERTY_ID = "service_name";
public static final String DESCRIPTION_PROPERTY_ID = "description";
public static final String SERVICE_CONFIG_VERSION_NOTE_PROPERTY_ID = "service_config_version_note";
public static final String HOST_NAME_PROPERTY_ID = "host_name";
public static final String HOSTS_HOSTNAME_PROPERTY_ID = "hosts/host_name";
public static final String HOSTS_PROPERTY_ID = "hosts";
public static final String DESIRED_CONFIGS_PROPERTY_ID = "desired_configs";
public static final String VERSION_TAGS_PROPERTY_ID = "version_tags";
public static final String CLUSTER_NAME = PropertyHelper.getPropertyId(CONFIG_GROUP, CLUSTER_NAME_PROPERTY_ID);
public static final String ID = PropertyHelper.getPropertyId(CONFIG_GROUP, ID_PROPERTY_ID);
public static final String GROUP_NAME = PropertyHelper.getPropertyId(CONFIG_GROUP, GROUP_NAME_PROPERTY_ID);
public static final String TAG = PropertyHelper.getPropertyId(CONFIG_GROUP, TAG_PROPERTY_ID);
public static final String SERVICE_NAME = PropertyHelper.getPropertyId(CONFIG_GROUP, SERVICE_NAME_PROPERTY_ID);
public static final String DESCRIPTION = PropertyHelper.getPropertyId(CONFIG_GROUP, DESCRIPTION_PROPERTY_ID);
public static final String SERVICE_CONFIG_VERSION_NOTE = PropertyHelper
.getPropertyId(CONFIG_GROUP, SERVICE_CONFIG_VERSION_NOTE_PROPERTY_ID);
public static final String HOST_NAME = PropertyHelper.getPropertyId(null, HOST_NAME_PROPERTY_ID);
public static final String HOSTS_HOST_NAME = PropertyHelper.getPropertyId(CONFIG_GROUP, HOSTS_HOSTNAME_PROPERTY_ID);
public static final String HOSTS = PropertyHelper.getPropertyId(CONFIG_GROUP, HOSTS_PROPERTY_ID);
public static final String DESIRED_CONFIGS = PropertyHelper.getPropertyId(CONFIG_GROUP, DESIRED_CONFIGS_PROPERTY_ID);
public static final String VERSION_TAGS = PropertyHelper.getPropertyId(CONFIG_GROUP, VERSION_TAGS_PROPERTY_ID);
/**
* The key property ids for a ConfigGroup resource.
*/
private static final Map<Resource.Type, String> keyPropertyIds = ImmutableMap.<Resource.Type, String>builder()
.put(Resource.Type.Cluster, CLUSTER_NAME)
.put(Resource.Type.ConfigGroup, ID)
.build();
/**
* The property ids for a ConfigGroup resource.
*/
private static final Set<String> propertyIds = Sets.newHashSet(
CLUSTER_NAME,
ID,
GROUP_NAME,
TAG,
SERVICE_NAME,
DESCRIPTION,
SERVICE_CONFIG_VERSION_NOTE,
HOST_NAME,
HOSTS_HOST_NAME,
HOSTS,
DESIRED_CONFIGS,
VERSION_TAGS);
@Inject
private static HostDAO hostDAO;
/**
* Used for creating {@link Config} instances to return in the REST response.
*/
@Inject
private static ConfigFactory configFactory;
@Inject
private static Provider<ConfigHelper> m_configHelper;
/**
* Create a new resource provider for the given management controller.
*
* @param managementController the management controller
*/
protected ConfigGroupResourceProvider(AmbariManagementController managementController) {
super(Resource.Type.ConfigGroup, propertyIds, keyPropertyIds, managementController);
EnumSet<RoleAuthorization> manageGroupsAuthSet =
EnumSet.of(RoleAuthorization.SERVICE_MANAGE_CONFIG_GROUPS, RoleAuthorization.CLUSTER_MANAGE_CONFIG_GROUPS);
setRequiredCreateAuthorizations(manageGroupsAuthSet);
setRequiredDeleteAuthorizations(manageGroupsAuthSet);
setRequiredUpdateAuthorizations(manageGroupsAuthSet);
setRequiredGetAuthorizations(EnumSet.of(RoleAuthorization.CLUSTER_VIEW_CONFIGS,
RoleAuthorization.CLUSTER_MANAGE_CONFIG_GROUPS, RoleAuthorization.SERVICE_VIEW_CONFIGS,
RoleAuthorization.SERVICE_MANAGE_CONFIG_GROUPS, RoleAuthorization.SERVICE_COMPARE_CONFIGS));
}
@Override
protected Set<String> getPKPropertyIds() {
return new HashSet<>(keyPropertyIds.values());
}
@Override
public RequestStatus createResourcesAuthorized(Request request) throws
SystemException, UnsupportedPropertyException,
ResourceAlreadyExistsException, NoSuchParentResourceException {
final Set<ConfigGroupRequest> requests = new HashSet<>();
for (Map<String, Object> propertyMap : request.getProperties()) {
requests.add(getConfigGroupRequest(propertyMap));
}
RequestStatus status = createResources(requests);
notifyCreate(Resource.Type.ConfigGroup, request);
return status;
}
@Override
public Set<Resource> getResourcesAuthorized(Request request, Predicate predicate) throws
SystemException, UnsupportedPropertyException, NoSuchResourceException,
NoSuchParentResourceException {
final Set<ConfigGroupRequest> requests = new HashSet<>();
for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
requests.add(getConfigGroupRequest(propertyMap));
}
Set<ConfigGroupResponse> responses = getResources(new Command<Set<ConfigGroupResponse>>() {
@Override
public Set<ConfigGroupResponse> invoke() throws AmbariException {
return getConfigGroups(requests);
}
});
Set<String> requestedIds = getRequestPropertyIds(request, predicate);
Set<Resource> resources = new HashSet<>();
if (requestedIds.contains(HOSTS_HOST_NAME)) {
requestedIds.add(HOSTS);
}
for (ConfigGroupResponse response : responses) {
Resource resource = new ResourceImpl(Resource.Type.ConfigGroup);
setResourceProperty(resource, ID,
response.getId(), requestedIds);
setResourceProperty(resource, CLUSTER_NAME,
response.getClusterName(), requestedIds);
setResourceProperty(resource, GROUP_NAME,
response.getGroupName(), requestedIds);
setResourceProperty(resource, TAG,
response.getTag(), requestedIds);
setResourceProperty(resource, DESCRIPTION,
response.getDescription(), requestedIds);
setResourceProperty(resource, HOSTS,
response.getHosts(), requestedIds);
setResourceProperty(resource, DESIRED_CONFIGS,
response.getConfigurations(), requestedIds);
resources.add(resource);
}
return resources;
}
@Override
public RequestStatus updateResourcesAuthorized(Request request, Predicate predicate) throws
SystemException, UnsupportedPropertyException,
NoSuchResourceException, NoSuchParentResourceException {
final Set<ConfigGroupRequest> requests = new HashSet<>();
Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
if (iterator.hasNext()) {
for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) {
requests.add(getConfigGroupRequest(propertyMap));
}
}
updateResources(requests);
Set<Resource> associatedResources = new HashSet<>();
for (ConfigGroupRequest configGroupRequest : requests) {
ConfigGroupResponse configGroupResponse = getManagementController().getConfigGroupUpdateResults(configGroupRequest);
Resource resource = new ResourceImpl(Resource.Type.ConfigGroup);
resource.setProperty(ID, configGroupResponse.getId());
resource.setProperty(CLUSTER_NAME, configGroupResponse.getClusterName());
resource.setProperty(GROUP_NAME, configGroupResponse.getGroupName());
resource.setProperty(TAG, configGroupResponse.getTag());
resource.setProperty(VERSION_TAGS, configGroupResponse.getVersionTags());
associatedResources.add(resource);
}
notifyUpdate(Resource.Type.ConfigGroup, request, predicate);
return getRequestStatus(null, associatedResources);
}
@Override
public RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate) throws
SystemException, UnsupportedPropertyException, NoSuchResourceException,
NoSuchParentResourceException {
for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
final ConfigGroupRequest configGroupRequest = getConfigGroupRequest(propertyMap);
modifyResources(new Command<Void>() {
@Override
public Void invoke() throws AmbariException, AuthorizationException {
deleteConfigGroup(configGroupRequest);
return null;
}
});
}
notifyDelete(Resource.Type.ConfigGroup, predicate);
return getRequestStatus(null);
}
@Override
public Set<String> checkPropertyIds(Set<String> propertyIds) {
//allow providing service_config_version_note, but we should not return it for config group
Set<String> unsupportedPropertyIds = super.checkPropertyIds(propertyIds);
for (Iterator<String> iterator = unsupportedPropertyIds.iterator(); iterator.hasNext(); ) {
String next = iterator.next();
next = PropertyHelper.getPropertyName(next);
if (next.equals("service_config_version_note") || next.equals("/service_config_version_note")) {
iterator.remove();
}
}
return unsupportedPropertyIds;
}
/**
* Create configuration group resources based on set of config group requests.
*
* @param requests set of config group requests
*
* @return a request status
*
* @throws SystemException an internal system exception occurred
* @throws UnsupportedPropertyException the request contains unsupported property ids
* @throws ResourceAlreadyExistsException attempted to create a resource which already exists
* @throws NoSuchParentResourceException a parent resource of the resource to create doesn't exist
*/
public RequestStatus createResources(final Set<ConfigGroupRequest> requests)throws
SystemException, UnsupportedPropertyException,
ResourceAlreadyExistsException, NoSuchParentResourceException{
Set<ConfigGroupResponse> responses =
createResources(new Command<Set<ConfigGroupResponse>>() {
@Override
public Set<ConfigGroupResponse> invoke() throws AmbariException, AuthorizationException {
return createConfigGroups(requests);
}
});
Set<Resource> associatedResources = new HashSet<>();
for (ConfigGroupResponse response : responses) {
Resource resource = new ResourceImpl(Resource.Type.ConfigGroup);
resource.setProperty(ID, response.getId());
associatedResources.add(resource);
}
return getRequestStatus(null, associatedResources);
}
public RequestStatus updateResources(final Set<ConfigGroupRequest> requests)
throws SystemException,
UnsupportedPropertyException,
NoSuchResourceException,
NoSuchParentResourceException {
modifyResources(new Command<Void>() {
@Override
public Void invoke() throws AmbariException, AuthorizationException {
updateConfigGroups(requests);
return null;
}
});
return getRequestStatus(null);
}
private synchronized Set<ConfigGroupResponse> getConfigGroups
(Set<ConfigGroupRequest> requests) throws AmbariException {
Set<ConfigGroupResponse> responses = new HashSet<>();
if (requests != null) {
for (ConfigGroupRequest request : requests) {
LOG.debug("Received a Config group request with, clusterName = {}, groupId = {}, groupName = {}, tag = {}",
request.getClusterName(), request.getId(), request.getGroupName(), request.getTag());
if (request.getClusterName() == null) {
LOG.warn("Cluster name is a required field.");
continue;
}
Cluster cluster = getManagementController().getClusters().getCluster
(request.getClusterName());
Map<Long, ConfigGroup> configGroupMap = cluster.getConfigGroups();
// By group id
if (request.getId() != null) {
ConfigGroup configGroup = configGroupMap.get(request.getId());
if (configGroup != null) {
responses.add(configGroup.convertToResponse());
} else {
throw new ConfigGroupNotFoundException(cluster.getClusterName(),
request.getId().toString());
}
continue;
}
// By group name
if (request.getGroupName() != null) {
for (ConfigGroup configGroup : configGroupMap.values()) {
if (configGroup.getName().equals(request.getGroupName())) {
responses.add(configGroup.convertToResponse());
}
}
continue;
}
// By tag only
if (request.getTag() != null && request.getHosts().isEmpty()) {
for (ConfigGroup configGroup : configGroupMap.values()) {
if (configGroup.getTag().equals(request.getTag())) {
responses.add(configGroup.convertToResponse());
}
}
continue;
}
// By hostnames only
if (!request.getHosts().isEmpty() && request.getTag() == null) {
for (String hostname : request.getHosts()) {
Map<Long, ConfigGroup> groupMap = cluster
.getConfigGroupsByHostname(hostname);
if (!groupMap.isEmpty()) {
for (ConfigGroup configGroup : groupMap.values()) {
responses.add(configGroup.convertToResponse());
}
}
}
continue;
}
// By tag and hostnames
if (request.getTag() != null && !request.getHosts().isEmpty()) {
for (ConfigGroup configGroup : configGroupMap.values()) {
// Has tag
if (configGroup.getTag().equals(request.getTag())) {
// Has a match with hosts
List<Long> groupHostIds = new ArrayList<>(configGroup.getHosts().keySet());
Set<String> groupHostNames = new HashSet<>(hostDAO.getHostNamesByHostIds(groupHostIds));
groupHostNames.retainAll(request.getHosts());
if (!groupHostNames.isEmpty()) {
responses.add(configGroup.convertToResponse());
}
}
}
continue;
}
// Select all
for (ConfigGroup configGroup : configGroupMap.values()) {
responses.add(configGroup.convertToResponse());
}
}
}
return responses;
}
private void verifyConfigs(Map<String, Config> configs, String clusterName) throws AmbariException {
if (configs == null) {
return;
}
Clusters clusters = getManagementController().getClusters();
for (String key : configs.keySet()) {
if(!clusters.getCluster(clusterName).isConfigTypeExists(key)){
throw new AmbariException("Trying to add not existent config type to config group:"+
" configType = "+ key +
" cluster = " + clusterName);
}
}
}
private void verifyHostList(Cluster cluster, Map<Long, Host> hosts,
ConfigGroupRequest request) throws AmbariException {
Map<Long, ConfigGroup> configGroupMap = cluster.getConfigGroups();
if (configGroupMap != null) {
for (ConfigGroup configGroup : configGroupMap.values()) {
if (configGroup.getTag().equals(request.getTag())
&& !configGroup.getId().equals(request.getId())) {
// Check the new host list for duplicated with this group
for (Host host : hosts.values()) {
if (configGroup.getHosts().containsKey(host.getHostId())) {
throw new DuplicateResourceException("Host is already " +
"associated with a config group"
+ ", clusterName = " + configGroup.getClusterName()
+ ", configGroupName = " + configGroup.getName()
+ ", tag = " + configGroup.getTag()
+ ", hostname = " + host.getHostName());
}
}
}
}
}
}
private synchronized void deleteConfigGroup(ConfigGroupRequest request)
throws AmbariException, AuthorizationException {
if (request.getId() == null) {
throw new AmbariException("Config group id is a required field.");
}
Clusters clusters = getManagementController().getClusters();
Cluster cluster;
try {
cluster = clusters.getCluster(request.getClusterName());
} catch (ClusterNotFoundException e) {
throw new ParentObjectNotFoundException(
"Attempted to delete a config group from a cluster which doesn't " +
"exist", e);
}
ConfigGroup configGroup = cluster.getConfigGroups().get(request.getId());
if (configGroup == null) {
throw new ConfigGroupNotFoundException(cluster.getClusterName(), request.getId().toString());
}
if (StringUtils.isEmpty(configGroup.getServiceName())) {
if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(),
RoleAuthorization.CLUSTER_MANAGE_CONFIG_GROUPS)) {
throw new AuthorizationException("The authenticated user is not authorized to delete config groups");
}
} else {
if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(),
RoleAuthorization.SERVICE_MANAGE_CONFIG_GROUPS)) {
throw new AuthorizationException("The authenticated user is not authorized to delete config groups");
}
}
configLogger.info("(configchange) Deleting configuration group. cluster: '{}', changed by: '{}', config group: '{}', config group id: '{}'",
cluster.getClusterName(), getManagementController().getAuthName(), configGroup.getName(), request.getId());
cluster.deleteConfigGroup(request.getId());
}
private void validateRequest(ConfigGroupRequest request) {
if (request.getClusterName() == null
|| request.getClusterName().isEmpty()
|| request.getGroupName() == null
|| request.getGroupName().isEmpty()
|| request.getTag() == null
|| request.getTag().isEmpty()) {
LOG.debug("Received a config group request with cluster name = {}, group name = {}, tag = {}",
request.getClusterName(), request.getGroupName(), request.getTag());
throw new IllegalArgumentException("Cluster name, group name and tag need to be provided.");
}
}
private synchronized Set<ConfigGroupResponse> createConfigGroups
(Set<ConfigGroupRequest> requests) throws AmbariException, AuthorizationException {
if (requests.isEmpty()) {
LOG.warn("Received an empty requests set");
return null;
}
Set<ConfigGroupResponse> configGroupResponses = new
HashSet<>();
Clusters clusters = getManagementController().getClusters();
ConfigGroupFactory configGroupFactory = getManagementController()
.getConfigGroupFactory();
Set<String> updatedClusters = new HashSet<>();
for (ConfigGroupRequest request : requests) {
Cluster cluster;
try {
cluster = clusters.getCluster(request.getClusterName());
} catch (ClusterNotFoundException e) {
throw new ParentObjectNotFoundException(
"Attempted to add a config group to a cluster which doesn't exist", e);
}
validateRequest(request);
Map<Long, ConfigGroup> configGroupMap = cluster.getConfigGroups();
if (configGroupMap != null) {
for (ConfigGroup configGroup : configGroupMap.values()) {
if (configGroup.getName().equals(request.getGroupName()) &&
configGroup.getTag().equals(request.getTag())) {
throw new DuplicateResourceException("Config group already " +
"exists with the same name and tag"
+ ", clusterName = " + request.getClusterName()
+ ", groupName = " + request.getGroupName()
+ ", tag = " + request.getTag());
}
}
}
// Find hosts
Map<Long, Host> hosts = new HashMap<>();
if (request.getHosts() != null && !request.getHosts().isEmpty()) {
for (String hostname : request.getHosts()) {
Host host = clusters.getHost(hostname);
HostEntity hostEntity = hostDAO.findByName(hostname);
if (host == null || hostEntity == null) {
throw new HostNotFoundException(hostname);
}
hosts.put(hostEntity.getHostId(), host);
}
}
verifyHostList(cluster, hosts, request);
String serviceName = request.getServiceName();
if (serviceName == null && !MapUtils.isEmpty(request.getConfigs())) {
try {
serviceName = cluster.getServiceForConfigTypes(request.getConfigs().keySet());
} catch (IllegalArgumentException e) {
// Ignore this since we may have hit a config type that spans multiple services. This may
// happen in unit test cases but should not happen with later versions of stacks.
}
}
if (StringUtils.isEmpty(serviceName)) {
if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(),
RoleAuthorization.CLUSTER_MANAGE_CONFIG_GROUPS)) {
throw new AuthorizationException("The authenticated user is not authorized to create config groups");
}
} else {
if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(),
RoleAuthorization.SERVICE_MANAGE_CONFIG_GROUPS)) {
throw new AuthorizationException("The authenticated user is not authorized to create config groups");
}
}
configLogger.info("(configchange) Creating new configuration group. cluster: '{}', changed by: '{}', config group: '{}', tag: '{}'",
cluster.getClusterName(), getManagementController().getAuthName(), request.getGroupName(), request.getTag());
verifyConfigs(request.getConfigs(), cluster.getClusterName());
ConfigGroup configGroup = configGroupFactory.createNew(cluster, serviceName,
request.getGroupName(),
request.getTag(), request.getDescription(),
request.getConfigs(), hosts);
cluster.addConfigGroup(configGroup);
if (serviceName != null) {
cluster.createServiceConfigVersion(serviceName, getManagementController().getAuthName(),
request.getServiceConfigVersionNote(), configGroup);
} else {
LOG.warn("Could not determine service name for config group {}, service config version not created",
configGroup.getId());
}
ConfigGroupResponse response = new ConfigGroupResponse(configGroup
.getId(), configGroup.getClusterName(), configGroup.getName(),
configGroup.getTag(), configGroup.getDescription(), null, null);
configGroupResponses.add(response);
updatedClusters.add(cluster.getClusterName());
}
m_configHelper.get().updateAgentConfigs(updatedClusters);
return configGroupResponses;
}
private synchronized void updateConfigGroups (Set<ConfigGroupRequest> requests) throws AmbariException, AuthorizationException {
if (requests.isEmpty()) {
LOG.warn("Received an empty requests set");
return;
}
Clusters clusters = getManagementController().getClusters();
Set<String> updatedClusters = new HashSet<>();
for (ConfigGroupRequest request : requests) {
Cluster cluster;
try {
cluster = clusters.getCluster(request.getClusterName());
} catch (ClusterNotFoundException e) {
throw new ParentObjectNotFoundException(
"Attempted to add a config group to a cluster which doesn't exist", e);
}
if (request.getId() == null) {
throw new AmbariException("Config group Id is a required parameter.");
}
validateRequest(request);
// Find config group
ConfigGroup configGroup = cluster.getConfigGroups().get(request.getId());
if (configGroup == null) {
throw new AmbariException("Config group not found"
+ ", clusterName = " + request.getClusterName()
+ ", groupId = " + request.getId());
}
String serviceName = configGroup.getServiceName();
String requestServiceName = cluster.getServiceForConfigTypes(request.getConfigs().keySet());
if (StringUtils.isEmpty(serviceName) && StringUtils.isEmpty(requestServiceName)) {
if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(),
RoleAuthorization.CLUSTER_MANAGE_CONFIG_GROUPS)) {
throw new AuthorizationException("The authenticated user is not authorized to update config groups");
}
} else {
if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(),
RoleAuthorization.SERVICE_MANAGE_CONFIG_GROUPS)) {
throw new AuthorizationException("The authenticated user is not authorized to update config groups");
}
}
if (serviceName != null && requestServiceName != null && !StringUtils.equals(serviceName, requestServiceName)) {
throw new IllegalArgumentException("Config group " + configGroup.getId() +
" is mapped to service " + serviceName + ", " +
"but request contain configs from service " + requestServiceName);
} else if (serviceName == null && requestServiceName != null) {
configGroup.setServiceName(requestServiceName);
serviceName = requestServiceName;
}
int numHosts = (null != configGroup.getHosts()) ? configGroup.getHosts().size() : 0;
configLogger.info("(configchange) Updating configuration group host membership or config value. cluster: '{}', changed by: '{}', " +
"service_name: '{}', config group: '{}', tag: '{}', num hosts in config group: '{}', note: '{}'",
cluster.getClusterName(), getManagementController().getAuthName(),
serviceName, request.getGroupName(), request.getTag(), numHosts, request.getServiceConfigVersionNote());
if (!request.getConfigs().isEmpty()) {
List<String> affectedConfigTypeList = new ArrayList(request.getConfigs().keySet());
Collections.sort(affectedConfigTypeList);
String affectedConfigTypesString = "(" + StringUtils.join(affectedConfigTypeList, ", ") + ")";
configLogger.info("(configchange) Affected configs: {}", affectedConfigTypesString);
for (Config config : request.getConfigs().values()) {
List<String> sortedConfigKeys = new ArrayList(config.getProperties().keySet());
Collections.sort(sortedConfigKeys);
String sortedConfigKeysString = StringUtils.join(sortedConfigKeys, ", ");
configLogger.info("(configchange) Config type '{}' was modified with the following keys, {}", config.getType(), sortedConfigKeysString);
}
}
// Update hosts
Map<Long, Host> hosts = new HashMap<>();
if (request.getHosts() != null && !request.getHosts().isEmpty()) {
for (String hostname : request.getHosts()) {
Host host = clusters.getHost(hostname);
HostEntity hostEntity = hostDAO.findById(host.getHostId());
if (hostEntity == null) {
throw new HostNotFoundException(hostname);
}
hosts.put(hostEntity.getHostId(), host);
}
}
verifyHostList(cluster, hosts, request);
configGroup.setHosts(hosts);
// Update Configs
verifyConfigs(request.getConfigs(), request.getClusterName());
configGroup.setConfigurations(request.getConfigs());
// Save
configGroup.setName(request.getGroupName());
configGroup.setDescription(request.getDescription());
configGroup.setTag(request.getTag());
if (serviceName != null) {
cluster.createServiceConfigVersion(serviceName, getManagementController().getAuthName(),
request.getServiceConfigVersionNote(), configGroup);
ConfigGroupResponse configGroupResponse = new ConfigGroupResponse(configGroup.getId(), cluster.getClusterName(), configGroup.getName(),
request.getTag(), "", new HashSet<>(), new HashSet<>());
Set<Map<String, Object>> versionTags = new HashSet<>();
Map<String, Object> tagsMap = new HashMap<>();
for (Config config : configGroup.getConfigurations().values()) {
tagsMap.put(config.getType(), config.getTag());
}
versionTags.add(tagsMap);
configGroupResponse.setVersionTags(versionTags);
getManagementController().saveConfigGroupUpdate(request, configGroupResponse);
updatedClusters.add(cluster.getClusterName());
} else {
LOG.warn("Could not determine service name for config group {}, service config version not created",
configGroup.getId());
}
}
m_configHelper.get().updateAgentConfigs(updatedClusters);
}
@SuppressWarnings("unchecked")
ConfigGroupRequest getConfigGroupRequest(Map<String, Object> properties) {
Object groupIdObj = properties.get(ID);
Long groupId = null;
if (groupIdObj != null) {
groupId = groupIdObj instanceof Long ? (Long) groupIdObj :
Long.parseLong((String) groupIdObj);
}
ConfigGroupRequest request = new ConfigGroupRequest(
groupId,
(String) properties.get(CLUSTER_NAME),
(String) properties.get(GROUP_NAME),
(String) properties.get(TAG),
(String) properties.get(SERVICE_NAME),
(String) properties.get(DESCRIPTION),
null,
null);
request.setServiceConfigVersionNote((String) properties.get(SERVICE_CONFIG_VERSION_NOTE));
Map<String, Config> configurations = new HashMap<>();
Set<String> hosts = new HashSet<>();
String hostnameKey = HOST_NAME;
Object hostObj = properties.get(HOSTS);
if (hostObj == null) {
hostnameKey = HOSTS_HOST_NAME;
hostObj = properties.get(HOSTS_HOST_NAME);
}
if (hostObj != null) {
if (hostObj instanceof HashSet<?>) {
try {
Set<Map<String, String>> hostsSet = (Set<Map<String, String>>) hostObj;
for (Map<String, String> hostMap : hostsSet) {
if (hostMap.containsKey(hostnameKey)) {
String hostname = hostMap.get(hostnameKey);
hosts.add(hostname);
}
}
} catch (Exception e) {
LOG.warn("Host json in unparseable format. " + hostObj, e);
}
} else {
if (hostObj instanceof String) {
hosts.add((String) hostObj);
}
}
}
Object configObj = properties.get(DESIRED_CONFIGS);
if (configObj != null && configObj instanceof HashSet<?>) {
try {
Set<Map<String, Object>> configSet = (Set<Map<String, Object>>) configObj;
for (Map<String, Object> configMap : configSet) {
String type = (String) configMap.get(ConfigurationResourceProvider.TYPE);
String tag = (String) configMap.get(ConfigurationResourceProvider.TAG);
Map<String, String> configProperties = new HashMap<>();
Map<String, Map<String, String>> configAttributes = new HashMap<>();
for (Map.Entry<String, Object> entry : configMap.entrySet()) {
String propertyCategory = PropertyHelper.getPropertyCategory(entry.getKey());
if (propertyCategory != null && entry.getValue() != null) {
if ("properties".equals(propertyCategory)) {
configProperties.put(PropertyHelper.getPropertyName(entry.getKey()),
entry.getValue().toString());
} else if ("properties_attributes".equals(PropertyHelper.getPropertyCategory(propertyCategory))) {
String attributeName = PropertyHelper.getPropertyName(propertyCategory);
if (!configAttributes.containsKey(attributeName)) {
configAttributes.put(attributeName, new HashMap<>());
}
Map<String, String> attributeValues
= configAttributes.get(attributeName);
attributeValues.put(PropertyHelper.getPropertyName(entry.getKey()),
entry.getValue().toString());
}
}
}
Config config = configFactory.createReadOnly(type, tag, configProperties, configAttributes);
configurations.put(config.getType(), config);
}
} catch (Exception e) {
LOG.warn("Config json in unparseable format. " + configObj, e);
}
}
request.setConfigs(configurations);
request.setHosts(hosts);
return request;
}
/**
* Bypassing predicate evaluation for the lack of a matcher for a
* non-scalar resource
*
* @param predicate the predicate
* @param resource the resource
*
* @return always returns true
*/
@Override
public boolean evaluate(Predicate predicate, Resource resource) {
return true;
}
}