/** * 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.state.stack.upgrade; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.controller.internal.OperatingSystemResourceProvider; import org.apache.ambari.server.controller.internal.RepositoryResourceProvider; import org.apache.ambari.server.controller.internal.RepositoryVersionResourceProvider; import org.apache.ambari.server.orm.entities.OperatingSystemEntity; import org.apache.ambari.server.orm.entities.RepositoryEntity; import org.apache.ambari.server.state.RepositoryInfo; import org.apache.ambari.server.state.stack.UpgradePack; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.inject.Inject; import com.google.inject.Singleton; /** * Provides helper methods to manage repository versions. */ @Singleton public class RepositoryVersionHelper { private static final Logger LOG = LoggerFactory.getLogger(RepositoryVersionHelper.class); @Inject private Gson gson; @Inject(optional = true) private AmbariMetaInfo ambariMetaInfo; /** * Parses operating systems json to a list of entities. Expects json like: * <pre> * [ * { * "repositories":[ * { * "Repositories/base_url":"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0", * "Repositories/repo_name":"HDP-UTILS", * "Repositories/repo_id":"HDP-UTILS-1.1.0.20" * }, * { * "Repositories/base_url":"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0", * "Repositories/repo_name":"HDP", * "Repositories/repo_id":"HDP-2.2" * } * ], * "OperatingSystems/os_type":"redhat6" * } * ] * </pre> * @param repositoriesJson operating systems json * @return list of operating system entities * @throws Exception if any kind of json parsing error happened */ public List<OperatingSystemEntity> parseOperatingSystems(String repositoriesJson) throws Exception { final List<OperatingSystemEntity> operatingSystems = new ArrayList<>(); final JsonArray rootJson = new JsonParser().parse(repositoriesJson).getAsJsonArray(); for (JsonElement operatingSystemJson: rootJson) { JsonObject osObj = operatingSystemJson.getAsJsonObject(); final OperatingSystemEntity operatingSystemEntity = new OperatingSystemEntity(); operatingSystemEntity.setOsType(osObj.get(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID).getAsString()); if (osObj.has(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS)) { operatingSystemEntity.setAmbariManagedRepos(osObj.get( OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS).getAsBoolean()); } for (JsonElement repositoryElement: osObj.get(RepositoryVersionResourceProvider.SUBRESOURCE_REPOSITORIES_PROPERTY_ID).getAsJsonArray()) { final RepositoryEntity repositoryEntity = new RepositoryEntity(); final JsonObject repositoryJson = repositoryElement.getAsJsonObject(); repositoryEntity.setBaseUrl(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID).getAsString()); repositoryEntity.setName(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID).getAsString()); repositoryEntity.setRepositoryId(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID).getAsString()); if (repositoryJson.get(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID) != null) { repositoryEntity.setMirrorsList(repositoryJson.get(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID).getAsString()); } if (repositoryJson.getAsJsonObject().get(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID) != null) { repositoryEntity.setUnique(repositoryJson.getAsJsonObject().get(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID).getAsBoolean()); } operatingSystemEntity.getRepositories().add(repositoryEntity); } operatingSystems.add(operatingSystemEntity); } return operatingSystems; } /** * Serializes repository info to json for storing to DB. * Produces json like: * <pre> * [ * { * "repositories":[ * { * "Repositories/base_url":"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0", * "Repositories/repo_name":"HDP-UTILS", * "Repositories/repo_id":"HDP-UTILS-1.1.0.20" * }, * { * "Repositories/base_url":"http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/updates/2.2.0.0", * "Repositories/repo_name":"HDP", * "Repositories/repo_id":"HDP-2.2" * } * ], * "OperatingSystems/os_type":"redhat6" * } * ] * </pre> * * @param repositories list of repository infos * @return serialized list of operating systems */ public String serializeOperatingSystems(List<RepositoryInfo> repositories) { final JsonArray rootJson = new JsonArray(); final Multimap<String, RepositoryInfo> operatingSystems = ArrayListMultimap.create(); for (RepositoryInfo repository: repositories) { operatingSystems.put(repository.getOsType(), repository); } for (Entry<String, Collection<RepositoryInfo>> operatingSystem : operatingSystems.asMap().entrySet()) { final JsonObject operatingSystemJson = new JsonObject(); final JsonArray repositoriesJson = new JsonArray(); for (RepositoryInfo repository : operatingSystem.getValue()) { final JsonObject repositoryJson = new JsonObject(); repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID, repository.getBaseUrl()); repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID, repository.getRepoName()); repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID, repository.getRepoId()); repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_MIRRORS_LIST_PROPERTY_ID, repository.getMirrorsList()); repositoryJson.addProperty(RepositoryResourceProvider.REPOSITORY_UNIQUE_PROPERTY_ID, repository.isUnique()); repositoriesJson.add(repositoryJson); operatingSystemJson.addProperty(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS, repository.isAmbariManagedRepositories()); } operatingSystemJson.add(RepositoryVersionResourceProvider.SUBRESOURCE_REPOSITORIES_PROPERTY_ID, repositoriesJson); operatingSystemJson.addProperty(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID, operatingSystem.getKey()); rootJson.add(operatingSystemJson); } return gson.toJson(rootJson); } public String serializeOperatingSystemEntities(List<OperatingSystemEntity> operatingSystems) { List<RepositoryInfo> repositoryInfos = new ArrayList<>(); for (OperatingSystemEntity os: operatingSystems) { for (RepositoryEntity repositoryEntity: os.getRepositories()) { RepositoryInfo repositoryInfo = new RepositoryInfo(); repositoryInfo.setRepoId(repositoryEntity.getRepositoryId()); repositoryInfo.setRepoName(repositoryEntity.getName()); repositoryInfo.setBaseUrl(repositoryEntity.getBaseUrl()); repositoryInfo.setOsType(os.getOsType()); repositoryInfo.setAmbariManagedRepositories(os.isAmbariManagedRepos()); repositoryInfos.add(repositoryInfo); } } return serializeOperatingSystems(repositoryInfos); } /** * Scans the given stack for upgrade packages which can be applied to update the cluster to given repository version. * * @param stackName stack name * @param stackVersion stack version * @param repositoryVersion target repository version * @param upgradeType if not {@code null} null, will only return upgrade packs whose type matches. * @return upgrade pack name * @throws AmbariException if no upgrade packs suit the requirements */ public String getUpgradePackageName(String stackName, String stackVersion, String repositoryVersion, UpgradeType upgradeType) throws AmbariException { final Map<String, UpgradePack> upgradePacks = ambariMetaInfo.getUpgradePacks(stackName, stackVersion); for (UpgradePack upgradePack : upgradePacks.values()) { final String upgradePackName = upgradePack.getName(); if (null != upgradeType && upgradePack.getType() != upgradeType) { continue; } // check that upgrade pack has <target> node if (StringUtils.isBlank(upgradePack.getTarget())) { LOG.error("Upgrade pack " + upgradePackName + " is corrupted, it should contain <target> node"); continue; } if (upgradePack.canBeApplied(repositoryVersion)) { return upgradePackName; } } throw new AmbariException("There were no suitable upgrade packs for stack " + stackName + " " + stackVersion + ((null != upgradeType) ? " and upgrade type " + upgradeType : "")); } }