You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by be...@apache.org on 2018/05/08 18:47:09 UTC

[ambari] branch branch-feature-AMBARI-14714 updated: AMBARI-23575 - Download mpacks during blueprint luster provisioning (benyoka) (#1209)

This is an automated email from the ASF dual-hosted git repository.

benyoka pushed a commit to branch branch-feature-AMBARI-14714
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/branch-feature-AMBARI-14714 by this push:
     new 3782e18  AMBARI-23575 - Download mpacks during blueprint luster provisioning (benyoka) (#1209)
3782e18 is described below

commit 3782e18bdd5cbf72a61e57fe2f8ab662bb56e9ff
Author: benyoka <be...@users.noreply.github.com>
AuthorDate: Tue May 8 20:47:04 2018 +0200

    AMBARI-23575 - Download mpacks during blueprint luster provisioning (benyoka) (#1209)
    
    * AMBARI-23575 download mpacks during custer provisioning (benyoka)
    
    * AMBARI-23575 add javadoc (benyoka)
    
    * AMBARI-23575 unit test for DownloadMpackTask (benyoka)
    
    * AMBARI-23575 fix TopologyManager unit tests WIP (benyoka)
    
    * AMBARI-23575 fix TopologyManagerTest
    
    * AMBARI-23575 add new topology manager test (benyoka)
    
    * AMBARI-23575 small improvements (benyoka)
    
    * AMBARI-23575 remove static dependencies from DownloadMpackTask (benyoka)
---
 .../ambari/server/controller/MpackRequest.java     |   3 +-
 .../internal/ProvisionClusterRequest.java          |  11 ++
 .../ambari/server/topology/DownloadMpacksTask.java | 111 +++++++++++++++++
 .../ambari/server/topology/TopologyManager.java    |   9 +-
 .../server/topology/DownloadMpacksTaskTest.java    | 138 +++++++++++++++++++++
 .../server/topology/TopologyManagerTest.java       | 105 ++++++++++++----
 6 files changed, 351 insertions(+), 26 deletions(-)

diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/MpackRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/MpackRequest.java
index 49d0caa..efabc51 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/MpackRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/MpackRequest.java
@@ -81,8 +81,7 @@ public class MpackRequest {
 
   @Override
   public int hashCode() {
-    int result = 1;
-    result = 31 + getId().hashCode();
+    int result = 31 + (null != getId() ? getId().hashCode() : 0);
     return result;
   }
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
index 1bca924..3b3700e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ProvisionClusterRequest.java
@@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Enums;
 import com.google.common.base.Optional;
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Request for provisioning a cluster.
@@ -501,6 +502,16 @@ public class ProvisionClusterRequest extends BaseClusterRequest implements Provi
     return mpackInstances;
   }
 
+  /**
+   * @return a set containing the mpacks in the provision request and the blueprint combined.
+   */
+  public Set<MpackInstance> getAllMpacks() {
+    return ImmutableSet.<MpackInstance>builder().
+      addAll(mpackInstances).
+      addAll(blueprint.getMpacks()).
+      build();
+  }
+
   @Override
   public TopologyRequestEntity toEntity() {
     TopologyRequestEntity entity = super.toEntity();
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/DownloadMpacksTask.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/DownloadMpacksTask.java
new file mode 100644
index 0000000..2216936
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/DownloadMpacksTask.java
@@ -0,0 +1,111 @@
+/*
+ * 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.topology;
+
+import static java.util.stream.Collectors.toList;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.ambari.server.StackAccessException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.internal.MpackResourceProvider;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Downloads (registers) missing (declared by the blueprint or the cluster template but not present) management packs
+ * during cluster creation.
+ */
+public class DownloadMpacksTask {
+  private static final Logger LOG = LoggerFactory.getLogger(DownloadMpacksTask.class);
+
+  private MpackResourceProvider mpackResourceProvider;
+  private AmbariMetaInfo ambariMetaInfo;
+
+  public DownloadMpacksTask(MpackResourceProvider mpackResourceProvider, AmbariMetaInfo ambariMetaInfo) {
+    this.mpackResourceProvider = mpackResourceProvider;
+    this.ambariMetaInfo = ambariMetaInfo;
+  }
+
+  /**
+   * Registers/downloads all required management packs
+   * @param mpackInstances management pack instances declared in the blueprint and/or the cluster creation template
+   */
+  public void downloadMissingMpacks(Collection<MpackInstance> mpackInstances) {
+    List<MpackInstance> missingMpacks = mpackInstances.stream().
+      filter(this::isStackMissing).
+      collect(toList());
+
+    for (MpackInstance mpack: missingMpacks) {
+      Preconditions.checkArgument(null != mpack.getUrl(), "Cannot register missing mpack with undefined uri: %s",
+        mpack.getStackId());
+      LOG.info("Registering mpack {}", mpack.getStackId());
+      Request mpackRequest = createRequest(mpack.getUrl());
+      try {
+        RequestStatus.Status status = mpackResourceProvider.createResources(mpackRequest).getStatus();
+        if (!RequestStatus.Status.Complete.equals(status)) {
+          throw new RuntimeException("An error occured while registering mpack. Request status: " + status);
+        }
+      }
+      catch (Exception ex) {
+        throw ex instanceof RuntimeException ?
+          (RuntimeException)ex :
+          new RuntimeException("Error occured while registering mpack: " + mpack.getStackId(), ex);
+      }
+    }
+  }
+
+  /**
+   * @param mpackUri the uri of the mpack
+   * @return the Request to send to {@link MpackResourceProvider} to to register the mpack
+   */
+  private Request createRequest(String mpackUri) {
+    return PropertyHelper.getCreateRequest(
+      ImmutableSet.of(
+        ImmutableMap.of(
+          MpackResourceProvider.MPACK_URI, mpackUri)),
+      ImmutableMap.of()
+    );
+  }
+
+  /**
+   *
+   * @param mpackInstance the mpack to check
+   * @return {@code true} if the mpack is not registered, {@code false} if already registered.
+   */
+  boolean isStackMissing(MpackInstance mpackInstance) {
+    try {
+      ambariMetaInfo.getStack(mpackInstance.getStackId());
+      return false;
+    }
+    catch (StackAccessException ex) {
+      LOG.debug("Stack {} is not available.", mpackInstance.getStackId());
+      return true;
+    }
+  }
+
+}
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java
index 81329e5..634595e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/topology/TopologyManager.java
@@ -48,6 +48,7 @@ import org.apache.ambari.server.controller.internal.ArtifactResourceProvider;
 import org.apache.ambari.server.controller.internal.BaseClusterRequest;
 import org.apache.ambari.server.controller.internal.CalculatedStatus;
 import org.apache.ambari.server.controller.internal.CredentialResourceProvider;
+import org.apache.ambari.server.controller.internal.MpackResourceProvider;
 import org.apache.ambari.server.controller.internal.ProvisionClusterRequest;
 import org.apache.ambari.server.controller.internal.RequestImpl;
 import org.apache.ambari.server.controller.internal.ScaleClusterRequest;
@@ -101,7 +102,6 @@ public class TopologyManager {
   public static final String INITIAL_CONFIG_TAG = "INITIAL";
   public static final String TOPOLOGY_RESOLVED_TAG = "TOPOLOGY_RESOLVED";
   public static final String KDC_ADMIN_CREDENTIAL = "kdc.admin.credential";
-  public static final String RAW_REQUEST_BODY_ARTIFACT_NAME = "raw_provision_cluster_template";
 
   private PersistedState persistedState;
 
@@ -282,6 +282,11 @@ public class TopologyManager {
                                                String rawRequestBody) throws InvalidTopologyException, AmbariException {
     ensureInitialized();
 
+    MpackResourceProvider mpackResourceProvider = (MpackResourceProvider)
+      AmbariContext.getClusterController().ensureResourceProvider(Resource.Type.Mpack);
+    new DownloadMpacksTask(mpackResourceProvider, AmbariServer.getController().getAmbariMetaInfo()).
+      downloadMissingMpacks(request.getAllMpacks());
+
     BlueprintBasedClusterProvisionRequest provisionRequest = new BlueprintBasedClusterProvisionRequest(ambariContext, securityConfigurationFactory, request.getBlueprint(), request);
     Map<String, Set<ResolvedComponent>> resolved = resolver.resolveComponents(provisionRequest);
 
@@ -897,6 +902,8 @@ public class TopologyManager {
     }
   }
 
+
+
   @Transactional
   protected LogicalRequest createLogicalRequest(final PersistedTopologyRequest request, ClusterTopology topology, Long requestId)
       throws AmbariException {
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/DownloadMpacksTaskTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/DownloadMpacksTaskTest.java
new file mode 100644
index 0000000..8a27be5
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/DownloadMpacksTaskTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.topology;
+
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.mock;
+import static org.easymock.EasyMock.newCapture;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.server.StackAccessException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.internal.MpackResourceProvider;
+import org.apache.ambari.server.controller.internal.RequestStatusImpl;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.state.StackId;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class DownloadMpacksTaskTest {
+
+  private static final List<MpackInstance> INSTALLED_MPACKS = ImmutableList.of(
+    mpack("HDPCORE", "1.0.0.0"),
+    mpack("HDF", "3.1.1.0"));
+
+  private static final List<MpackInstance> MISSING_MPACKS = ImmutableList.of(
+    mpack("EDW", "1.0.0"),
+    mpack("HDP", "2.6.0"));
+
+  private AmbariMetaInfo metaInfo;
+  private MpackResourceProvider resourceProvider;
+  private DownloadMpacksTask downloadMpacksTask;
+  private Capture<Request> downloadRequests;
+
+  @Before
+  public void setup() throws Exception {
+    metaInfo = mock(AmbariMetaInfo.class);
+    for (MpackInstance mpackInstance: INSTALLED_MPACKS) {
+      expect(metaInfo.getStack(mpackInstance.getStackId())).andReturn(null).anyTimes();
+    }
+    expect(metaInfo.getStack(anyObject(StackId.class))).
+      andThrow(new StackAccessException("The specified stack is not found.")).anyTimes();
+
+    resourceProvider = mock(MpackResourceProvider.class);
+    downloadRequests = newCapture(CaptureType.ALL);
+    expect(resourceProvider.createResources(capture(downloadRequests))).
+      andReturn(new RequestStatusImpl(null, null, null)).anyTimes();
+    downloadMpacksTask = new DownloadMpacksTask(resourceProvider, metaInfo);
+
+    replay(metaInfo, resourceProvider);
+  }
+
+  @Test
+  public void testIsStackMissing() {
+    INSTALLED_MPACKS.forEach(stackId -> assertFalse(downloadMpacksTask.isStackMissing(stackId)) );
+    MISSING_MPACKS.forEach(stackId -> assertTrue(downloadMpacksTask.isStackMissing(stackId)) );
+  }
+
+  @Test
+  public void testDownloadMissingMpacks() {
+    // given
+    List<MpackInstance> mpacks = concat(INSTALLED_MPACKS.stream(), MISSING_MPACKS.stream()).collect(toList());
+
+    // when
+    downloadMpacksTask.downloadMissingMpacks(mpacks);
+
+    // then
+    Set<String> missingMpackUris = MISSING_MPACKS.stream().
+      map(MpackInstance::getUrl).
+      collect(toSet());
+
+    Set<String> dowloadedMpackUris = downloadRequests.getValues().stream().
+      map(this::getUriFromRequest).
+      collect(toSet());
+
+    assertEquals(missingMpackUris, dowloadedMpackUris);
+
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testDownloadMissingMpacks_undefinedUri() {
+    // given
+    MpackInstance brokenMpack = mpack("HDP", "2.6");
+    brokenMpack.setUrl(null);
+
+    // when
+    downloadMpacksTask.downloadMissingMpacks(ImmutableList.of(brokenMpack));
+  }
+
+
+  private String getUriFromRequest(Request request) {
+    return (String)request.getProperties().iterator().next().get(MpackResourceProvider.MPACK_URI);
+  }
+
+  private static MpackInstance mpack(String stackName, String stackVersion) {
+    MpackInstance mpack = new MpackInstance();
+    mpack.setMpackName(stackName);
+    mpack.setMpackVersion(stackVersion);
+    mpack.setUrl(createUri(stackName, stackVersion));
+    return mpack;
+  }
+
+  private static String createUri(String stackName, String stackVersion) {
+    return "http://mpacks.org/" + stackName + "." + stackVersion;
+  }
+
+}
\ No newline at end of file
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java
index 297c321..39799de 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/topology/TopologyManagerTest.java
@@ -22,17 +22,19 @@ import static java.util.stream.Collectors.toSet;
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.anyString;
 import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.createNiceMock;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.getCurrentArguments;
 import static org.easymock.EasyMock.isA;
 import static org.easymock.EasyMock.newCapture;
 import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.reset;
 import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
 import static org.powermock.api.easymock.PowerMock.mockStatic;
 
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -48,16 +50,23 @@ import java.util.concurrent.Future;
 import java.util.stream.Stream;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.ClusterRequest;
 import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.ShortTaskStatus;
 import org.apache.ambari.server.controller.internal.HostResourceProvider;
+import org.apache.ambari.server.controller.internal.MpackResourceProvider;
 import org.apache.ambari.server.controller.internal.ProvisionClusterRequest;
+import org.apache.ambari.server.controller.internal.RequestStatusImpl;
 import org.apache.ambari.server.controller.internal.ScaleClusterRequest;
 import org.apache.ambari.server.controller.internal.Stack;
 import org.apache.ambari.server.controller.spi.ClusterController;
+import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.events.RequestFinishedEvent;
@@ -71,7 +80,6 @@ import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.quicklinksprofile.QuickLinksProfile;
 import org.apache.ambari.server.topology.tasks.ConfigureClusterTask;
 import org.apache.ambari.server.topology.tasks.ConfigureClusterTaskFactory;
-import org.apache.ambari.server.topology.validators.TopologyValidator;
 import org.apache.ambari.server.topology.validators.TopologyValidatorService;
 import org.easymock.Capture;
 import org.easymock.EasyMock;
@@ -89,6 +97,7 @@ import org.junit.runner.RunWith;
 import org.powermock.api.easymock.PowerMock;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -97,7 +106,7 @@ import com.google.common.collect.ImmutableSet;
  * TopologyManager unit tests
  */
 @RunWith(PowerMockRunner.class)
-@PrepareForTest( { TopologyManager.class })
+@PrepareForTest({TopologyManager.class, AmbariServer.class, AmbariContext.class})
 public class TopologyManagerTest {
 
   private static final String CLUSTER_NAME = "test-cluster";
@@ -163,6 +172,8 @@ public class TopologyManagerTest {
   @Mock(type = MockType.STRICT)
   private ResourceProvider resourceProvider;
   @Mock(type = MockType.STRICT)
+  private MpackResourceProvider mpackResourceProvider;
+  @Mock(type = MockType.STRICT)
   private SettingDAO settingDAO;
   @Mock(type = MockType.NICE)
   private ClusterTopology clusterTopologyMock;
@@ -170,6 +181,10 @@ public class TopologyManagerTest {
   private ConfigureClusterTaskFactory configureClusterTaskFactory;
   @Mock(type = MockType.NICE)
   private ConfigureClusterTask configureClusterTask;
+  @Mock
+  private AmbariManagementController controller;
+  @Mock
+  private AmbariMetaInfo metaInfo;
 
   @Mock(type = MockType.STRICT)
   private Future mockFuture;
@@ -205,13 +220,14 @@ public class TopologyManagerTest {
   private final Collection<Component> group2Components = Arrays.asList(new Component("component3"), new Component("component4"));
   private final Collection<String> group2ComponentNames = group2Components.stream().map(Component::getName).collect(toSet());
 
+  private final MpackInstance mpack1 = new MpackInstance("HDPCORE", "1.0.0.0", "http://mpacks.org/hdpcore", null, new Configuration());
+  private final MpackInstance mpack2 = new MpackInstance("HDF", "3.3.0", "http://mpacks.org/hdf", null, new Configuration());
+
   private Map<String, Collection<String>> group1ServiceComponents = new HashMap<>();
   private Map<String, Collection<String>> group2ServiceComponents = new HashMap<>();
 
   private String predicate = "Hosts/host_name=foo";
 
-  private List<TopologyValidator> topologyValidators = new ArrayList<>();
-
   private Capture<ClusterTopology> clusterTopologyCapture;
   private Capture<Map<String, Object>> configRequestPropertiesCapture;
   private Capture<Map<String, Object>> configRequestPropertiesCapture2;
@@ -219,6 +235,8 @@ public class TopologyManagerTest {
   private Capture<ClusterRequest> updateClusterConfigRequestCapture;
   private Capture<Runnable> updateConfigTaskCapture;
 
+  private final Set<String> installedMpacks = new HashSet<>();
+
   @Before
   public void setup() throws Exception {
     expect(configuration.getParallelTopologyTaskCreationThreadPoolSize()).andReturn(1).anyTimes();
@@ -320,6 +338,7 @@ public class TopologyManagerTest {
     expect(request.getSecurityConfiguration()).andReturn(null).anyTimes();
     expect(request.getStackIds()).andReturn(ImmutableSet.of()).anyTimes();
     expect(request.getMpacks()).andReturn(ImmutableSet.of()).anyTimes();
+    expect(request.getAllMpacks()).andReturn(ImmutableSet.of(mpack1, mpack2)).anyTimes();
 
     expect(componentResolver.resolveComponents(anyObject())).andReturn(ImmutableMap.of()).anyTimes();
 
@@ -368,6 +387,8 @@ public class TopologyManagerTest {
     ambariContext.persistInstallStateForUI(CLUSTER_NAME, STACK_ID);
     expectLastCall().anyTimes();
 
+    expect(clusterController.ensureResourceProvider(Resource.Type.Mpack)).andReturn(mpackResourceProvider).anyTimes();
+    expect(resourceProvider.createResources((anyObject()))).andReturn(new RequestStatusImpl(null, null, null)).anyTimes(); // persist raw request
     expect(clusterController.ensureResourceProvider(anyObject(Resource.Type.class))).andReturn(resourceProvider);
 
     expect(configureClusterTaskFactory.createConfigureClusterTask(anyObject(), anyObject(), anyObject())).andReturn(configureClusterTask);
@@ -379,20 +400,31 @@ public class TopologyManagerTest {
     persistedState.persistLogicalRequest(logicalRequest, 1);
     expectLastCall().anyTimes();
 
-    Class clazz = TopologyManager.class;
-
-    Field f = clazz.getDeclaredField("executor");
-    f.setAccessible(true);
-    f.set(topologyManager, executor);
-
+    installedMpacks.clear();
+    installedMpacks.add("HDPCORE");
+    installedMpacks.add("HDF");
+    expect(metaInfo.getStack(anyObject())).
+      andAnswer(() -> {
+        if (!installedMpacks.contains(((StackId) getCurrentArguments()[0]).getStackName())) {
+          throw new StackAccessException(null);
+        }
+        return null;
+      }).
+      anyTimes();
+    expect(controller.getAmbariMetaInfo()).andReturn(metaInfo).anyTimes();
+    mockStatic(AmbariServer.class);
+    expect(AmbariServer.getController()).andReturn(controller).anyTimes();
+    PowerMock.replay(AmbariServer.class);
+
+    mockStatic(AmbariContext.class);
+    expect(AmbariContext.getClusterController()).andReturn(clusterController).anyTimes();
+    PowerMock.replay(AmbariContext.class);
+
+    Whitebox.setInternalState(topologyManager, "executor", executor);
     EasyMockSupport.injectMocks(topologyManager);
 
-    Field f2 = clazz.getDeclaredField("executor");
-    f2.setAccessible(true);
-    f2.set(topologyManagerReplay, executor);
-
+    Whitebox.setInternalState(topologyManagerReplay, "executor", executor);
     EasyMockSupport.injectMocks(topologyManagerReplay);
-
   }
 
   @After
@@ -400,12 +432,14 @@ public class TopologyManagerTest {
     PowerMock.verify(System.class);
     verify(blueprint, stack, request, group1, group2, ambariContext, logicalRequestFactory, componentResolver,
         logicalRequest, configurationRequest, configurationRequest2, configurationRequest3,
-        requestStatusResponse, executor, persistedState, clusterTopologyMock, mockFuture, settingDAO);
+        requestStatusResponse, executor, persistedState, clusterTopologyMock, mockFuture, settingDAO,
+        resourceProvider, mpackResourceProvider);
 
-    PowerMock.reset(System.class);
+    PowerMock.reset(System.class, AmbariServer.class, AmbariContext.class);
     reset(blueprint, stack, request, group1, group2, ambariContext, logicalRequestFactory, componentResolver,
         logicalRequest, configurationRequest, configurationRequest2, configurationRequest3,
-        requestStatusResponse, executor, persistedState, clusterTopologyMock, mockFuture, settingDAO);
+        requestStatusResponse, executor, persistedState, clusterTopologyMock, mockFuture, settingDAO,
+        resourceProvider, mpackResourceProvider, metaInfo, controller);
   }
 
   @Test
@@ -418,6 +452,28 @@ public class TopologyManagerTest {
   }
 
   @Test
+  public void testProvisionCluster_downloadMissingMpack() throws Exception {
+    // given
+    expect(persistedState.getAllRequests()).andReturn(Collections.emptyMap()).anyTimes();
+
+    installedMpacks.remove("HDF");
+
+    reset(mpackResourceProvider);
+    Capture<Request> mpackRequestCapture = Capture.newInstance();
+    expect(mpackResourceProvider.createResources(capture(mpackRequestCapture))).
+      andReturn(new RequestStatusImpl(null, null, null)).once();
+    replayAll();
+
+    // when
+    topologyManager.provisionCluster(request, "{}");
+
+    // then
+    assertEquals("http://mpacks.org/hdf",
+      mpackRequestCapture.getValue().getProperties().iterator().next().get(MpackResourceProvider.MPACK_URI));
+  }
+
+
+  @Test
   public void testAddKerberosClientAtTopologyInit() throws Exception {
     Map<ClusterTopology, List<LogicalRequest>> allRequests = new HashMap<>();
     List<LogicalRequest> requestList = new ArrayList<>();
@@ -536,7 +592,7 @@ public class TopologyManagerTest {
     Map<ClusterTopology,List<LogicalRequest>> allRequests = new HashMap<>();
     List<LogicalRequest> logicalRequests = new ArrayList<>();
     logicalRequests.add(logicalRequest);
-    ClusterTopology clusterTopologyMock = EasyMock.createNiceMock(ClusterTopology.class);
+    ClusterTopology clusterTopologyMock = createNiceMock(ClusterTopology.class);
     expect(clusterTopologyMock.getClusterId()).andReturn(CLUSTER_ID).anyTimes();
 
     expect(ambariContext.isTopologyResolved(EasyMock.anyLong())).andReturn(true).anyTimes();
@@ -562,8 +618,8 @@ public class TopologyManagerTest {
     replay(blueprint, stack, request, group1, group2, ambariContext, logicalRequestFactory, componentResolver,
             configurationRequest, configurationRequest2, configurationRequest3, executor,
             persistedState, clusterTopologyMock, securityConfigurationFactory, credentialStoreService,
-            clusterController, resourceProvider, mockFuture, requestStatusResponse, logicalRequest, settingDAO,
-            configureClusterTaskFactory, configureClusterTask);
+            clusterController, resourceProvider, mpackResourceProvider, mockFuture, requestStatusResponse,
+            logicalRequest, settingDAO, configureClusterTaskFactory, configureClusterTask, metaInfo, controller);
   }
 
   @Test(expected = InvalidTopologyException.class)
@@ -575,7 +631,7 @@ public class TopologyManagerTest {
     properties.put(HostResourceProvider.HOST_CLUSTER_NAME_PROPERTY_ID, CLUSTER_NAME);
     properties.put(HostResourceProvider.BLUEPRINT_PROPERTY_ID, BLUEPRINT_NAME);
     propertySet.add(properties);
-    BlueprintFactory bpfMock = EasyMock.createNiceMock(BlueprintFactory.class);
+    BlueprintFactory bpfMock = createNiceMock(BlueprintFactory.class);
     EasyMock.expect(bpfMock.getBlueprint(BLUEPRINT_NAME)).andReturn(blueprint).anyTimes();
     ScaleClusterRequest.init(bpfMock);
     replay(bpfMock);
@@ -603,8 +659,10 @@ public class TopologyManagerTest {
     PowerMock.replay(System.class);
     final SettingEntity quickLinksProfile = createQuickLinksSettingEntity(SAMPLE_QUICKLINKS_PROFILE_1, timeStamp);
     settingDAO.create(eq(quickLinksProfile));
+    expectLastCall();
 
     replayAll();
+    PowerMock.replayAll();
 
     topologyManager.provisionCluster(request, "{}");
   }
@@ -630,6 +688,7 @@ public class TopologyManagerTest {
     expect(settingDAO.merge(newProfile)).andReturn(newProfile);
 
     replayAll();
+    PowerMock.replayAll();
 
     topologyManager.provisionCluster(request, "{}");
   }

-- 
To stop receiving notification emails like this one, please contact
benyoka@apache.org.