diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRenderer.java b/ambari-server/src/main/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRenderer.java index e518de7b68f..e34fcb13361 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRenderer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRenderer.java @@ -18,6 +18,8 @@ package org.apache.ambari.server.api.query.render; +import static java.util.stream.Collectors.toList; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -26,10 +28,12 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.api.query.QueryInfo; +import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.api.services.Request; import org.apache.ambari.server.api.services.Result; import org.apache.ambari.server.api.services.ResultImpl; @@ -42,6 +46,7 @@ import org.apache.ambari.server.controller.internal.ArtifactResourceProvider; import org.apache.ambari.server.controller.internal.BlueprintConfigurationProcessor; import org.apache.ambari.server.controller.internal.BlueprintResourceProvider; +import org.apache.ambari.server.controller.internal.ClusterSettingResourceProvider; import org.apache.ambari.server.controller.internal.ExportBlueprintRequest; import org.apache.ambari.server.controller.internal.RequestImpl; import org.apache.ambari.server.controller.internal.ResourceImpl; @@ -68,7 +73,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.Iterables; +import com.google.common.collect.ImmutableMap; /** * Renderer which renders a cluster resource as a blueprint. @@ -80,6 +85,12 @@ public class ClusterBlueprintRenderer extends BaseRenderer implements Renderer { */ private AmbariManagementController controller = AmbariServer.getController(); + + /** + * MetaInfo used to get stack and mpack information. + */ + private AmbariMetaInfo metaInfo = controller.getAmbariMetaInfo(); + // /** // * Map of configuration type to configuration properties which are required that a user // * input. These properties will be stripped from the exported blueprint. @@ -101,48 +112,38 @@ public TreeNode> finalizeProperties( copyPropertiesToResult(queryProperties, resultTree); - String configType = Resource.Type.Configuration.name(); - if (resultTree.getChild(configType) == null) { - resultTree.addChild(new HashSet<>(), configType); - } + ensureChild(resultTree, Resource.Type.Configuration, "properties"); - String serviceType = Resource.Type.Service.name(); - if (resultTree.getChild(serviceType) == null) { - resultTree.addChild(new HashSet<>(), serviceType); - } - TreeNode> serviceNode = resultTree.getChild(serviceType); - if (serviceNode == null) { - serviceNode = resultTree.addChild(new HashSet<>(), serviceType); - } - String serviceComponentType = Resource.Type.Component.name(); - TreeNode> serviceComponentNode = resultTree.getChild( - serviceType + "/" + serviceComponentType); - if (serviceComponentNode == null) { - serviceComponentNode = serviceNode.addChild(new HashSet<>(), serviceComponentType); - } - serviceComponentNode.getObject().add("ServiceComponentInfo/cluster_name"); - serviceComponentNode.getObject().add("ServiceComponentInfo/service_name"); - serviceComponentNode.getObject().add("ServiceComponentInfo/component_name"); - serviceComponentNode.getObject().add("ServiceComponentInfo/recovery_enabled"); - - String hostType = Resource.Type.Host.name(); - String hostComponentType = Resource.Type.HostComponent.name(); - TreeNode> hostComponentNode = resultTree.getChild( - hostType + "/" + hostComponentType); - - if (hostComponentNode == null) { - TreeNode> hostNode = resultTree.getChild(hostType); - if (hostNode == null) { - hostNode = resultTree.addChild(new HashSet<>(), hostType); - } - hostComponentNode = hostNode.addChild(new HashSet<>(), hostComponentType); - } - resultTree.getChild(configType).getObject().add("properties"); - hostComponentNode.getObject().add("HostRoles/component_name"); + ensureChild(resultTree, Resource.Type.ClusterSetting); + + TreeNode> serviceGroupNode = ensureChild(resultTree, Resource.Type.ServiceGroup); + TreeNode> serviceNode = ensureChild(serviceGroupNode, Resource.Type.Service); + ensureChild(serviceNode, Resource.Type.Component, + "ServiceComponentInfo/cluster_name", + "ServiceComponentInfo/service_name", + "ServiceComponentInfo/component_name", + "ServiceComponentInfo/recovery_enabled"); + + TreeNode> hostNode = ensureChild(resultTree, Resource.Type.Host); + ensureChild(hostNode, Resource.Type.HostComponent, "HostRoles/component_name"); return resultTree; } + private TreeNode> ensureChild(TreeNode> parent, + Resource.Type resourceType, + String... properties) { + TreeNode> child = parent.getChild(resourceType.name()); + if (null == child) { + child = parent.addChild(new HashSet<>(), resourceType.name()); + } + for (String property: properties) { + child.getObject().add(property); + } + return child; + } + + @Override public Result finalizeResult(Result queryResult) { TreeNode resultTree = queryResult.getResultTree(); @@ -198,11 +199,10 @@ private Resource createBlueprintResource(TreeNode clusterNode) { configProcessor.doUpdateForBlueprintExport(); Set stackIds = topology.getStackIds(); - if (stackIds.size() == 1) { - StackId stackId = Iterables.getOnlyElement(stackIds); - blueprintResource.setProperty("Blueprints/stack_name", stackId.getStackName()); - blueprintResource.setProperty("Blueprints/stack_version", stackId.getStackVersion()); - } + // TODO: mpacks should come from service groups once https://github.com/apache/ambari/pull/234 will be committed + Collection> mpackInstances = stackIds.stream(). + map( stackId -> ImmutableMap.of("name", stackId.getStackName(), "version", stackId.getStackVersion())).collect(toList()); + blueprintResource.setProperty(BlueprintResourceProvider.MPACK_INSTANCES_PROPERTY_ID, mpackInstances); if (topology.isClusterKerberosEnabled()) { Map securityConfigMap = new LinkedHashMap<>(); @@ -237,7 +237,7 @@ private Resource createBlueprintResource(TreeNode clusterNode) { /*** * Constructs the Settings object of the following form: * "settings": [ { - "recovery_settings": [ + "cluster_settings": [ { "recovery_enabled": "true" } ] }, @@ -261,6 +261,8 @@ private Resource createBlueprintResource(TreeNode clusterNode) { "recovery_enabled": "true" } ] } ] * + * NOTE: As of 3.0 global recovery settings will move under a new section called cluster_settings. + * * @param clusterNode * @return A Collection> which represents the Setting Object */ @@ -270,25 +272,27 @@ private Collection> getSettings(TreeNode clusterNo //Initialize collections to create appropriate json structure Collection> blueprintSetting = new ArrayList<>(); - Set> recoverySettingValue = new HashSet<>(); Set> serviceSettingValue = new HashSet<>(); Set> componentSettingValue = new HashSet<>(); - HashMap property = new HashMap<>(); - HashMap componentProperty = new HashMap<>(); - Boolean globalRecoveryEnabled = false; - //Fetch the services, to obtain ServiceInfo and ServiceComponents - Collection> serviceChildren = clusterNode.getChild("services").getChildren(); + // TODO: set mpack instance if needed (multi-mpack case) + Collection> serviceChildren = + clusterNode.getChild("servicegroups"). + getChildren().stream().flatMap( + node -> node.getChild("services").getChildren().stream()). + collect(toList()); + + HashMap serviceProperty; for (TreeNode serviceNode : serviceChildren) { ResourceImpl service = (ResourceImpl) serviceNode.getObject(); Map ServiceInfoMap = service.getPropertiesMap().get("ServiceInfo"); //service_settings population - property = new HashMap<>(); + serviceProperty = new HashMap<>(); if (ServiceInfoMap.get("credential_store_enabled").equals("true")) { - property.put("name", ServiceInfoMap.get("service_name").toString()); - property.put("credential_store_enabled", "true"); + serviceProperty.put("name", ServiceInfoMap.get("service_name").toString()); + serviceProperty.put("credential_store_enabled", "true"); } //Fetch the service Components to obtain ServiceComponentInfo @@ -298,34 +302,36 @@ private Collection> getSettings(TreeNode clusterNo Map ServiceComponentInfoMap = component.getPropertiesMap().get("ServiceComponentInfo"); if (ServiceComponentInfoMap.get("recovery_enabled").equals("true")) { - globalRecoveryEnabled = true; - property.put("name", ServiceInfoMap.get("service_name").toString()); - property.put("recovery_enabled", "true"); + serviceProperty.put("name", ServiceInfoMap.get("service_name").toString()); + serviceProperty.put("recovery_enabled", "true"); //component_settings population - componentProperty = new HashMap<>(); + HashMap componentProperty = new HashMap<>(); componentProperty.put("name", ServiceComponentInfoMap.get("component_name").toString()); componentProperty.put("recovery_enabled", "true"); + componentSettingValue.add(componentProperty); } } - if (!property.isEmpty()) - serviceSettingValue.add(property); - if (!componentProperty.isEmpty()) - componentSettingValue.add(componentProperty); + if (!serviceProperty.isEmpty()) + serviceSettingValue.add(serviceProperty); } - //recovery_settings population - property = new HashMap<>(); - if (globalRecoveryEnabled) { - property.put("recovery_enabled", "true"); - } else { - property.put("recovery_enabled", "false"); + + // Add cluster settings + Set> clusterSettings = new HashSet<>(); + TreeNode settingsNode = clusterNode.getChild("settings"); + if (null != settingsNode) { + for (TreeNode clusterSettingNode: settingsNode.getChildren()) { + Map nodeProperties = clusterSettingNode.getObject().getPropertiesMap().get(ClusterSettingResourceProvider.RESPONSE_KEY); + String key = Objects.toString(nodeProperties.get(ClusterSettingResourceProvider.CLUSTER_SETTING_NAME_PROPERTY_ID)); + String value = Objects.toString(nodeProperties.get(ClusterSettingResourceProvider.CLUSTER_SETTING_VALUE_PROPERTY_ID)); + clusterSettings.add(ImmutableMap.of(key, value)); + } } - recoverySettingValue.add(property); //Add all the different setting values. Map settingMap = new HashMap<>(); - settingMap.put("recovery_settings", recoverySettingValue); + settingMap.put("cluster_settings", clusterSettings); blueprintSetting.add(settingMap); settingMap = new HashMap<>(); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java index 936826a4318..af2c11ebd01 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterSettingResourceProvider.java @@ -70,13 +70,16 @@ public class ClusterSettingResourceProvider extends AbstractControllerResourcePr // ----- Property ID constants --------------------------------------------- + public static final String CLUSTER_SETTING_NAME_PROPERTY_ID = "cluster_setting_name"; + public static final String CLUSTER_SETTING_VALUE_PROPERTY_ID = "cluster_setting_value"; + public static final String RESPONSE_KEY = "ClusterSettingInfo"; public static final String ALL_PROPERTIES = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "*"; public static final String CLUSTER_SETTING_CLUSTER_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_id"; public static final String CLUSTER_SETTING_CLUSTER_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_name"; public static final String CLUSTER_SETTING_CLUSTER_SETTING_ID_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_setting_id"; - public static final String CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_setting_name"; - public static final String CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + "cluster_setting_value"; + public static final String CLUSTER_SETTING_CLUSTER_SETTING_NAME_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + CLUSTER_SETTING_NAME_PROPERTY_ID; + public static final String CLUSTER_SETTING_CLUSTER_SETTING_VALUE_PROPERTY_ID = RESPONSE_KEY + PropertyHelper.EXTERNAL_PATH_SEP + CLUSTER_SETTING_VALUE_PROPERTY_ID; private static final Set pkPropertyIds = Sets.newHashSet(new String[]{ diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java index a867d11602d..3aefd42d659 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/MpackResourceProvider.java @@ -159,12 +159,15 @@ public RequestStatus createResourcesAuthorized(final Request request) associatedResources.add(resource); return getRequestStatus(null, associatedResources); } - } catch (IOException e) { - if (e instanceof ConnectException) - throw new SystemException("The Mpack Uri : " + mpackRequest.getMpackUri() + " is not valid. Please try again"); - e.printStackTrace(); - } catch (BodyParseException e1) { - e1.printStackTrace(); + } + catch (ConnectException e) { + throw new SystemException("The Mpack Uri: " + mpackRequest.getMpackUri() + " is not valid. Please try again", e); + } + catch (IOException e) { + throw new SystemException("I/O exception occured during installing mpack: " + mpackRequest.getMpackUri(), e); + } + catch (BodyParseException e) { + throw new SystemException("Invalid mpack registration request", e); } return null; } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java index 0cb0e88b373..0a95ee673b6 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/query/render/ClusterBlueprintRendererTest.java @@ -266,7 +266,23 @@ public TreeNode createResultTreeSettingsObject(TreeNode resu TreeNode clusterTree = resultTree.addChild(clusterResource, "Cluster:1"); - TreeNode servicesTree = clusterTree.addChild(null, "services"); + // Add global recovery_enabled as cluster setting + TreeNode settingsNode = clusterTree.addChild(null, "settings"); + Resource clusterSettingResource = new ResourceImpl(Resource.Type.ClusterSetting); + clusterSettingResource.setProperty("ClusterSettingInfo/cluster_setting_name", "recovery_enabled"); + clusterSettingResource.setProperty("ClusterSettingInfo/cluster_setting_value", "true"); + settingsNode.addChild(clusterSettingResource, "ClusterSetting:1"); + + TreeNode serviceGroupsTree = clusterTree.addChild(null, "servicegroups"); + Resource serviceGroupResource = new ResourceImpl(Resource.Type.ServiceGroup); + serviceGroupResource.setProperty("ServiceGroupInfo/cluster_id", "1"); + serviceGroupResource.setProperty("ServiceGroupInfo/cluster_name", "c1"); + serviceGroupResource.setProperty("ServiceGroupInfo/service_group_id", "1"); + serviceGroupResource.setProperty("ServiceGroupInfo/service_group_name", "core"); + TreeNode serviceGroup1Tree = serviceGroupsTree.addChild(serviceGroupResource, "ServiceGroup:1"); + clusterTree.addChild(serviceGroupsTree); + + TreeNode servicesTree = serviceGroup1Tree.addChild(null, "services"); servicesTree.setProperty("isCollection", "true"); //Scenario 1 : Service with Credential Store enabled, Recovery enabled for Component:1 and not for Component:2 @@ -359,15 +375,15 @@ public void testGetSettings_instance(){ assertTrue(children.containsKey("settings")); List> settingValues = (ArrayList)children.get("settings"); - Boolean isRecoverySettings = false; + Boolean isClusterSettings = false; Boolean isComponentSettings = false; Boolean isServiceSettings = false; //Verify actual values for(Map settingProp : settingValues){ - if(settingProp.containsKey("recovery_settings")){ - isRecoverySettings = true; - HashSet> checkPropSize = (HashSet)settingProp.get("recovery_settings"); + if(settingProp.containsKey("cluster_settings")){ + isClusterSettings = true; + HashSet> checkPropSize = (HashSet)settingProp.get("cluster_settings"); assertEquals(1,checkPropSize.size()); assertEquals("true",checkPropSize.iterator().next().get("recovery_enabled")); @@ -394,7 +410,7 @@ public void testGetSettings_instance(){ } } //Verify if required information is present in actual result - assertTrue(isRecoverySettings); + assertTrue(isClusterSettings); assertTrue(isComponentSettings); assertTrue(isServiceSettings); @@ -436,8 +452,7 @@ public void testFinalizeResult_kerberos() throws Exception{ Resource blueprintResource = blueprintNode.getObject(); Map> properties = blueprintResource.getPropertiesMap(); - assertEquals(STACK_ID.getStackName(), properties.get("Blueprints").get("stack_name")); - assertEquals(STACK_ID.getStackVersion(), properties.get("Blueprints").get("stack_version")); + checkMpackInstance(properties); Map securityProperties = (Map) properties.get("Blueprints").get("security"); assertNotNull(securityProperties); @@ -463,8 +478,7 @@ public void testFinalizeResult() throws Exception{ Resource blueprintResource = blueprintNode.getObject(); Map> properties = blueprintResource.getPropertiesMap(); - assertEquals(STACK_ID.getStackName(), properties.get("Blueprints").get("stack_name")); - assertEquals(STACK_ID.getStackVersion(), properties.get("Blueprints").get("stack_version")); + checkMpackInstance(properties); Collection> host_groups = (Collection>) properties.get("").get("host_groups"); assertEquals(2, host_groups.size()); @@ -542,8 +556,7 @@ public void testFinalizeResultWithAttributes() throws Exception{ Resource blueprintResource = blueprintNode.getObject(); Map> properties = blueprintResource.getPropertiesMap(); - assertEquals(STACK_ID.getStackName(), properties.get("Blueprints").get("stack_name")); - assertEquals(STACK_ID.getStackVersion(), properties.get("Blueprints").get("stack_version")); + checkMpackInstance(properties); Collection> host_groups = (Collection>) properties.get("").get("host_groups"); assertEquals(2, host_groups.size()); @@ -678,9 +691,18 @@ public Map> getPropertiesMap() { TreeNode clusterTree = resultTree.addChild(clusterResource, "Cluster:1"); - // add empty services resource for basic unit testing - Resource servicesResource = new ResourceImpl(Resource.Type.Service); - clusterTree.addChild(servicesResource, "services"); + // add a service group and empty services resource for basic unit testing + TreeNode serviceGroupsTree = clusterTree.addChild(null, "servicegroups"); + Resource serviceGroupResource = new ResourceImpl(Resource.Type.ServiceGroup); + serviceGroupResource.setProperty("ServiceGroupInfo/cluster_id", "1"); + serviceGroupResource.setProperty("ServiceGroupInfo/cluster_name", "c1"); + serviceGroupResource.setProperty("ServiceGroupInfo/service_group_id", "1"); + serviceGroupResource.setProperty("ServiceGroupInfo/service_group_name", "core"); + TreeNode serviceGroup1Tree = serviceGroupsTree.addChild(serviceGroupResource, "ServiceGroup:1"); + clusterTree.addChild(serviceGroupsTree); + + TreeNode servicesTree = serviceGroup1Tree.addChild(null, "services"); + servicesTree.setProperty("isCollection", "true"); Resource configurationsResource = new ResourceImpl(Resource.Type.Configuration); @@ -780,6 +802,13 @@ public Map> getPropertiesMap() { host3ComponentsTree.addChild(ttComponentResource, "HostComponent:2"); } + private void checkMpackInstance(Map> blueprintProperties) { + Map mpackInstanceProperties = + ((List>)blueprintProperties.get("").get("mpack_instances")).get(0); + assertEquals(STACK_ID.getStackName(), mpackInstanceProperties.get("name")); + assertEquals(STACK_ID.getStackVersion(), mpackInstanceProperties.get("version")); + } + private String getLocalHostName() throws UnknownHostException { return InetAddress.getLocalHost().getHostName(); }