JCLOUDS-274 Implement listCookbookVersionsInEnvironment in ChefService API

This commit is contained in:
Noorul Islam K M 2013-10-04 14:09:05 +05:30 committed by Ignasi Barrera
parent d786daa70e
commit 89a2b8ab36
5 changed files with 359 additions and 1 deletions

View File

@ -186,6 +186,25 @@ public interface ChefService {
*/
Iterable<? extends CookbookVersion> listCookbookVersions();
/**
* Lists the details of all existing cookbooks in an environment.
*
* @param environmentName The environment name.
* @return The details of all existing cookbooks in an environment.
*/
Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName);
/**
* Lists the details of all existing cookbooks in an environment
* limiting number of versions.
*
* @param environmentName The environment name.
* @param numVersions The number of cookbook versions to include.
* Use 'all' to return all cookbook versions.
* @return The details of all existing cookbooks in environment.
*/
Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName, String numVersions);
/**
* Lists the details of all existing environments.
*

View File

@ -49,6 +49,7 @@ import org.jclouds.chef.strategy.DeleteAllClientsInList;
import org.jclouds.chef.strategy.DeleteAllNodesInList;
import org.jclouds.chef.strategy.ListClients;
import org.jclouds.chef.strategy.ListCookbookVersions;
import org.jclouds.chef.strategy.ListCookbookVersionsInEnvironment;
import org.jclouds.chef.strategy.ListNodesInEnvironment;
import org.jclouds.chef.strategy.ListEnvironments;
import org.jclouds.chef.strategy.ListNodes;
@ -88,6 +89,7 @@ public class BaseChefService implements ChefService {
private final BootstrapConfigForGroup bootstrapConfigForGroup;
private final RunListForGroup runListForGroup;
private final ListCookbookVersions listCookbookVersions;
private final ListCookbookVersionsInEnvironment listCookbookVersionsInEnvironment;
private final ListEnvironments listEnvironments;
private final ListNodesInEnvironment listNodesInEnvironment;
private final Json json;
@ -104,7 +106,8 @@ public class BaseChefService implements ChefService {
UpdateAutomaticAttributesOnNode updateAutomaticAttributesOnNode, Supplier<PrivateKey> privateKey,
@Named(CHEF_BOOTSTRAP_DATABAG) String databag, GroupToBootScript groupToBootScript,
BootstrapConfigForGroup bootstrapConfigForGroup, RunListForGroup runListForGroup,
ListEnvironments listEnvironments, ListNodesInEnvironment listNodesInEnvironment, Json json) {
ListEnvironments listEnvironments, ListNodesInEnvironment listNodesInEnvironment,
ListCookbookVersionsInEnvironment listCookbookVersionsInEnvironment, Json json) {
this.chefContext = checkNotNull(chefContext, "chefContext");
this.api = checkNotNull(api, "api");
this.cleanupStaleNodesAndClients = checkNotNull(cleanupStaleNodesAndClients, "cleanupStaleNodesAndClients");
@ -124,6 +127,7 @@ public class BaseChefService implements ChefService {
this.runListForGroup = checkNotNull(runListForGroup, "runListForGroup");
this.listEnvironments = checkNotNull(listEnvironments, "listEnvironments");
this.listNodesInEnvironment = checkNotNull(listNodesInEnvironment, "listNodesInEnvironment");
this.listCookbookVersionsInEnvironment = checkNotNull(listCookbookVersionsInEnvironment, "listCookbookVersionsInEnvironment");
this.json = checkNotNull(json, "json");
}
@ -237,6 +241,16 @@ public class BaseChefService implements ChefService {
return listCookbookVersions.execute();
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName) {
return listCookbookVersionsInEnvironment.execute(environmentName);
}
@Override
public Iterable<? extends CookbookVersion> listCookbookVersionsInEnvironment(String environmentName, String numVersions) {
return listCookbookVersionsInEnvironment.execute(environmentName, numVersions);
}
@Override
public Iterable<? extends Environment> listEnvironments() {
return listEnvironments.execute();

View File

@ -0,0 +1,41 @@
/*
* 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.jclouds.chef.strategy;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.strategy.internal.ListCookbookVersionsInEnvironmentImpl;
import com.google.common.base.Predicate;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.ImplementedBy;
/**
*
* @author Noorul Islam K M
*/
@ImplementedBy(ListCookbookVersionsInEnvironmentImpl.class)
public interface ListCookbookVersionsInEnvironment {
Iterable<? extends CookbookVersion> execute(String environmentName);
Iterable<? extends CookbookVersion> execute(String environmentName, String numVersions);
Iterable<? extends CookbookVersion> execute(ListeningExecutorService executor, String environmentName);
Iterable<? extends CookbookVersion> execute(ListeningExecutorService executor, String environmentName, String numVersions);
}

View File

@ -0,0 +1,113 @@
/*
* 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.jclouds.chef.strategy.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.contains;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList;
import static com.google.common.util.concurrent.Futures.getUnchecked;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.config.ChefProperties;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.strategy.ListCookbookVersionsInEnvironment;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.Inject;
/**
*
* @author Noorul Islam K M
*/
@Singleton
public class ListCookbookVersionsInEnvironmentImpl implements ListCookbookVersionsInEnvironment {
protected final ChefApi api;
protected final ListeningExecutorService userExecutor;
@Resource
@Named(ChefProperties.CHEF_LOGGER)
protected Logger logger = Logger.NULL;
@Inject
ListCookbookVersionsInEnvironmentImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ChefApi api) {
this.userExecutor = checkNotNull(userExecutor, "userExecuor");
this.api = checkNotNull(api, "api");
}
@Override
public Iterable<? extends CookbookVersion> execute(String environmentName) {
return execute(userExecutor, environmentName);
}
@Override
public Iterable<? extends CookbookVersion> execute(String environmentName, String numVersions) {
return execute(userExecutor, environmentName, numVersions);
}
public Iterable<? extends CookbookVersion> execute(ListeningExecutorService executor, String environmentName) {
return execute(executor, api.listCookbooksInEnvironment(environmentName));
}
@Override
public Iterable<? extends CookbookVersion> execute(ListeningExecutorService executor, String environmentName, String numVersions) {
return execute(executor, api.listCookbooksInEnvironment(environmentName, numVersions));
}
private Iterable<? extends CookbookVersion> execute(final ListeningExecutorService executor,
Iterable<CookbookDefinition> cookbookDefs) {
return concat(transform(cookbookDefs, new Function<CookbookDefinition, Iterable<? extends CookbookVersion>>() {
@Override
public Iterable<? extends CookbookVersion> apply(final CookbookDefinition cookbookDef) {
// TODO getting each version could also go parallel
Set<CookbookDefinition.Version> cookbookVersions = cookbookDef.getVersions();
ListenableFuture<List<CookbookVersion>> futures = allAsList(transform(cookbookVersions,
new Function<CookbookDefinition.Version, ListenableFuture<CookbookVersion>>() {
@Override
public ListenableFuture<CookbookVersion> apply(final CookbookDefinition.Version version) {
return executor.submit(new Callable<CookbookVersion>() {
@Override
public CookbookVersion call() throws Exception {
return api.getCookbook(cookbookDef.getName(), version.getVersion());
}
});
}
}));
logger.trace(String.format("getting versions of cookbook %s: ", cookbookDef.getName()));
return getUnchecked(futures);
}
}));
}
}

View File

@ -0,0 +1,171 @@
/*
* 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.jclouds.chef.strategy.internal;
import static com.google.common.collect.Iterables.size;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import org.jclouds.chef.ChefApi;
import org.jclouds.chef.domain.ChecksumStatus;
import org.jclouds.chef.domain.CookbookDefinition;
import org.jclouds.chef.domain.CookbookVersion;
import org.jclouds.chef.domain.Metadata;
import org.jclouds.chef.domain.Resource;
import org.jclouds.chef.domain.Sandbox;
import org.jclouds.chef.domain.UploadSandbox;
import org.jclouds.chef.internal.BaseChefLiveTest;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.FilePayload;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import java.io.File;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Bytes;
/**
* Tests behavior of {@code ListCookbookVersionsInEnvironmentImpl} strategies
*
* @author Noorul Islam K M
*/
@Test(groups = "live", testName = "ListCookbookVersionsInEnvironmentImplLiveTest")
public class ListCookbookVersionsInEnvironmentImplLiveTest extends BaseChefLiveTest<ChefApi> {
public static final String PREFIX = "jcloudstest-strategy-" + System.getProperty("user.name");
private ListCookbookVersionsInEnvironmentImpl strategy;
private CreateNodeAndPopulateAutomaticAttributesImpl creator;
@Override
protected void initialize() {
super.initialize();
try {
createCookbooksWithMultipleVersions(PREFIX);
createCookbooksWithMultipleVersions(PREFIX + 1);
} catch (Exception e) {
fail("Could not create cookbooks", e);
}
this.strategy = injector.getInstance(ListCookbookVersionsInEnvironmentImpl.class);
}
@AfterClass(groups = { "integration", "live" })
@Override
protected void tearDown() {
api.deleteCookbook(PREFIX, "0.0.0");
api.deleteCookbook(PREFIX, "1.0.0");
api.deleteCookbook(PREFIX + 1, "0.0.0");
api.deleteCookbook(PREFIX + 1, "1.0.0");
super.tearDown();
}
@Test
public void testExecute() {
assertTrue(size(strategy.execute("_default")) > 0, "Expected one or more elements");
}
@Test
public void testExecuteWithNumVersions() {
assertTrue(size(strategy.execute("_default", "2")) > 0, "Expected one or more elements");
}
@Test
public void testExecuteWithNumVersionsAll() {
assertTrue(size(strategy.execute("_default", "all")) > 0, "Expected one or more elements");
}
private FilePayload uploadContent(String fileName) throws Exception {
// Define the file you want in the cookbook
FilePayload content = Payloads.newFilePayload(new File(System.getProperty("user.dir"), fileName));
content.getContentMetadata().setContentType("application/x-binary");
// Get an md5 so that you can see if the server already has it or not
Payloads.calculateMD5(content);
// Note that java collections cannot effectively do equals or hashcodes on
// byte arrays, so let's convert to a list of bytes.
List<Byte> md5 = Bytes.asList(content.getContentMetadata().getContentMD5());
// Request an upload site for this file
UploadSandbox site = api.createUploadSandboxForChecksums(ImmutableSet.of(md5));
assertTrue(site.getChecksums().containsKey(md5), md5 + " not in " + site.getChecksums());
try {
// Upload the file contents, if still not uploaded
ChecksumStatus status = site.getChecksums().get(md5);
if (status.needsUpload()) {
api.uploadContent(status.getUrl(), content);
}
Sandbox sandbox = api.commitSandbox(site.getSandboxId(), true);
assertTrue(sandbox.isCompleted(), "Sandbox should be completed after uploading");
} catch (RuntimeException e) {
api.commitSandbox(site.getSandboxId(), false);
fail("Could not upload content", e);
}
return content;
}
private void createCookbooksWithMultipleVersions(String cookbookName) throws Exception {
FilePayload v0content = uploadContent("pom.xml");
FilePayload v1content = uploadContent("../README.md");
// Create the metadata of the cookbook
Metadata metadata = Metadata.builder() //
.name(cookbookName) //
.version("0.0.0") //
.description("Jclouds test uploaded cookbook") //
.maintainer("jclouds") //
.maintainerEmail("someone@jclouds.org") //
.license("Apache 2.0") //
.build();
// Create new cookbook version
CookbookVersion cookbook = CookbookVersion.builder(cookbookName, "0.0.0") //
.metadata(metadata) //
.rootFile(Resource.builder().fromPayload(v0content).build()) //
.build();
// upload the cookbook to the remote server
api.updateCookbook(cookbookName, "0.0.0", cookbook);
// Create the metadata of the cookbook
metadata = Metadata.builder() //
.name(cookbookName) //
.version("1.0.0") //
.description("Jclouds test uploaded cookbook") //
.maintainer("jclouds") //
.maintainerEmail("someone@jclouds.org") //
.license("Apache 2.0") //
.build();
// Create a new cookbook version
cookbook = CookbookVersion.builder(cookbookName, "1.0.0") //
.metadata(metadata) //
.rootFile(Resource.builder().fromPayload(v1content).build()) //
.build();
// upload the cookbook to the remote server
api.updateCookbook(cookbookName, "1.0.0", cookbook);
}
}