blob: 98b91b3d295ab59e778ad140d3a98efc8bee44c1 [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.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.StaticallyInject;
import org.apache.ambari.server.api.resources.OperatingSystemResourceDefinition;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.predicate.AndPredicate;
import org.apache.ambari.server.controller.predicate.EqualsPredicate;
import org.apache.ambari.server.controller.predicate.OrPredicate;
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.Resource;
import org.apache.ambari.server.controller.spi.Resource.Type;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.controller.utilities.PredicateBuilder;
import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.repository.ManifestServiceInfo;
import org.apache.ambari.server.state.repository.VersionDefinitionXml;
import org.apache.ambari.server.state.stack.UpgradePack;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* Resource provider for repository versions resources.
*/
@StaticallyInject
public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourceProvider {
// ----- Property ID constants ---------------------------------------------
public static final String REPOSITORY_VERSION_ID_PROPERTY_ID = "CompatibleRepositoryVersions/id";
public static final String REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID = "CompatibleRepositoryVersions/stack_name";
public static final String REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID = "CompatibleRepositoryVersions/stack_version";
public static final String REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID = "CompatibleRepositoryVersions/repository_version";
public static final String REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID = "CompatibleRepositoryVersions/display_name";
public static final String REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID = "CompatibleRepositoryVersions/upgrade_types";
public static final String REPOSITORY_VERSION_SERVICES = "CompatibleRepositoryVersions/services";
public static final String REPOSITORY_VERSION_STACK_SERVICES = "CompatibleRepositoryVersions/stack_services";
public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID = new OperatingSystemResourceDefinition().getPluralName();
private static final String REPOSITORY_STACK_VALUE = "stack_value";
private static Set<String> pkPropertyIds = Collections.singleton(REPOSITORY_VERSION_ID_PROPERTY_ID);
static Set<String> propertyIds = Sets.newHashSet(
REPOSITORY_STACK_VALUE,
REPOSITORY_VERSION_ID_PROPERTY_ID,
REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID,
REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID,
REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID,
REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID,
REPOSITORY_VERSION_SERVICES,
REPOSITORY_VERSION_STACK_SERVICES);
static Map<Type, String> keyPropertyIds = new HashMap<Type, String>() {
{
put(Type.Stack, REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID);
put(Type.StackVersion, REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID);
put(Type.Upgrade, REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID);
put(Type.CompatibleRepositoryVersion, REPOSITORY_VERSION_ID_PROPERTY_ID);
}
};
@Inject
private static RepositoryVersionDAO s_repositoryVersionDAO;
@Inject
private static Provider<AmbariMetaInfo> s_ambariMetaInfo;
/**
* Create a new resource provider.
*/
public CompatibleRepositoryVersionResourceProvider(AmbariManagementController amc) {
super(propertyIds, keyPropertyIds, amc);
}
@Override
public Set<Resource> getResources(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
final Set<Resource> resources = new HashSet<>();
final Set<String> requestedIds = getRequestPropertyIds(request, predicate);
final Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
Long currentStackUniqueId = null;
Map<Long, CompatibleRepositoryVersion> compatibleRepositoryVersionsMap = new HashMap<>();
StackId stackId = null;
// !!! this is the case where the predicate was altered to include all stacks
for (Map<String, Object> propertyMap : propertyMaps) {
if (propertyMap.containsKey(REPOSITORY_STACK_VALUE)) {
stackId = new StackId(propertyMap.get(REPOSITORY_STACK_VALUE).toString());
break;
}
}
if (null == stackId) {
if (propertyMaps.size() == 1) {
Map<String, Object> propertyMap = propertyMaps.iterator().next();
stackId = getStackInformationFromUrl(propertyMap);
} else {
LOG.error("Property Maps size is NOT equal to 1. Current 'propertyMaps' size = {}", propertyMaps.size());
}
}
if (null == stackId) {
LOG.error("Could not determine stack to process. Returning empty set.");
return resources;
}
for (RepositoryVersionEntity repositoryVersionEntity : s_repositoryVersionDAO.findByStack(stackId)) {
currentStackUniqueId = repositoryVersionEntity.getId();
compatibleRepositoryVersionsMap.put(repositoryVersionEntity.getId(),
new CompatibleRepositoryVersion(repositoryVersionEntity));
if (LOG.isDebugEnabled()) {
LOG.debug("Added current stack id: {} to map", repositoryVersionEntity.getId());
}
}
Map<String, UpgradePack> packs = s_ambariMetaInfo.get().getUpgradePacks(
stackId.getStackName(), stackId.getStackVersion());
for (UpgradePack up : packs.values()) {
if (null != up.getTargetStack()) {
StackId targetStackId = new StackId(up.getTargetStack());
List<RepositoryVersionEntity> repositoryVersionEntities = s_repositoryVersionDAO.findByStack(targetStackId);
for (RepositoryVersionEntity repositoryVersionEntity : repositoryVersionEntities) {
if (compatibleRepositoryVersionsMap.containsKey(repositoryVersionEntity.getId())) {
compatibleRepositoryVersionsMap.get(repositoryVersionEntity.getId()).addUpgradePackType(up.getType());
if (LOG.isDebugEnabled()) {
LOG.debug("Stack id: {} exists in map. Appended new upgrade type {}" + repositoryVersionEntity.getId(), up.getType());
}
} else {
CompatibleRepositoryVersion compatibleRepositoryVersionEntity = new CompatibleRepositoryVersion(repositoryVersionEntity);
compatibleRepositoryVersionEntity.addUpgradePackType(up.getType());
compatibleRepositoryVersionsMap.put(repositoryVersionEntity.getId(), compatibleRepositoryVersionEntity);
if (LOG.isDebugEnabled()) {
LOG.debug("Added Stack id: {} to map with upgrade type {}", repositoryVersionEntity.getId(), up.getType());
}
}
}
} else {
if (currentStackUniqueId != null) {
compatibleRepositoryVersionsMap.get(currentStackUniqueId).addUpgradePackType(up.getType());
if (LOG.isDebugEnabled()) {
LOG.debug("Current Stack id: {} retrieved from map. Added upgrade type {}", currentStackUniqueId, up.getType());
}
} else {
LOG.error("Couldn't retrieve Current stack entry from Map.");
}
}
}
for (CompatibleRepositoryVersion entity : compatibleRepositoryVersionsMap.values()) {
RepositoryVersionEntity repositoryVersionEntity = entity.getRepositoryVersionEntity();
final Resource resource = new ResourceImpl(Resource.Type.CompatibleRepositoryVersion);
setResourceProperty(resource, REPOSITORY_VERSION_ID_PROPERTY_ID, repositoryVersionEntity.getId(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID, repositoryVersionEntity.getStackName(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID, repositoryVersionEntity.getStackVersion(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID, repositoryVersionEntity.getDisplayName(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID, repositoryVersionEntity.getVersion(), requestedIds);
setResourceProperty(resource, REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID, entity.getSupportedTypes(), requestedIds);
final VersionDefinitionXml xml;
try {
xml = repositoryVersionEntity.getRepositoryXml();
} catch (Exception e) {
throw new SystemException(String.format("Could not load xml for Repository %s", repositoryVersionEntity.getId()), e);
}
final StackInfo stack;
try {
stack = s_ambariMetaInfo.get().getStack(repositoryVersionEntity.getStackName(), repositoryVersionEntity.getStackVersion());
} catch (AmbariException e) {
throw new SystemException(String.format("Could not load stack %s for Repository %s",
repositoryVersionEntity.getStackId().toString(), repositoryVersionEntity.getId()));
}
final List<ManifestServiceInfo> stackServices;
if (null != xml) {
setResourceProperty(resource, REPOSITORY_VERSION_SERVICES, xml.getAvailableServices(stack), requestedIds);
stackServices = xml.getStackServices(stack);
} else {
stackServices = new ArrayList<>();
for (ServiceInfo si : stack.getServices()) {
stackServices.add(new ManifestServiceInfo(si.getName(), si.getDisplayName(), si.getComment(),
Collections.singleton(si.getVersion())));
}
}
setResourceProperty(resource, REPOSITORY_VERSION_STACK_SERVICES, stackServices, requestedIds);
resources.add(resource);
}
return resources;
}
@Override
protected Set<String> getPKPropertyIds() {
return pkPropertyIds;
}
/**
* Gets the stack id from the request map
*
* @param propertyMap the request map
* @return the StackId, or {@code null} if not found.
*/
protected StackId getStackInformationFromUrl(Map<String, Object> propertyMap) {
if (propertyMap.containsKey(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID) && propertyMap.containsKey(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID)) {
return new StackId(propertyMap.get(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).toString(), propertyMap.get(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).toString());
}
return null;
}
/**
* Identify the case where this is a top-level request, containing ONLY the stack name
* and stack version. Determine all other compatible stacks and make a new Predicate
* out of them.
*
* Consider a stack STACK-2.2 that is compatible with 2.3 and 2.4. The result of this
* call will be a predicate like so (abbreviated):
* <pre>
* in -> AndPredicate([stack_name=STACK],[stack_version=2.2])
* out-> OrPredicate(
* AndPredicate([stack_name=STACK],[stack_version=2.2]),
* AndPredicate([stack_name=STACK],[stack_version=2.3]),
* AndPredicate([stack_name=STACK],[stack_version=2.4]) )
* </pre>
*
* Any input predicate that does not conform to ONLY stack_name/stack_version will
* revert to the that predicate (return {@code null}).
*/
@SuppressWarnings("rawtypes")
@Override
public Predicate amendPredicate(Predicate predicate) {
if (!AndPredicate.class.isInstance(predicate)) {
return null;
}
AndPredicate ap = (AndPredicate) predicate;
if (2 != ap.getPropertyIds().size()) {
return null;
}
if (!ap.getPropertyIds().contains(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID) &&
!ap.getPropertyIds().contains(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID)) {
return null;
}
Predicate[] predicates = ap.getPredicates();
if (!EqualsPredicate.class.isInstance(predicates[0]) || !EqualsPredicate.class.isInstance(predicates[1])) {
return null;
}
EqualsPredicate pred1 = (EqualsPredicate) predicates[0];
EqualsPredicate pred2 = (EqualsPredicate) predicates[1];
StackId stackId = null;
if (pred1.getPropertyId().equals(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID)) {
stackId = new StackId(pred1.getValue().toString(), pred2.getValue().toString());
} else {
stackId = new StackId(pred2.getValue().toString(), pred1.getValue().toString());
}
Map<String, UpgradePack> packs = s_ambariMetaInfo.get().getUpgradePacks(
stackId.getStackName(), stackId.getStackVersion());
Set<String> stackIds = new HashSet<>();
for (Entry<String, UpgradePack> entry : packs.entrySet()) {
UpgradePack pack = entry.getValue();
String packStack = pack.getTargetStack();
if (null == packStack || !packStack.equals(stackId.toString())) {
stackIds.add(packStack);
}
}
// !!! use the one passed in, it already includes the one of interest
List<Predicate> usable = new ArrayList<>();
usable.add(predicate);
// !!! add predicate for each of the compatible stacks as found by the upgrade packs
for (String requiredStack : stackIds) {
StackId targetStack = new StackId(requiredStack);
Predicate p = new PredicateBuilder().property(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).equals(targetStack.getStackName())
.and().property(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).equals(targetStack.getStackVersion()).toPredicate();
usable.add(p);
}
// !!! add the stack that is used to find compatible versions for
Predicate p = new PredicateBuilder().property(REPOSITORY_STACK_VALUE).equals(stackId.toString()).toPredicate();
usable.add(p);
p = new OrPredicate(usable.toArray(new Predicate[usable.size()]));
return p;
}
}