Forráskód Böngészése

AMBARI-2420. Add the ability to set base_url for a repository (ncole).

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1494278 13f79535-47bb-0310-9956-ffa450edef68
Nate Cole 12 éve
szülő
commit
f4f27333b8

+ 145 - 40
ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java

@@ -18,28 +18,49 @@
 
 package org.apache.ambari.server.api.services;
 
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.StackAccessException;
 import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.resources.ResourceManager;
-import org.apache.ambari.server.state.*;
+import org.apache.ambari.server.state.ComponentInfo;
+import org.apache.ambari.server.state.OperatingSystemInfo;
+import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.state.RepositoryInfo;
+import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.Stack;
+import org.apache.ambari.server.state.StackInfo;
+import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.util.*;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
 
 /**
  * ServiceInfo responsible getting information about cluster.
@@ -249,6 +270,117 @@ public class AmbariMetaInfo {
           + ", repoId= " + repoId);
     return repoResult;
   }
+  
+  public synchronized void updateRepository(String stackName, String stackVersion,
+      String osType, String repoId, String baseUrl) throws AmbariException {
+    
+    // validate existing
+    RepositoryInfo ri = getRepository(stackName, stackVersion, osType, repoId);
+    
+    if (!stackRoot.exists())
+      throw new StackAccessException("Stack root does not exist.");
+    
+    String repoFileName = stackRoot.getAbsolutePath() + File.separator +
+        stackName + File.separator + stackVersion + File.separator +
+        REPOSITORY_FOLDER_NAME + File.separator + REPOSITORY_FILE_NAME;
+    
+    File repoFile = new File(repoFileName);
+    if (!repoFile.exists())
+      throw new StackAccessException("Stack repo file does not exist.");
+    
+    try {
+      // backup
+      File newFile = new File(repoFileName + "." + System.currentTimeMillis());
+      FileUtils.copyFile(repoFile, newFile, false);
+
+      // read/update/persist
+      DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+      DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+      Document doc = dBuilder.parse(repoFile);
+      
+      NodeList osNodes = doc.getElementsByTagName(REPOSITORY_XML_MAIN_BLOCK_NAME);
+
+      List<Node> newOsNodes = new ArrayList<Node>();
+      
+      for (int i = 0; i < osNodes.getLength(); i++) {
+        Node osNode = osNodes.item(i);
+        if (osNode.getNodeType() != Node.ELEMENT_NODE) {
+          continue;
+        }
+        
+        NamedNodeMap attrs = osNode.getAttributes();
+        Node osAttr = attrs.getNamedItem(REPOSITORY_XML_ATTRIBUTE_OS_TYPE);
+        if (osAttr == null) {
+          continue;
+        }
+        
+        String xmlOsValue = osAttr.getNodeValue();
+        
+        if (-1 == xmlOsValue.indexOf(osType)) {
+          continue;
+        }
+        
+        Node template = osNode.cloneNode(true);
+        
+        // many os'es can be defined
+        String[] allOsTypes = osAttr.getNodeValue().split(",");
+        
+        for (String xmlOsType : allOsTypes) {
+          Node newOsNode = template.cloneNode(true);
+          NamedNodeMap newAttrs = newOsNode.getAttributes();
+          Node newOsAttr = newAttrs.getNamedItem(REPOSITORY_XML_ATTRIBUTE_OS_TYPE);
+          newOsAttr.setTextContent(xmlOsType);
+
+          if (xmlOsType.equals(osType)) {
+            NodeList newOsNodeChildren = newOsNode.getChildNodes();
+            
+            for (int j = 0; j < newOsNodeChildren.getLength(); j++) {
+              Node repoNode = newOsNodeChildren.item(j);
+              if (repoNode.getNodeName().equals(REPOSITORY_XML_REPO_BLOCK_NAME)) {
+
+                Element property = (Element) repoNode;
+                String xmlRepoId = getTagValue(REPOSITORY_XML_PROPERTY_REPOID, property);
+                
+                if (xmlRepoId.equals(repoId)) {
+                  NodeList nl = property.getElementsByTagName(REPOSITORY_XML_PROPERTY_BASEURL);
+                  for (int k = 0; k < nl.getLength(); k++) {
+                    nl.item(k).setTextContent(baseUrl);
+                  }
+                }
+              }
+            }
+            doc.getDocumentElement().replaceChild(newOsNode, osNode);
+          } else {
+            newOsNodes.add(newOsNode);
+          }
+        }
+      }
+      
+      for (Node n : newOsNodes) {
+        doc.getDocumentElement().appendChild(n);
+      }
+
+      TransformerFactory tf = TransformerFactory.newInstance();
+      Transformer t = tf.newTransformer();
+      t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+      t.setOutputProperty(OutputKeys.METHOD, "xml");
+      t.setOutputProperty(OutputKeys.INDENT, "yes");
+      t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+      t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",  "2");
+      doc.setXmlStandalone(true);
+      
+      t.transform(new DOMSource(doc), new StreamResult(repoFile));      
+    }
+    catch (Exception e) {
+      throw new AmbariException (e.getMessage(), e);
+    }
+    
+    // modify existing definition currently in-memory (must be valid to get here)
+    if (null != ri) {
+      ri.setBaseUrl(baseUrl);
+    }
+    
+  }
 
   /*
    * function for given a stack name and version, is it a supported stack
@@ -914,34 +1046,6 @@ public class AmbariMetaInfo {
     return result;
   }
 
-  //TODO: Method is unused as of now
-/*  public boolean areOsTypesCompatible(String type1, String type2) {
-    if (type1 == null || type2 == null) {
-      return false;
-    }
-    if (type1.equals(type2)) {
-      return true;
-    }
-    if (type1.equals("redhat5") || type1.equals("centos5") ||
-        type1.equals("oraclelinux5")) {
-      if (type2.equals("centos5") || type2.equals("redhat5") ||
-          type2.equals("oraclelinux5")) {
-        return true;
-      }
-    } else if (type1.equals("redhat6") || type1.equals("centos6") ||
-        type1.equals("oraclelinux6")) {
-      if (type2.equals("centos6") || type2.equals("redhat6") ||
-          type2.equals("oraclelinux6")) {
-        return true;
-      }
-    } else if (type1.equals("suse11") || type1.equals("sles11")) {
-      if (type2.equals("suse11") || type2.equals("sles11")) {
-        return true;
-      }
-    }
-    return false;
-  }*/
-
   public boolean isOsSupported(String osType) {
     return osType.equals("redhat5") || osType.equals("centos5") ||
             osType.equals("oraclelinux5") ||
@@ -949,4 +1053,5 @@ public class AmbariMetaInfo {
             osType.equals("oraclelinux6") ||
             osType.equals("suse11") || osType.equals("sles11");
   }
+ 
 }

+ 19 - 1
ambari-server/src/main/java/org/apache/ambari/server/api/services/StacksService.java

@@ -22,7 +22,11 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.ws.rs.*;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
@@ -109,6 +113,20 @@ public class StacksService extends BaseService {
     return handleRequest(headers, null, ui, Request.Type.GET,
         createRepositoryResource(stackName, stackVersion, osType, repoId));
   }
+  
+  @PUT
+  @Path("{stackName}/versions/{stackVersion}/operatingSystems/{osType}/repositories/{repoId}")
+  @Produces("text/plain")
+  public Response updateRepository(String body, @Context HttpHeaders headers,
+      @Context UriInfo ui, @PathParam("stackName") String stackName,
+      @PathParam("stackVersion") String stackVersion,
+      @PathParam("osType") String osType,
+      @PathParam("repoId") String repoId) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT,
+        createRepositoryResource(stackName, stackVersion, osType, repoId));
+  }
+  
 
   @GET
   @Path("{stackName}/versions/{stackVersion}/stackServices")

+ 9 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java

@@ -455,6 +455,15 @@ public interface AmbariManagementController {
    */
   public Set<RepositoryResponse> getRepositories(Set<RepositoryRequest> requests) throws AmbariException;
 
+  /**
+   * Updates repositories by stack name, version and operating system.
+   * 
+   * @param requests the repositories
+   * 
+   * @throws AmbariException
+   */
+  void updateRespositories(Set<RepositoryRequest> requests) throws AmbariException;
+
   
   /**
    * Get repositories by stack name, version.

+ 26 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java

@@ -4249,7 +4249,7 @@ public class AmbariManagementControllerImpl implements
     }
     return response;
   }
-
+  
   private Set<RepositoryResponse> getRepositories(RepositoryRequest request) throws AmbariException {
 
     String stackName = request.getStackName();
@@ -4274,6 +4274,31 @@ public class AmbariManagementControllerImpl implements
 
     return response;
   }
+  
+  @Override
+  public void updateRespositories(Set<RepositoryRequest> requests) throws AmbariException {
+    for (RepositoryRequest rr : requests) {
+      if (null == rr.getStackName() || rr.getStackName().isEmpty())
+        throw new AmbariException("Stack name must be specified.");
+      
+      if (null == rr.getStackVersion() || rr.getStackVersion().isEmpty())
+        throw new AmbariException("Stack version must be specified.");
+      
+      if (null == rr.getOsType() || rr.getOsType().isEmpty())
+        throw new AmbariException("OS type must be specified.");
+      
+      if (null == rr.getRepoId() || rr.getRepoId().isEmpty())
+        throw new AmbariException("Repo ID must be specified.");
+      
+      if (null != rr.getBaseUrl()) {
+        // verify url is accessible
+        ambariMetaInfo.updateRepository(rr.getStackName(),
+            rr.getStackVersion(), rr.getOsType(), rr.getRepoId(),
+            rr.getBaseUrl());
+      }
+    }
+  }
+  
 
   @Override
   public Set<StackVersionResponse> getStackVersions(

+ 23 - 4
ambari-server/src/main/java/org/apache/ambari/server/controller/RepositoryRequest.java

@@ -20,21 +20,40 @@ package org.apache.ambari.server.controller;
 
 public class RepositoryRequest extends OperatingSystemRequest{
 
+  private String repoId;
+  private String baseUrl;
+  
   public RepositoryRequest(String stackName, String stackVersion, String osType, String repoId) {
     super(stackName, stackVersion, osType);
     setRepoId(repoId);
   }
 
-  
   public String getRepoId() {
     return repoId;
   }
 
-
   public void setRepoId(String repoId) {
     this.repoId = repoId;
   }
-
-  private String repoId;
+  
+  /**
+   * Gets the base URL for the repo.
+   * 
+   * @return the url
+   */
+  public String getBaseUrl() {
+    return baseUrl;
+  }
+  
+  /**
+   * Sets the base URL for the repo.
+   * 
+   * @param url the base URL.
+   */
+  public void setBaseUrl(String url) {
+    baseUrl = url;
+  }
+  
+  
 
 }

+ 59 - 11
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RepositoryResourceProvider.java

@@ -22,6 +22,7 @@ package org.apache.ambari.server.controller.internal;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -33,38 +34,41 @@ 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.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.Resource.Type;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
-public class RepositoryResourceProvider extends ReadOnlyResourceProvider {
+public class RepositoryResourceProvider extends AbstractControllerResourceProvider {
 
   public static final String REPOSITORY_NAME_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "repo_name");
 
-  private static final String STACK_NAME_PROPERTY_ID = PropertyHelper
+  public static final String STACK_NAME_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "stack_name");
 
-  private static final String STACK_VERSION_PROPERTY_ID = PropertyHelper
+  public static final String STACK_VERSION_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "stack_version");
 
-  private static final String OS_TYPE_PROPERTY_ID = PropertyHelper
+  public static final String OS_TYPE_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "os_type");
 
-  private static final String REPOSITORY_BASE_URL_PROPERTY_ID = PropertyHelper
+  public static final String REPOSITORY_BASE_URL_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "base_url");
 
-  private static final String REPOSITORY_OS_TYPE_PROPERTY_ID = PropertyHelper
+  public static final String REPOSITORY_OS_TYPE_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "os_type");
 
-  private static final String REPO_ID_PROPERTY_ID = PropertyHelper
+  public static final String REPO_ID_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "repo_id");
 
-  private static final String REPOSITORY_MIRRORS_LIST_PROPERTY_ID = PropertyHelper
+  public static final String REPOSITORY_MIRRORS_LIST_PROPERTY_ID = PropertyHelper
       .getPropertyId("Repositories", "mirrors_list");
+  
 
   private static Set<String> pkPropertyIds = new HashSet<String>(
       Arrays.asList(new String[] { STACK_NAME_PROPERTY_ID,
@@ -76,6 +80,31 @@ public class RepositoryResourceProvider extends ReadOnlyResourceProvider {
       AmbariManagementController managementController) {
     super(propertyIds, keyPropertyIds, managementController);
   }
+  
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+    
+    final Set<RepositoryRequest> requests = new HashSet<RepositoryRequest>();
+    
+    Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
+    if (iterator.hasNext()) {
+      for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) {
+        requests.add(getRequest(propertyMap));
+      }
+    }
+    
+    modifyResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        getManagementController().updateRespositories(requests);
+        return null;
+      }
+    });
+    
+    return getRequestStatus(null);
+  }
 
   @Override
   public Set<Resource> getResources(Request request, Predicate predicate)
@@ -125,14 +154,33 @@ public class RepositoryResourceProvider extends ReadOnlyResourceProvider {
 
     return resources;
   }
+  
+  @Override
+  public RequestStatus createResources(Request request) throws SystemException,
+      UnsupportedPropertyException, ResourceAlreadyExistsException,
+      NoSuchParentResourceException {
+    throw new SystemException("Cannot create repositories.", null);
+  }
+  
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException,
+      NoSuchResourceException, NoSuchParentResourceException {
+    throw new SystemException("Cannot delete repositories.", null);
+  }
 
   private RepositoryRequest getRequest(Map<String, Object> properties) {
-    return new RepositoryRequest(
+    RepositoryRequest rr = new RepositoryRequest(
         (String) properties.get(STACK_NAME_PROPERTY_ID),
         (String) properties.get(STACK_VERSION_PROPERTY_ID),
         (String) properties.get(OS_TYPE_PROPERTY_ID),
-        (String) properties.get(REPO_ID_PROPERTY_ID)
-        );
+        (String) properties.get(REPO_ID_PROPERTY_ID));
+    
+    if (properties.containsKey(REPOSITORY_BASE_URL_PROPERTY_ID)) {
+      rr.setBaseUrl((String) properties.get(REPOSITORY_BASE_URL_PROPERTY_ID));
+    }
+    
+    return rr;
   }
 
   @Override

+ 52 - 1
ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java

@@ -240,7 +240,7 @@ public class AmbariMetaInfoTest {
     assertEquals(3, redhat6cnt.size());
     assertEquals(3, centos6Cnt.size());
   }
-
+  
   
   @Test
   /**
@@ -428,4 +428,55 @@ public class AmbariMetaInfoTest {
     Assert.assertTrue(metaInfo.isOsSupported("sles11"));
     Assert.assertFalse(metaInfo.isOsSupported("windows"));
   }
+  
+  @Test
+  public void testRepoBaseUrl() throws Exception {
+    File stackRoot = new File("src/test/resources/stacks");
+    
+    File tmp = new File(FileUtils.getTempDirectoryPath() + "stacks" + System.currentTimeMillis());
+    FileUtils.copyDirectory(stackRoot, tmp);
+
+    AmbariMetaInfo metaInfo = new AmbariMetaInfo(tmp, new File("target/version"));
+    metaInfo.init();
+
+    String TMP_URL1 = "http://foo.com";
+    String TMP_URL2 = "http://bar.com";
+    
+    try {
+      RepositoryInfo repository = metaInfo.getRepository(STACK_NAME_HDP, STACK_VERSION_HDP, OS_TYPE, REPO_ID);
+      
+      metaInfo.updateRepository(STACK_NAME_HDP, STACK_VERSION_HDP, OS_TYPE, REPO_ID, TMP_URL1);
+      repository = metaInfo.getRepository(STACK_NAME_HDP, STACK_VERSION_HDP, OS_TYPE, REPO_ID);
+      Assert.assertEquals(TMP_URL1, repository.getBaseUrl());
+      
+      // reload from disk
+      AmbariMetaInfo metaInfo1 = new AmbariMetaInfo(tmp, new File("target/version"));
+      metaInfo1.init();
+      
+      RepositoryInfo repository1 = metaInfo.getRepository(STACK_NAME_HDP, STACK_VERSION_HDP, OS_TYPE, REPO_ID);
+      Assert.assertEquals(TMP_URL1, repository1.getBaseUrl());
+      
+      try {
+        metaInfo1.updateRepository(NON_EXT_VALUE, STACK_VERSION_HDP, OS_TYPE, REPO_ID, TMP_URL2);
+        Assert.fail("Expect StackAccessException on name");
+
+        metaInfo1.updateRepository(STACK_NAME_HDP, NON_EXT_VALUE, OS_TYPE, REPO_ID, TMP_URL2);
+        Assert.fail("Expect StackAccessException on version");
+        
+        metaInfo1.updateRepository(STACK_NAME_HDP, STACK_VERSION_HDP, NON_EXT_VALUE, REPO_ID, TMP_URL2);
+        Assert.fail("Expect StackAccessException on OS");
+        
+        metaInfo1.updateRepository(STACK_NAME_HDP, STACK_VERSION_HDP, OS_TYPE, NON_EXT_VALUE, TMP_URL2);
+        Assert.fail("Expect StackAccessException on repo id");
+        
+      } catch (Exception e) {
+        // expecting failure
+      }
+      
+    } finally {
+      FileUtils.deleteDirectory(tmp);
+    }
+  }
+
+  
 }

+ 164 - 0
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RepositoryResourceProviderTest.java

@@ -0,0 +1,164 @@
+/**
+ * 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 static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.RepositoryRequest;
+import org.apache.ambari.server.controller.RepositoryResponse;
+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.ResourceProvider;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RepositoryResourceProviderTest {
+  
+  private static final String VAL_STACK_NAME = "HDP";
+  private static final String VAL_STACK_VERSION = "0.2";
+  private static final String VAL_OS = "centos6";
+  private static final String VAL_REPO_ID = "HDP-0.2";
+  private static final String VAL_REPO_NAME = "HDP1";
+  private static final String VAL_BASE_URL = "http://foo.com";
+
+  @Test
+  public void testGetResources() throws Exception{
+    Resource.Type type = Resource.Type.Repository;
+
+    AmbariManagementController managementController = EasyMock.createMock(AmbariManagementController.class);
+
+    RepositoryResponse rr = new RepositoryResponse(VAL_BASE_URL, VAL_OS,
+        VAL_REPO_ID, VAL_REPO_NAME, null);
+    Set<RepositoryResponse> allResponse = new HashSet<RepositoryResponse>();
+    allResponse.add(rr);
+    
+    // set expectations
+    expect(managementController.getRepositories(EasyMock.<Set<RepositoryRequest>>anyObject())).andReturn(allResponse).times(1);
+
+    // replay
+    replay(managementController);
+
+    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
+        type,
+        PropertyHelper.getPropertyIds(type),
+        PropertyHelper.getKeyPropertyIds(type),
+        managementController);
+
+    Set<String> propertyIds = new HashSet<String>();
+    propertyIds.add(RepositoryResourceProvider.STACK_NAME_PROPERTY_ID);
+    propertyIds.add(RepositoryResourceProvider.STACK_VERSION_PROPERTY_ID);
+    propertyIds.add(RepositoryResourceProvider.REPOSITORY_NAME_PROPERTY_ID);
+    propertyIds.add(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID);
+    propertyIds.add(RepositoryResourceProvider.REPOSITORY_OS_TYPE_PROPERTY_ID);
+    propertyIds.add(RepositoryResourceProvider.REPO_ID_PROPERTY_ID);
+
+    Predicate predicate =
+        new PredicateBuilder().property(RepositoryResourceProvider.STACK_NAME_PROPERTY_ID).equals(VAL_STACK_NAME)
+          .and().property(RepositoryResourceProvider.STACK_VERSION_PROPERTY_ID).equals(VAL_STACK_VERSION)
+          .toPredicate();
+    
+    // create the request
+    Request request = PropertyHelper.getReadRequest(propertyIds);
+
+    // get all ... no predicate
+    Set<Resource> resources = provider.getResources(request, predicate);
+
+    Assert.assertEquals(allResponse.size(), resources.size());
+    
+    for (Resource resource : resources) {
+      Object o = resource.getPropertyValue(RepositoryResourceProvider.STACK_NAME_PROPERTY_ID);
+      Assert.assertEquals(VAL_STACK_NAME, o);
+      
+      o = resource.getPropertyValue(RepositoryResourceProvider.STACK_VERSION_PROPERTY_ID);
+      Assert.assertEquals(VAL_STACK_VERSION, o);
+      
+      o = resource.getPropertyValue(RepositoryResourceProvider.REPOSITORY_NAME_PROPERTY_ID);
+      Assert.assertEquals(o, VAL_REPO_NAME);
+      
+      o = resource.getPropertyValue(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID);
+      Assert.assertEquals(o, VAL_BASE_URL);
+      
+      o = resource.getPropertyValue(RepositoryResourceProvider.REPOSITORY_OS_TYPE_PROPERTY_ID);
+      Assert.assertEquals(o, VAL_OS);
+      
+      o = resource.getPropertyValue(RepositoryResourceProvider.REPO_ID_PROPERTY_ID);
+      Assert.assertEquals(o, VAL_REPO_ID);
+
+    }
+
+    // verify
+    verify(managementController);
+  }
+  
+  @Test
+  public void testUpdateResources() throws Exception {
+    Resource.Type type = Resource.Type.Repository;
+
+    AmbariManagementController managementController = EasyMock.createMock(AmbariManagementController.class);
+
+    RepositoryResponse rr = new RepositoryResponse(VAL_BASE_URL, VAL_OS,
+        VAL_REPO_ID, VAL_REPO_NAME, null);
+    Set<RepositoryResponse> allResponse = new HashSet<RepositoryResponse>();
+    allResponse.add(rr);    
+    
+    // set expectations
+    expect(managementController.getRepositories(EasyMock.<Set<RepositoryRequest>>anyObject())).andReturn(allResponse).times(1);
+    managementController.updateRespositories(EasyMock.<Set<RepositoryRequest>>anyObject());
+
+    // replay
+    replay(managementController);
+    
+    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
+        type,
+        PropertyHelper.getPropertyIds(type),
+        PropertyHelper.getKeyPropertyIds(type),
+        managementController);
+
+    // add the property map to a set for the request.
+    Map<String, Object> properties = new LinkedHashMap<String, Object>();
+    properties.put(RepositoryResourceProvider.REPOSITORY_BASE_URL_PROPERTY_ID, "http://bar.com");
+
+    // create the request
+    Request request = PropertyHelper.getUpdateRequest(properties, null);
+    
+    Predicate predicate =
+        new PredicateBuilder().property(RepositoryResourceProvider.STACK_NAME_PROPERTY_ID).equals(VAL_STACK_NAME)
+          .and().property(RepositoryResourceProvider.STACK_VERSION_PROPERTY_ID).equals(VAL_STACK_VERSION)
+          .toPredicate();
+    
+    provider.updateResources(request, predicate);    
+    
+    // verify
+    verify(managementController);
+  }
+
+}