소스 검색

AMBARI-15837. FE needs to be able to pass the VDF XML to the API and get the structured JSON format without the server persisting the VD resource in the DB (ncole)

Nate Cole 9 년 전
부모
커밋
81279faedf

+ 7 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/resources/VersionDefinitionResourceDefinition.java

@@ -17,9 +17,11 @@
  */
 package org.apache.ambari.server.api.resources;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 
+import org.apache.ambari.server.controller.internal.VersionDefinitionResourceProvider;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 
@@ -47,4 +49,9 @@ public class VersionDefinitionResourceDefinition extends BaseResourceDefinition
     return Collections.singleton(new SubResourceDefinition(Type.OperatingSystem));
   }
 
+  @Override
+  public Collection<String> getCreateDirectives() {
+    return Collections.singleton(VersionDefinitionResourceProvider.DIRECTIVE_DRY_RUN);
+  }
+
 }

+ 125 - 22
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProvider.java

@@ -33,6 +33,7 @@ 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.resources.RepositoryResourceDefinition;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
 import org.apache.ambari.server.configuration.Configuration;
@@ -48,6 +49,8 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
+import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
+import org.apache.ambari.server.orm.entities.RepositoryEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.StackEntity;
 import org.apache.ambari.server.security.authorization.ResourceType;
@@ -61,6 +64,9 @@ import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.math.NumberUtils;
+import org.codehaus.jackson.node.ArrayNode;
+import org.codehaus.jackson.node.JsonNodeFactory;
+import org.codehaus.jackson.node.ObjectNode;
 
 import com.google.common.collect.Sets;
 import com.google.inject.Inject;
@@ -93,6 +99,8 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
   protected static final String VERSION_DEF_STACK_SERVICES           = "VersionDefinition/stack_services";
   protected static final String SHOW_AVAILABLE                       = "VersionDefinition/show_available";
 
+  public static final String DIRECTIVE_DRY_RUN                       = "dry_run";
+
   public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID  = new OperatingSystemResourceDefinition().getPluralName();
 
   @Inject
@@ -156,9 +164,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     super(PROPERTY_IDS, KEY_PROPERTY_IDS);
 
     setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS));
-
-    setRequiredGetAuthorizations(EnumSet.of(
-        RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS));
+    setRequiredGetAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS));
   }
 
   @Override
@@ -187,9 +193,18 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
           VERSION_DEF_DEFINITION_URL));
     }
 
-    RepositoryVersionEntity entity = createResources(new Command<RepositoryVersionEntity>() {
+    Map<String, String> requestInfo = request.getRequestInfoProperties();
+
+    final boolean dryRun;
+    if (requestInfo.containsKey(DIRECTIVE_DRY_RUN)) {
+      dryRun = Boolean.parseBoolean(requestInfo.get(DIRECTIVE_DRY_RUN));
+    } else {
+      dryRun = false;
+    }
+
+    XmlHolder xmlHolder = createResources(new Command<XmlHolder>() {
       @Override
-      public RepositoryVersionEntity invoke() throws AmbariException {
+      public XmlHolder invoke() throws AmbariException {
 
         String definitionUrl = (String) properties.get(VERSION_DEF_DEFINITION_URL);
         String definitionBase64 = (String) properties.get(VERSION_DEF_DEFINITION_BASE64);
@@ -218,24 +233,49 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
           throw new AmbariException("Cannot determine creation method");
         }
 
+        toRepositoryVersionEntity(holder);
 
-        RepositoryVersionEntity entity = toRepositoryVersionEntity(holder);
-
-        RepositoryVersionResourceProvider.validateRepositoryVersion(s_repoVersionDAO,
-            s_metaInfo.get(), entity);
+        if (!dryRun) {
+          RepositoryVersionResourceProvider.validateRepositoryVersion(s_repoVersionDAO,
+              s_metaInfo.get(), holder.entity);
+        }
 
-        checkForParent(holder, entity);
+        checkForParent(holder);
 
-        s_repoVersionDAO.create(entity);
+        if (!dryRun) {
+          s_repoVersionDAO.create(holder.entity);
+        }
 
-        return entity;
+        return holder;
       }
     });
 
-    notifyCreate(Resource.Type.VersionDefinition, request);
+    final Resource res;
+
+    if (dryRun) {
+      // !!! dry runs imply that the whole entity should be provided.  this is usually
+      // done via sub-resources, but that model breaks down since we don't have a saved
+      // entity yet
+      Set<String> ids = Sets.newHashSet(
+        VERSION_DEF_TYPE_PROPERTY_ID,
+        VERSION_DEF_FULL_VERSION,
+        VERSION_DEF_RELEASE_BUILD,
+        VERSION_DEF_RELEASE_COMPATIBLE_WITH,
+        VERSION_DEF_RELEASE_NOTES,
+        VERSION_DEF_RELEASE_VERSION,
+        VERSION_DEF_AVAILABLE_SERVICES,
+        VERSION_DEF_STACK_SERVICES);
+
+      res = toResource(null, xmlHolder.xml, ids, false);
+
+      addSubresources(res, xmlHolder.entity);
+    } else {
+      res = toResource(xmlHolder.entity, Collections.<String>emptySet());
+      notifyCreate(Resource.Type.VersionDefinition, request);
+    }
 
     RequestStatusImpl status = new RequestStatusImpl(null,
-        Collections.singleton(toResource(entity, Collections.<String>emptySet())));
+        Collections.singleton(res));
 
     return status;
   }
@@ -263,7 +303,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
             Boolean.parseBoolean(propertyMap.get(SHOW_AVAILABLE).toString())) {
 
           for (Entry<String, VersionDefinitionXml> entry : s_metaInfo.get().getVersionDefinitions().entrySet()) {
-            results.add(toResource(entry.getKey(), entry.getValue(), requestPropertyIds));
+            results.add(toResource(entry.getKey(), entry.getValue(), requestPropertyIds, true));
           }
 
         } else {
@@ -283,7 +323,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
                 throw new NoSuchResourceException(String.format("Could not find version %s",
                     id));
               }
-              results.add(toResource(id, xml, requestPropertyIds));
+              results.add(toResource(id, xml, requestPropertyIds, true));
 
             }
           } else {
@@ -319,7 +359,8 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
    * In the case of a patch, check if there is a parent repo.
    * @param entity the entity to check
    */
-  private void checkForParent(XmlHolder holder, RepositoryVersionEntity entity) throws AmbariException {
+  private void checkForParent(XmlHolder holder) throws AmbariException {
+    RepositoryVersionEntity entity = holder.entity;
     if (entity.getType() != RepositoryType.PATCH) {
       return;
     }
@@ -449,7 +490,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
    * @return constructed entity
    * @throws AmbariException if some properties are missing or json has incorrect structure
    */
-  protected RepositoryVersionEntity toRepositoryVersionEntity(XmlHolder holder) throws AmbariException {
+  protected void toRepositoryVersionEntity(XmlHolder holder) throws AmbariException {
 
     // !!! TODO validate parsed object graph
 
@@ -469,14 +510,17 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     entity.setVersionXml(holder.xmlString);
     entity.setVersionXsd(holder.xml.xsdLocation);
 
-    return entity;
+    holder.entity = entity;
   }
 
-  private Resource toResource(String id, VersionDefinitionXml xml, Set<String> requestedIds) throws SystemException {
+  private Resource toResource(String id, VersionDefinitionXml xml, Set<String> requestedIds, boolean fromAvailable) throws SystemException {
 
     Resource resource = new ResourceImpl(Resource.Type.VersionDefinition);
     resource.setProperty(VERSION_DEF_ID, id);
-    resource.setProperty(SHOW_AVAILABLE, Boolean.TRUE);
+    if (fromAvailable) {
+      resource.setProperty(SHOW_AVAILABLE, Boolean.TRUE);
+    }
+
     StackId stackId = new StackId(xml.release.stackId);
 
     // !!! these are needed for href
@@ -501,7 +545,6 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     setResourceProperty(resource, VERSION_DEF_STACK_SERVICES, xml.getStackServices(stack), requestedIds);
 
     return resource;
-
   }
 
   /**
@@ -560,6 +603,65 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     return resource;
   }
 
+  /**
+   * Provide the dry-run entity with fake sub-resources.  These are not queryable by normal API.
+   */
+  private void addSubresources(Resource res, RepositoryVersionEntity entity) {
+    JsonNodeFactory factory = JsonNodeFactory.instance;
+
+    ArrayNode subs = factory.arrayNode();
+
+    for (OperatingSystemEntity os : entity.getOperatingSystems()) {
+      ObjectNode osBase = factory.objectNode();
+
+      ObjectNode osElement = factory.objectNode();
+      osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS),
+          os.isAmbariManagedRepos());
+      osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_OS_TYPE_PROPERTY_ID),
+          os.getOsType());
+
+      osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_STACK_NAME_PROPERTY_ID),
+          entity.getStackName());
+      osElement.put(PropertyHelper.getPropertyName(OperatingSystemResourceProvider.OPERATING_SYSTEM_STACK_VERSION_PROPERTY_ID),
+          entity.getStackVersion());
+
+      osBase.put(PropertyHelper.getPropertyCategory(OperatingSystemResourceProvider.OPERATING_SYSTEM_AMBARI_MANAGED_REPOS),
+          osElement);
+
+      ArrayNode reposArray = factory.arrayNode();
+      for (RepositoryEntity repo : os.getRepositories()) {
+        ObjectNode repoBase = factory.objectNode();
+
+        ObjectNode repoElement = factory.objectNode();
+
+        repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID),
+            repo.getBaseUrl());
+        repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_OS_TYPE_PROPERTY_ID),
+            os.getOsType());
+        repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_REPO_ID_PROPERTY_ID),
+            repo.getRepositoryId());
+        repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_REPO_NAME_PROPERTY_ID),
+            repo.getName());
+        repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_STACK_NAME_PROPERTY_ID),
+            entity.getStackName());
+        repoElement.put(PropertyHelper.getPropertyName(RepositoryResourceProvider.REPOSITORY_STACK_VERSION_PROPERTY_ID),
+            entity.getStackVersion());
+
+        repoBase.put(PropertyHelper.getPropertyCategory(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID),
+            repoElement);
+
+        reposArray.add(repoBase);
+      }
+
+      osBase.put(new RepositoryResourceDefinition().getPluralName(), reposArray);
+
+      subs.add(osBase);
+    }
+
+    res.setProperty(new OperatingSystemResourceDefinition().getPluralName(), subs);
+  }
+
+
   /**
    * Convenience class to hold the xml String representation, the url, and the parsed object.
    */
@@ -567,6 +669,7 @@ public class VersionDefinitionResourceProvider extends AbstractAuthorizedResourc
     String url = null;
     String xmlString = null;
     VersionDefinitionXml xml = null;
+    RepositoryVersionEntity entity = null;
   }
 
 

+ 34 - 0
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/VersionDefinitionResourceProviderTest.java

@@ -311,4 +311,38 @@ public class VersionDefinitionResourceProviderTest {
     Assert.assertEquals(1, results.size());
   }
 
+  @Test
+  public void testCreateDryRun() throws Exception {
+    Authentication authentication = TestAuthenticationFactory.createAdministrator();
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    File file = new File("src/test/resources/version_definition_resource_provider.xml");
+
+    final ResourceProvider versionProvider = new VersionDefinitionResourceProvider();
+    final ResourceProvider provider = injector.getInstance(ResourceProviderFactory.class)
+        .getRepositoryVersionResourceProvider();
+
+    final Set<Map<String, Object>> propertySet = new LinkedHashSet<Map<String, Object>>();
+    final Map<String, Object> properties = new LinkedHashMap<String, Object>();
+    properties.put(VersionDefinitionResourceProvider.VERSION_DEF_DEFINITION_URL,
+        file.toURI().toURL().toString());
+    propertySet.add(properties);
+
+    Map<String, String> info = Collections.singletonMap(VersionDefinitionResourceProvider.DIRECTIVE_DRY_RUN, "true");
+
+    final Request createRequest = PropertyHelper.getCreateRequest(propertySet, info);
+    RequestStatus status = versionProvider.createResources(createRequest);
+    Assert.assertEquals(1, status.getAssociatedResources().size());
+
+    Resource res = status.getAssociatedResources().iterator().next();
+    System.out.println(res.getPropertiesMap().keySet());
+    // because we aren't using subresources, but return subresource-like properties, the key is an empty string
+    Assert.assertTrue(res.getPropertiesMap().containsKey(""));
+    Map<String, Object> resMap = res.getPropertiesMap().get("");
+    Assert.assertTrue(resMap.containsKey("operating_systems"));
+
+    Request getRequest = PropertyHelper.getReadRequest("VersionDefinition");
+    Set<Resource> results = versionProvider.getResources(getRequest, null);
+    Assert.assertEquals(0, results.size());
+  }
 }