You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2014/07/28 22:02:57 UTC
[06/10] Move jclouds-chef to the main jclouds repo
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java
new file mode 100644
index 0000000..a426b8d
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/BaseListNodesImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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 com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.logging.Logger;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+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;
+
+public abstract class BaseListNodesImpl {
+
+ protected final ChefApi api;
+
+ protected Logger logger = Logger.NULL;
+
+ BaseListNodesImpl(ChefApi api) {
+ this.api = checkNotNull(api, "api");
+ }
+
+ protected Iterable<? extends Node> execute(Iterable<String> toGet) {
+ Iterable<? extends Node> nodes = transform(toGet, new Function<String, Node>() {
+ @Override
+ public Node apply(final String input) {
+ return api.getNode(input);
+ }
+ }
+ );
+
+ logger.trace(String.format("getting nodes: %s", Joiner.on(',').join(toGet)));
+ return nodes;
+
+ }
+
+ protected Iterable<? extends Node> executeConcurrently(final ListeningExecutorService executor,
+ Iterable<String> toGet) {
+ ListenableFuture<List<Node>> futures = allAsList(transform(toGet, new Function<String, ListenableFuture<Node>>() {
+ @Override
+ public ListenableFuture<Node> apply(final String input) {
+ return executor.submit(new Callable<Node>() {
+ @Override
+ public Node call() throws Exception {
+ return api.getNode(input);
+ }
+ });
+ }
+ }));
+
+ logger.trace(String.format("getting nodes: %s", Joiner.on(',').join(toGet)));
+ return getUnchecked(futures);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CleanupStaleNodesAndClientsImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CleanupStaleNodesAndClientsImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CleanupStaleNodesAndClientsImpl.java
new file mode 100644
index 0000000..46c765b
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CleanupStaleNodesAndClientsImpl.java
@@ -0,0 +1,102 @@
+/*
+ * 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.base.Predicates.and;
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+import static org.jclouds.chef.util.ChefUtils.fromOhaiTime;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.chef.strategy.CleanupStaleNodesAndClients;
+import org.jclouds.chef.strategy.DeleteAllClientsInList;
+import org.jclouds.chef.strategy.DeleteAllNodesInList;
+import org.jclouds.chef.strategy.ListNodes;
+import org.jclouds.domain.JsonBall;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+
+/**
+ *
+ * Cleans up nodes and apis who have been hanging around too long.
+ */
+@Singleton
+public class CleanupStaleNodesAndClientsImpl implements CleanupStaleNodesAndClients {
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ private final ListNodes nodeLister;
+ private final DeleteAllNodesInList nodeDeleter;
+ private final DeleteAllClientsInList clientDeleter;
+
+ @Inject
+ public CleanupStaleNodesAndClientsImpl(DeleteAllNodesInList nodeDeleter, DeleteAllClientsInList clientDeleter,
+ ListNodes nodeLister) {
+ this.nodeLister = checkNotNull(nodeLister, "nodeLister");
+ this.nodeDeleter = checkNotNull(nodeDeleter, "nodeDeleter");
+ this.clientDeleter = checkNotNull(clientDeleter, "clientDeleter");
+ }
+
+ @Override
+ public void execute(final String prefix, int secondsStale) {
+ final Calendar expired = Calendar.getInstance();
+ expired.setTime(new Date());
+ expired.add(Calendar.SECOND, -secondsStale);
+ Iterable<? extends Node> staleNodes = filter(
+ nodeLister.execute(), and(notNull(), new Predicate<Node>() {
+ @Override
+ public boolean apply(Node input) {
+ return input.getName().startsWith(prefix);
+ }
+ },
+ new Predicate<Node>() {
+ @Override
+ public boolean apply(Node input) {
+ JsonBall dateLong = input.getAutomaticAttributes().get("ohai_time");
+ if (dateLong == null)
+ return true;
+ Calendar nodeUpdate = Calendar.getInstance();
+ nodeUpdate.setTime(fromOhaiTime(dateLong));
+ return expired.after(nodeUpdate);
+ }
+ }));
+ Iterable<String> nodeNames = transform(staleNodes, new Function<Node, String>() {
+
+ @Override
+ public String apply(Node from) {
+ return from.getName();
+ }
+
+ });
+ nodeDeleter.execute(nodeNames);
+ clientDeleter.execute(nodeNames);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CreateNodeAndPopulateAutomaticAttributesImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CreateNodeAndPopulateAutomaticAttributesImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CreateNodeAndPopulateAutomaticAttributesImpl.java
new file mode 100644
index 0000000..7dabd06
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/CreateNodeAndPopulateAutomaticAttributesImpl.java
@@ -0,0 +1,83 @@
+/*
+ * 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 java.util.Map;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.chef.strategy.CreateNodeAndPopulateAutomaticAttributes;
+import org.jclouds.domain.JsonBall;
+import org.jclouds.logging.Logger;
+import org.jclouds.ohai.Automatic;
+
+import com.google.common.base.Supplier;
+
+/**
+ *
+ * Updates node with new automatic attributes.
+ */
+@Singleton
+public class CreateNodeAndPopulateAutomaticAttributesImpl implements CreateNodeAndPopulateAutomaticAttributes {
+
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ private final ChefApi chef;
+ private final Supplier<Map<String, JsonBall>> automaticSupplier;
+
+ @Inject
+ public CreateNodeAndPopulateAutomaticAttributesImpl(ChefApi chef,
+ @Automatic Supplier<Map<String, JsonBall>> automaticSupplier) {
+ this.chef = checkNotNull(chef, "chef");
+ this.automaticSupplier = checkNotNull(automaticSupplier, "automaticSupplier");
+ }
+
+ @Override
+ public Node execute(Node node) {
+ logger.trace("creating node %s", node.getName());
+ Node withAutomatic = Node.builder() //
+ .name(node.getName()) //
+ .normalAttributes(node.getNormalAttributes()) //
+ .overrideAttributes(node.getOverrideAttributes()) //
+ .defaultAttributes(node.getDefaultAttributes()) //
+ .automaticAttributes(node.getAutomaticAttributes()) //
+ .automaticAttributes(automaticSupplier.get()) //
+ .runList(node.getRunList()) //
+ .environment(node.getEnvironment()) //
+ .build();
+
+
+ chef.createNode(withAutomatic);
+ logger.debug("created node %s", withAutomatic.getName());
+ return node;
+ }
+
+ @Override
+ public Node execute(String nodeName, Iterable<String> runList) {
+ return execute(Node.builder().name(nodeName).runList(runList).environment("_default").build());
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllClientsInListImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllClientsInListImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllClientsInListImpl.java
new file mode 100644
index 0000000..ffdd3ec
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllClientsInListImpl.java
@@ -0,0 +1,85 @@
+/*
+ * 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.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.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.Client;
+import org.jclouds.chef.strategy.DeleteAllClientsInList;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+
+/**
+ * Concurrently delete all given clients.
+ */
+@Singleton
+public class DeleteAllClientsInListImpl implements DeleteAllClientsInList {
+
+ protected final ChefApi api;
+ protected final ListeningExecutorService userExecutor;
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ DeleteAllClientsInListImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ChefApi api) {
+ this.userExecutor = checkNotNull(userExecutor, "userExecuor");
+ this.api = checkNotNull(api, "api");
+ }
+
+ @Override
+ public void execute(Iterable<String> names) {
+ execute(userExecutor, names);
+ }
+
+ @Override
+ public void execute(final ListeningExecutorService executor, Iterable<String> names) {
+ ListenableFuture<List<Client>> futures = allAsList(transform(names,
+ new Function<String, ListenableFuture<Client>>() {
+ @Override
+ public ListenableFuture<Client> apply(final String input) {
+ return executor.submit(new Callable<Client>() {
+ @Override
+ public Client call() throws Exception {
+ return api.deleteClient(input);
+ }
+ });
+ }
+ }));
+
+ logger.trace(String.format("deleting clients: %s", Joiner.on(',').join(names)));
+ getUnchecked(futures);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllNodesInListImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllNodesInListImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllNodesInListImpl.java
new file mode 100644
index 0000000..212d8b7
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/DeleteAllNodesInListImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.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.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.Node;
+import org.jclouds.chef.strategy.DeleteAllNodesInList;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+
+@Singleton
+public class DeleteAllNodesInListImpl implements DeleteAllNodesInList {
+
+ protected final ChefApi api;
+ protected final ListeningExecutorService userExecutor;
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ DeleteAllNodesInListImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ChefApi api) {
+ this.userExecutor = checkNotNull(userExecutor, "userExecuor");
+ this.api = checkNotNull(api, "api");
+ }
+
+ @Override
+ public void execute(Iterable<String> names) {
+ execute(userExecutor, names);
+ }
+
+ @Override
+ public void execute(final ListeningExecutorService executor, Iterable<String> names) {
+ ListenableFuture<List<Node>> futures = allAsList(transform(names, new Function<String, ListenableFuture<Node>>() {
+ @Override
+ public ListenableFuture<Node> apply(final String input) {
+ return executor.submit(new Callable<Node>() {
+ @Override
+ public Node call() throws Exception {
+ return api.deleteNode(input);
+ }
+ });
+ }
+ }));
+
+ logger.trace(String.format("deleting nodes: %s", Joiner.on(',').join(names)));
+ getUnchecked(futures);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java
new file mode 100644
index 0000000..105be2f
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListClientsImpl.java
@@ -0,0 +1,109 @@
+/*
+ * 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.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.concurrent.Callable;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.chef.domain.Client;
+import org.jclouds.chef.strategy.ListClients;
+import org.jclouds.logging.Logger;
+
+import java.util.concurrent.ExecutorService;
+
+
+@Singleton
+public class ListClientsImpl implements ListClients {
+
+ protected final ChefApi api;
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ ListClientsImpl(ChefApi api) {
+ this.api = checkNotNull(api, "api");
+ }
+
+ @Override
+ public Iterable<? extends Client> execute() {
+
+ Iterable<String> toGet = api.listClients();
+ Iterable<? extends Client> clients = transform(toGet,
+ new Function<String, Client>() {
+ @Override
+ public Client apply(final String input) {
+
+ return api.getClient(input);
+ }
+
+ }
+ );
+
+ logger.trace(String.format("getting clients: %s", Joiner.on(',').join(toGet)));
+ return clients;
+
+ }
+
+ @Override
+ public Iterable<? extends Client> execute(ExecutorService executorService) {
+ return this.execute(MoreExecutors.listeningDecorator(executorService));
+ }
+
+
+ private Iterable<? extends Client> execute(ListeningExecutorService listeningExecutor) {
+ return executeConcurrently(listeningExecutor, api.listClients());
+ }
+
+ private Iterable<? extends Client> executeConcurrently(final ListeningExecutorService executor,
+ Iterable<String> toGet) {
+ ListenableFuture<List<Client>> futures = allAsList(transform(toGet,
+ new Function<String, ListenableFuture<Client>>() {
+ @Override
+ public ListenableFuture<Client> apply(final String input) {
+ return executor.submit(new Callable<Client>() {
+ @Override
+ public Client call() throws Exception {
+ return api.getClient(input);
+ }
+ });
+ }
+ }
+ ));
+
+ logger.trace(String.format("getting clients: %s", Joiner.on(',').join(toGet)));
+ return getUnchecked(futures);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
new file mode 100644
index 0000000..d109038
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsImpl.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.chef.domain.CookbookVersion;
+import org.jclouds.chef.strategy.ListCookbookVersions;
+import org.jclouds.logging.Logger;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.util.concurrent.ExecutorService;
+
+@Singleton
+public class ListCookbookVersionsImpl extends BaseListCookbookVersionsImpl implements ListCookbookVersions {
+
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ ListCookbookVersionsImpl(ChefApi api) {
+ super(api);
+ }
+
+ @Override
+ public Iterable<? extends CookbookVersion> execute() {
+ return super.execute(api.listCookbooks());
+ }
+
+ @Override
+ public Iterable<? extends CookbookVersion> execute(ExecutorService executor) {
+ return this.executeConcurrently(MoreExecutors.listeningDecorator(executor));
+ }
+
+
+ private Iterable<? extends CookbookVersion> executeConcurrently(ListeningExecutorService executor) {
+ return super.executeConcurrently(executor, api.listCookbooks());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
new file mode 100644
index 0000000..a7142dc
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListCookbookVersionsInEnvironmentImpl.java
@@ -0,0 +1,117 @@
+/*
+ * 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.transform;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
+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 java.util.concurrent.ExecutorService;
+
+@Singleton
+public class ListCookbookVersionsInEnvironmentImpl extends BaseListCookbookVersionsImpl
+ implements ListCookbookVersionsInEnvironment {
+
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ ListCookbookVersionsInEnvironmentImpl(ChefApi api) {
+ super(api);
+ }
+
+ @Override
+ public Iterable<? extends CookbookVersion> execute(String environmentName) {
+ return super.execute(transform(api.listCookbooksInEnvironment(environmentName),
+ new Function<CookbookDefinition, String>() {
+
+ @Override
+ public String apply(CookbookDefinition cookbookDefinition) {
+ return cookbookDefinition.getName();
+ }
+ }
+ ));
+ }
+
+ @Override
+ public Iterable<? extends CookbookVersion> execute(String environmentName, String numVersions) {
+ return super.execute(transform(api.listCookbooksInEnvironment(environmentName, numVersions),
+ new Function<CookbookDefinition, String>() {
+
+ @Override
+ public String apply(CookbookDefinition cookbookDefinition) {
+ return cookbookDefinition.getName();
+ }
+ }
+ ));
+ }
+
+ @Override
+ public Iterable<? extends CookbookVersion> execute(ExecutorService executor,
+ String environmentName) {
+ return this.executeConcurrently(MoreExecutors.listeningDecorator(executor), environmentName);
+ }
+
+ @Override
+ public Iterable<? extends CookbookVersion> execute(ExecutorService executor,
+ String environmentName, String numVersions) {
+ return this.executeConcurrently(MoreExecutors.listeningDecorator(executor), environmentName, numVersions);
+ }
+
+
+ private Iterable<? extends CookbookVersion> executeConcurrently(ListeningExecutorService executor,
+ String environmentName) {
+ return super.execute(
+ transform(api.listCookbooksInEnvironment(environmentName), new Function<CookbookDefinition, String>() {
+
+ @Override
+ public String apply(CookbookDefinition cookbookDefinition) {
+ return cookbookDefinition.getName();
+ }
+ })
+ );
+ }
+
+
+ private Iterable<? extends CookbookVersion> executeConcurrently(ListeningExecutorService executor,
+ String environmentName, String numVersions) {
+ return super.execute(transform(api.listCookbooksInEnvironment(environmentName, numVersions),
+ new Function<CookbookDefinition, String>() {
+
+ @Override
+ public String apply(CookbookDefinition cookbookDefinition) {
+ return cookbookDefinition.getName();
+ }
+ }
+ ));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
new file mode 100644
index 0000000..0ed792e
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListEnvironmentsImpl.java
@@ -0,0 +1,96 @@
+/*
+ * 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.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.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.Environment;
+import org.jclouds.chef.strategy.ListEnvironments;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+import com.google.common.util.concurrent.MoreExecutors;
+
+
+import java.util.concurrent.ExecutorService;
+
+
+
+@Singleton
+public class ListEnvironmentsImpl implements ListEnvironments {
+
+ protected final ChefApi api;
+ protected final ListeningExecutorService userExecutor;
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ ListEnvironmentsImpl(@Named(Constants.PROPERTY_USER_THREADS) ListeningExecutorService userExecutor, ChefApi api) {
+ this.userExecutor = checkNotNull(userExecutor, "userExecuor");
+ this.api = checkNotNull(api, "api");
+ }
+
+ @Override
+ public Iterable<? extends Environment> execute() {
+ return execute(userExecutor);
+ }
+
+ @Override
+ public Iterable<? extends Environment> execute(ExecutorService executor) {
+ return this.execute(MoreExecutors.listeningDecorator(executor));
+ }
+
+ private Iterable<? extends Environment> execute(ListeningExecutorService executor) {
+ return execute(executor, api.listEnvironments());
+ }
+
+ private Iterable<? extends Environment> execute(final ListeningExecutorService executor, Iterable<String> toGet) {
+ ListenableFuture<List<Environment>> futures = allAsList(transform(toGet,
+ new Function<String, ListenableFuture<Environment>>() {
+ @Override
+ public ListenableFuture<Environment> apply(final String input) {
+ return executor.submit(new Callable<Environment>() {
+ @Override
+ public Environment call() throws Exception {
+ return api.getEnvironment(input);
+ }
+ });
+ }
+ }));
+
+ logger.trace(String.format("deleting environments: %s", Joiner.on(',').join(toGet)));
+ return getUnchecked(futures);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java
new file mode 100644
index 0000000..8d95965
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesImpl.java
@@ -0,0 +1,62 @@
+/*
+ * 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 javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.chef.strategy.ListNodes;
+import org.jclouds.logging.Logger;
+
+import java.util.concurrent.ExecutorService;
+
+@Singleton
+public class ListNodesImpl extends BaseListNodesImpl implements ListNodes {
+
+
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ ListNodesImpl(ChefApi api) {
+ super(api);
+ }
+
+ @Override
+ public Iterable<? extends Node> execute() {
+ return super.execute(api.listNodes());
+ }
+
+ @Override
+ public Iterable<? extends Node> execute(ExecutorService executor) {
+ return this.executeConcurrently(MoreExecutors.listeningDecorator(executor));
+ }
+
+
+ private Iterable<? extends Node> executeConcurrently(ListeningExecutorService executor) {
+ return super.executeConcurrently(executor, api.listNodes());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
new file mode 100644
index 0000000..58ecaaa
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/ListNodesInEnvironmentImpl.java
@@ -0,0 +1,62 @@
+/*
+ * 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 javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.inject.Inject;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.chef.strategy.ListNodesInEnvironment;
+import org.jclouds.logging.Logger;
+
+import java.util.concurrent.ExecutorService;
+
+@Singleton
+public class ListNodesInEnvironmentImpl extends BaseListNodesImpl implements ListNodesInEnvironment {
+
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ @Inject
+ ListNodesInEnvironmentImpl(ChefApi api) {
+ super(api);
+ }
+
+ @Override
+ public Iterable<? extends Node> execute(String environmentName) {
+ return super.execute(api.listNodesInEnvironment(environmentName));
+ }
+
+ @Override
+ public Iterable<? extends Node> execute(ExecutorService executor, String environmentName) {
+ return this.executeConcurrently(MoreExecutors.listeningDecorator(executor), environmentName);
+ }
+
+
+ private Iterable<? extends Node> executeConcurrently(ListeningExecutorService executor,
+ String environmentName) {
+ return super.executeConcurrently(executor, api.listNodesInEnvironment(environmentName));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/UpdateAutomaticAttributesOnNodeImpl.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/UpdateAutomaticAttributesOnNodeImpl.java b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/UpdateAutomaticAttributesOnNodeImpl.java
new file mode 100644
index 0000000..a6dcac2
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/strategy/internal/UpdateAutomaticAttributesOnNodeImpl.java
@@ -0,0 +1,75 @@
+/*
+ * 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 java.util.Map;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.chef.strategy.UpdateAutomaticAttributesOnNode;
+import org.jclouds.domain.JsonBall;
+import org.jclouds.logging.Logger;
+import org.jclouds.ohai.Automatic;
+
+import com.google.common.base.Supplier;
+
+/**
+ *
+ * Updates node with new automatic attributes.
+ */
+@Singleton
+public class UpdateAutomaticAttributesOnNodeImpl implements UpdateAutomaticAttributesOnNode {
+
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ protected Logger logger = Logger.NULL;
+
+ private final ChefApi chef;
+ private final Supplier<Map<String, JsonBall>> automaticSupplier;
+
+ @Inject
+ public UpdateAutomaticAttributesOnNodeImpl(ChefApi chef, @Automatic Supplier<Map<String, JsonBall>> automaticSupplier) {
+ this.chef = checkNotNull(chef, "chef");
+ this.automaticSupplier = checkNotNull(automaticSupplier, "automaticSupplier");
+ }
+
+ @Override
+ public void execute(String nodeName) {
+ logger.trace("updating node %s", nodeName);
+ Node node = chef.getNode(nodeName);
+ Node updated = Node.builder() //
+ .name(node.getName()) //
+ .normalAttributes(node.getNormalAttributes()) //
+ .overrideAttributes(node.getOverrideAttributes()) //
+ .defaultAttributes(node.getDefaultAttributes()) //
+ .automaticAttributes(automaticSupplier.get()) //
+ .runList(node.getRunList()) //
+ .environment(node.getEnvironment()) //
+ .build();
+
+ chef.updateNode(updated);
+ logger.debug("updated node %s", nodeName);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/suppliers/ChefVersionSupplier.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/suppliers/ChefVersionSupplier.java b/apis/chef/src/main/java/org/jclouds/chef/suppliers/ChefVersionSupplier.java
new file mode 100644
index 0000000..a0d8b04
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/suppliers/ChefVersionSupplier.java
@@ -0,0 +1,73 @@
+/*
+ * 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.suppliers;
+
+import static com.google.common.base.Objects.firstNonNull;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.chef.config.ChefProperties;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.annotations.ApiVersion;
+
+import com.google.common.base.Supplier;
+
+/**
+ * Properly supply the version of the Chef Server.
+ */
+@Singleton
+public class ChefVersionSupplier implements Supplier<Integer> {
+
+ /** The default version to assume in case we can not parse it. */
+ public static final Integer FALLBACK_VERSION = 10;
+
+ @Resource
+ @Named(ChefProperties.CHEF_LOGGER)
+ private Logger logger = Logger.NULL;
+
+ /** The configured version of the Chef Server API. */
+ private final String apiVersion;
+
+ @Inject
+ ChefVersionSupplier(@ApiVersion String apiVersion) {
+ this.apiVersion = checkNotNull(apiVersion, "apiVersion must not be null");
+ }
+
+ @Override
+ public Integer get() {
+ // Old versions of Chef have versions like 0.9.x, 0.10.x, but newer
+ // versions are in the format 10.x.y, 11.x.y
+ Pattern versionPattern = Pattern.compile("(?:0\\.(\\d+)|(\\d+)\\.\\d+)(?:\\.\\d)*");
+
+ Matcher m = versionPattern.matcher(apiVersion);
+ if (!m.matches()) {
+ logger.warn("Configured version does not match the standard version pattern. Assuming version %s",
+ FALLBACK_VERSION);
+ return FALLBACK_VERSION;
+ }
+
+ return Integer.valueOf(firstNonNull(m.group(1), m.group(2)));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApi.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApi.java b/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApi.java
new file mode 100644
index 0000000..c2c5f10
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApi.java
@@ -0,0 +1,387 @@
+/*
+ * 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.test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Sets.newLinkedHashSet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.blobstore.config.LocalBlobStore;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.domain.PageSet;
+import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.domain.Client;
+import org.jclouds.chef.domain.CookbookDefinition;
+import org.jclouds.chef.domain.CookbookVersion;
+import org.jclouds.chef.domain.DatabagItem;
+import org.jclouds.chef.domain.Environment;
+import org.jclouds.chef.domain.Node;
+import org.jclouds.chef.domain.Resource;
+import org.jclouds.chef.domain.Role;
+import org.jclouds.chef.domain.Sandbox;
+import org.jclouds.chef.domain.SearchResult;
+import org.jclouds.chef.domain.UploadSandbox;
+import org.jclouds.chef.options.CreateClientOptions;
+import org.jclouds.chef.options.SearchOptions;
+import org.jclouds.io.Payload;
+import org.jclouds.lifecycle.Closer;
+import org.jclouds.util.Strings2;
+
+import com.google.common.base.Function;
+
+/**
+ * In-memory chef simulator.
+ */
+public class TransientChefApi implements ChefApi {
+ @Singleton
+ private static class StorageMetadataToName implements Function<PageSet<? extends StorageMetadata>, Set<String>> {
+ @Override
+ public Set<String> apply(PageSet<? extends StorageMetadata> from) {
+ return newLinkedHashSet(transform(from, new Function<StorageMetadata, String>() {
+
+ @Override
+ public String apply(StorageMetadata from) {
+ return from.getName();
+ }
+ }));
+ }
+ }
+
+ @Singleton
+ private static class BlobToDatabagItem implements Function<Blob, DatabagItem> {
+ @Override
+ public DatabagItem apply(Blob from) {
+ try {
+ return from == null ? null : new DatabagItem(from.getMetadata().getName(), Strings2.toStringAndClose(from
+ .getPayload().getInput()));
+ } catch (IOException e) {
+ propagate(e);
+ return null;
+ }
+ }
+ }
+
+ private final LocalBlobStore databags;
+ private final BlobToDatabagItem blobToDatabagItem;
+ private final StorageMetadataToName storageMetadataToName;
+ private final Closer closer;
+
+ @Inject
+ TransientChefApi(@Named("databags") LocalBlobStore databags, StorageMetadataToName storageMetadataToName,
+ BlobToDatabagItem blobToDatabagItem, Closer closer) {
+ this.databags = checkNotNull(databags, "databags");
+ this.storageMetadataToName = checkNotNull(storageMetadataToName, "storageMetadataToName");
+ this.blobToDatabagItem = checkNotNull(blobToDatabagItem, "blobToDatabagItem");
+ this.closer = checkNotNull(closer, "closer");
+ }
+
+ @Override
+ public Sandbox commitSandbox(String id, boolean isCompleted) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Client createClient(String clientName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Client createClient(String clientName, CreateClientOptions options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createDatabag(String databagName) {
+ databags.createContainerInLocation(null, databagName);
+ }
+
+ @Override
+ public DatabagItem createDatabagItem(String databagName, DatabagItem databagItem) {
+ Blob blob = databags.blobBuilder(databagItem.getId()).payload(databagItem.toString()).build();
+ databags.putBlob(databagName, blob);
+ return databagItem;
+ }
+
+ @Override
+ public void createNode(Node node) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createRole(Role role) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Client deleteClient(String clientName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CookbookVersion deleteCookbook(String cookbookName, String version) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void deleteDatabag(String databagName) {
+ databags.deleteContainer(databagName);
+ }
+
+ @Override
+ public DatabagItem deleteDatabagItem(String databagName, String databagItemId) {
+ DatabagItem item = blobToDatabagItem.apply(databags.getBlob(databagName, databagItemId));
+ databags.removeBlob(databagName, databagItemId);
+ return item;
+ }
+
+ @Override
+ public Node deleteNode(String nodeName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Role deleteRole(String rolename) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Client generateKeyForClient(String clientName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Client getClient(String clientName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CookbookVersion getCookbook(String cookbookName, String version) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DatabagItem getDatabagItem(String databagName, String databagItemId) {
+ return blobToDatabagItem.apply(databags.getBlob(databagName, databagItemId));
+ }
+
+ @Override
+ public Node getNode(String nodeName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Role getRole(String roleName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public UploadSandbox createUploadSandboxForChecksums(Set<List<Byte>> md5s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listVersionsOfCookbook(String cookbookName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listClients() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listCookbooks() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listDatabagItems(String databagName) {
+ return storageMetadataToName.apply(databags.list(databagName));
+ }
+
+ @Override
+ public Set<String> listDatabags() {
+ return storageMetadataToName.apply(databags.list());
+ }
+
+ @Override
+ public Set<String> listNodes() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listRoles() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listSearchIndexes() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Client> searchClients() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Client> searchClients(SearchOptions options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends DatabagItem> searchDatabagItems(String databagName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends DatabagItem> searchDatabagItems(String databagName, SearchOptions options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Node> searchNodes() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Node> searchNodes(SearchOptions options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Role> searchRoles() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Role> searchRoles(SearchOptions options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CookbookVersion updateCookbook(String cookbookName, String version, CookbookVersion cookbook) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DatabagItem updateDatabagItem(String databagName, DatabagItem item) {
+ return createDatabagItem(databagName, item);
+ }
+
+ @Override
+ public Node updateNode(Node node) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Role updateRole(Role role) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void uploadContent(URI location, Payload content) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public InputStream getResourceContents(Resource resource) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listEnvironments() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createEnvironment(Environment environment) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Environment deleteEnvironment(String environmentName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Environment getEnvironment(String environmentName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Environment updateEnvironment(Environment environment) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<CookbookDefinition> listCookbooksInEnvironment(String environmentName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<CookbookDefinition> listCookbooksInEnvironment(String environmentName, String numVersions) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CookbookDefinition getCookbookInEnvironment(String environmentName, String cookbookName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CookbookDefinition getCookbookInEnvironment(String environmentName, String cookbookName, String numVersions) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Environment> searchEnvironments() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SearchResult<? extends Environment> searchEnvironments(SearchOptions options) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listRecipesInEnvironment(String environmentName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> listNodesInEnvironment(String environmentName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void close() throws IOException {
+ closer.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApiMetadata.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApiMetadata.java b/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApiMetadata.java
new file mode 100644
index 0000000..c485080
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/test/TransientChefApiMetadata.java
@@ -0,0 +1,75 @@
+/*
+ * 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.test;
+
+import java.net.URI;
+
+import org.jclouds.chef.ChefApiMetadata;
+import org.jclouds.chef.config.ChefBootstrapModule;
+import org.jclouds.chef.config.ChefParserModule;
+import org.jclouds.chef.test.config.TransientChefApiModule;
+import org.jclouds.ohai.config.JMXOhaiModule;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for the Amazon-specific Chef API
+ */
+public class TransientChefApiMetadata extends BaseHttpApiMetadata<TransientChefApi> {
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder().fromApiMetadata(this);
+ }
+
+ public TransientChefApiMetadata() {
+ this(new Builder());
+ }
+
+ protected TransientChefApiMetadata(Builder builder) {
+ super(builder);
+ }
+
+ public static class Builder extends BaseHttpApiMetadata.Builder<TransientChefApi, Builder> {
+ protected Builder() {
+ id("transientchef")
+ .name("In-memory Chef API")
+ .identityName("unused")
+ .defaultIdentity("api")
+ .documentation(URI.create("http://localhost"))
+ .defaultCredential(
+ "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAyb2ZJJqGm0KKR+8nfQJNsSd+F9tXNMV7CfOcW6jsqs8EZgiV\nR09hD1IYOj4YqM0qJONlgyg4xRWewdSG7QTPj1lJpVAida9sXy2+kzyagZA1Am0O\nZcbqb5hoeIDgcX+eDa79s0u0DomjcfO9EKhvHLBz+zM+3QqPRkPV8nYTbfs+HjVz\nzOU6D1B0XR3+IPZZl2AnWs2d0qhnStHcDUvnRVQ0P482YwN9VgceOZtpPz0DCKEJ\n5Tx5STub8k0/zt/VAMHQafLSuQMLd2s4ZLuOZptN//uAsTmxireqd37z+8ZTdBbJ\n8LEpJ+iCXuSfm5aUh7iw6oxvToY2AL53+jK2UQIDAQABAoIBAQDA88B3i/xWn0vX\nBVxFamCYoecuNjGwXXkSyZew616A+EOCu47bh4aTurdFbYL0YFaAtaWvzlaN2eHg\nDb+HDuTefE29+WkcGk6SshPmiz5T0XOCAICWw6wSVDkHmGwS4jZvbAFm7W8nwGk9\nYhxgxFiRngswJZFopOLoF5WXs2td8guIYNslMpo7tu50iFnBHwKO2ZsPAk8t9nnS\nxlDavKruymEmqHCr3+dtio5eaenJcp3fjoXBQOKUk3ipII29XRB8NqeCVV/7Kxwq\nckqOBEbRwBclckyIbD+RiAgKvOelORjEiE9R42vuqvxRA6k9kd9o7utlX0AUtpEn\n3gZc6LepAoGBAP9ael5Y75+sK2JJUNOOhO8ae45cdsilp2yI0X+UBaSuQs2+dyPp\nkpEHAxd4pmmSvn/8c9TlEZhr+qYbABXVPlDncxpIuw2Ajbk7s/S4XaSKsRqpXL57\nzj/QOqLkRk8+OVV9q6lMeQNqLtEj1u6JPviX70Ro+FQtRttNOYbfdP/fAoGBAMpA\nXjR5woV5sUb+REg9vE
uYo8RSyOarxqKFCIXVUNsLOx+22+AK4+CQpbueWN7jotrl\nYD6uT6svWi3AAC7kiY0UI/fjVPRCUi8tVoQUE0TaU5VLITaYOB+W/bBaDE4M9560\n1NuDWO90baA5dfU44iuzva02rGJXK9+nS3o8nk/PAoGBALOL6djnDe4mwAaG6Jco\ncd4xr8jkyPzCRZuyBCSBbwphIUXLc7hDprPky064ncJD1UDmwIdkXd/fpMkg2QmA\n/CUk6LEFjMisqHojOaCL9gQZJPhLN5QUN2x1PJWGjs1vQh8Tkx0iUUCOa8bQPXNR\n+34OTsW6TUna4CSZAycLfhffAoGBAIggVsefBCvuQkF0NeUhmDCRZfhnd8y55RHR\n1HCvqKIlpv+rhcX/zmyBLuteopYyRJRsOiE2FW00i8+rIPRu4Z3Q5nybx7w3PzV9\noHN5R5baE9OyI4KpZWztpYYitZF67NcnAvVULHHOvVJQGnKYfLHJYmrJF7GA1ojM\nAuMdFbjFAoGAPxUhxwFy8gaqBahKUEZn4F81HFP5ihGhkT4QL6AFPO2e+JhIGjuR\n27+85hcFqQ+HHVtFsm81b/a+R7P4UuCRgc8eCjxQMoJ1Xl4n7VbjPbHMnIN0Ryvd\nO4ZpWDWYnCO021JTOUUOJ4J/y0416Bvkw0z59y7sNX7wDBBHHbK/XCc=\n-----END RSA PRIVATE KEY-----\n")
+ .defaultEndpoint("transientchef")
+ .defaultProperties(ChefApiMetadata.defaultProperties())
+ .defaultModules(
+ ImmutableSet.<Class<? extends Module>> of(TransientChefApiModule.class, ChefParserModule.class,
+ ChefBootstrapModule.class, JMXOhaiModule.class));
+ }
+
+ @Override
+ public TransientChefApiMetadata build() {
+ return new TransientChefApiMetadata(this);
+ }
+
+ @Override
+ protected Builder self() {
+ return this;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/test/config/TransientChefApiModule.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/test/config/TransientChefApiModule.java b/apis/chef/src/main/java/org/jclouds/chef/test/config/TransientChefApiModule.java
new file mode 100644
index 0000000..d9eab4d
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/test/config/TransientChefApiModule.java
@@ -0,0 +1,116 @@
+/*
+ * 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.test.config;
+
+import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.util.List;
+
+import javax.inject.Singleton;
+
+import org.jclouds.ContextBuilder;
+import org.jclouds.blobstore.TransientApiMetadata;
+import org.jclouds.blobstore.config.LocalBlobStore;
+import org.jclouds.chef.ChefApi;
+import org.jclouds.chef.config.Validator;
+import org.jclouds.chef.domain.Client;
+import org.jclouds.chef.functions.BootstrapConfigForGroup;
+import org.jclouds.chef.functions.ClientForGroup;
+import org.jclouds.chef.functions.RunListForGroup;
+import org.jclouds.chef.test.TransientChefApi;
+import org.jclouds.concurrent.config.ExecutorServiceModule;
+import org.jclouds.crypto.Crypto;
+import org.jclouds.domain.JsonBall;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.RestModule;
+import org.jclouds.rest.config.SyncToAsyncHttpInvocationModule;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheLoader;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.Provides;
+import com.google.inject.name.Names;
+
+@ConfiguresHttpApi
+public class TransientChefApiModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ install(new RestModule());
+ install(new SyncToAsyncHttpInvocationModule());
+ bind(ChefApi.class).to(TransientChefApi.class);
+ bind(LocalBlobStore.class).annotatedWith(Names.named("databags"))
+ .toInstance(
+ ContextBuilder
+ .newBuilder(new TransientApiMetadata())
+ .modules(
+ ImmutableSet.<Module> of(new ExecutorServiceModule(sameThreadExecutor(),
+ sameThreadExecutor()))).buildInjector().getInstance(LocalBlobStore.class));
+ }
+
+ @Provides
+ @Singleton
+ public Supplier<PrivateKey> supplyKey() {
+ return new Supplier<PrivateKey>() {
+ @Override
+ public PrivateKey get() {
+ return null;
+ }
+ };
+ }
+
+ @Provides
+ @Singleton
+ CacheLoader<String, List<String>> runListForGroup(RunListForGroup runListForGroup) {
+ return CacheLoader.from(runListForGroup);
+ }
+
+ @Provides
+ @Singleton
+ CacheLoader<String, ? extends JsonBall> bootstrapConfigForGroup(BootstrapConfigForGroup bootstrapConfigForGroup) {
+ return CacheLoader.from(bootstrapConfigForGroup);
+ }
+
+ @Provides
+ @Singleton
+ CacheLoader<String, Client> groupToClient(ClientForGroup clientForGroup) {
+ return CacheLoader.from(clientForGroup);
+ }
+
+ @Provides
+ @Singleton
+ @Validator
+ public Optional<String> provideValidatorName(Injector injector) {
+ return Optional.absent();
+ }
+
+ @Provides
+ @Singleton
+ @Validator
+ public Optional<PrivateKey> provideValidatorCredential(Crypto crypto, Injector injector)
+ throws InvalidKeySpecException, IOException {
+ return Optional.absent();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/util/ChefUtils.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/util/ChefUtils.java b/apis/chef/src/main/java/org/jclouds/chef/util/ChefUtils.java
new file mode 100644
index 0000000..3ba0c59
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/util/ChefUtils.java
@@ -0,0 +1,71 @@
+/*
+ * 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.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.jclouds.domain.JsonBall;
+import org.jclouds.ohai.Automatic;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+import com.google.inject.Binder;
+import com.google.inject.TypeLiteral;
+import com.google.inject.multibindings.MapBinder;
+
+public class ChefUtils {
+
+ public static Date fromOhaiTime(JsonBall ohaiDate) {
+ return new Date(Long.parseLong(checkNotNull(ohaiDate, "ohaiDate").toString().replaceAll("\\.[0-9]*$", "")));
+ }
+
+ public static JsonBall toOhaiTime(long millis) {
+ return new JsonBall(millis + "");
+ }
+
+ public static MapBinder<String, Supplier<JsonBall>> ohaiAutomaticAttributeBinder(Binder binder) {
+ MapBinder<String, Supplier<JsonBall>> mapbinder = MapBinder.newMapBinder(binder, new TypeLiteral<String>() {
+ }, new TypeLiteral<Supplier<JsonBall>>() {
+ }, Automatic.class);
+ return mapbinder;
+ }
+
+ /**
+ *
+ * @return NoSuchElementException if no element in the runList is a role.
+ */
+ public static String findRoleInRunList(List<String> runList) {
+ final Pattern pattern = Pattern.compile("^role\\[(.*)\\]$");
+ String roleToParse = Iterables.find(runList, new Predicate<String>() {
+
+ @Override
+ public boolean apply(String input) {
+ return pattern.matcher(input).matches();
+ }
+
+ });
+ Matcher matcher = pattern.matcher(roleToParse);
+ matcher.find();
+ return matcher.group(1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/util/CollectionUtils.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/util/CollectionUtils.java b/apis/chef/src/main/java/org/jclouds/chef/util/CollectionUtils.java
new file mode 100644
index 0000000..cabfbde
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/util/CollectionUtils.java
@@ -0,0 +1,69 @@
+/*
+ * 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.util;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Utility methods to work with collections.
+ */
+public class CollectionUtils {
+
+ /**
+ * Creates an immutable list with the elements of the given list. If the
+ * input list is <code>null</code>, it returns an empty list.
+ *
+ * @param input
+ * The list used to build the immutable one.
+ * @return An immutable list with the elements of the given list.
+ */
+ public static <T> ImmutableList<T> copyOfOrEmpty(@Nullable List<T> input) {
+ return input == null ? ImmutableList.<T> of() : ImmutableList.copyOf(input);
+ }
+
+ /**
+ * Creates an immutable set with the elements of the given set. If the input
+ * set is <code>null</code>, it returns an empty set.
+ *
+ * @param input
+ * The set used to build the immutable one.
+ * @return An immutable set with the elements of the given set.
+ */
+ public static <T> ImmutableSet<T> copyOfOrEmpty(@Nullable Set<T> input) {
+ return input == null ? ImmutableSet.<T> of() : ImmutableSet.copyOf(input);
+ }
+
+ /**
+ * Creates an immutable map with the elements of the given map. If the input
+ * map is <code>null</code>, it returns an empty map.
+ *
+ * @param input
+ * The map used to build the immutable one.
+ * @return An immutable map with the elements of the given map.
+ */
+ public static <K, V> ImmutableMap<K, V> copyOfOrEmpty(@Nullable Map<K, V> input) {
+ return input == null ? ImmutableMap.<K, V> of() : ImmutableMap.copyOf(input);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/util/RunListBuilder.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/chef/util/RunListBuilder.java b/apis/chef/src/main/java/org/jclouds/chef/util/RunListBuilder.java
new file mode 100644
index 0000000..27cc377
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/chef/util/RunListBuilder.java
@@ -0,0 +1,83 @@
+/*
+ * 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.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.addAll;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Lists.transform;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * builds a run list in the correct syntax for chef.
+ */
+public class RunListBuilder {
+ private List<String> list = newArrayList();
+
+ /**
+ * Add the following recipe to the run list
+ */
+ public RunListBuilder addRecipe(String recipe) {
+ return addRecipes(checkNotNull(recipe, "recipe"));
+ }
+
+ /**
+ * Add the following recipes to the run list
+ */
+ public RunListBuilder addRecipes(String... recipes) {
+ addAll(list, transform(Arrays.asList(checkNotNull(recipes, "recipes")), new Function<String, String>() {
+
+ @Override
+ public String apply(String from) {
+ return "recipe[" + from + "]";
+ }
+
+ }));
+ return this;
+ }
+
+ /**
+ * Add the following role to the run list
+ */
+ public RunListBuilder addRole(String role) {
+ return addRoles(checkNotNull(role, "role"));
+ }
+
+ /**
+ * Add the following roles to the run list
+ */
+ public RunListBuilder addRoles(String... roles) {
+ addAll(list, transform(Arrays.asList(checkNotNull(roles, "roles")), new Function<String, String>() {
+
+ @Override
+ public String apply(String from) {
+ return "role[" + from + "]";
+ }
+
+ }));
+ return this;
+ }
+
+ public List<String> build() {
+ return ImmutableList.copyOf(list);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/Automatic.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/ohai/Automatic.java b/apis/chef/src/main/java/org/jclouds/ohai/Automatic.java
new file mode 100644
index 0000000..9b3d134
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/ohai/Automatic.java
@@ -0,0 +1,33 @@
+/*
+ * 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.ohai;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+@Retention(RUNTIME)
+@Target({ TYPE, METHOD, PARAMETER })
+@Qualifier
+public @interface Automatic {
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/AutomaticSupplier.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/ohai/AutomaticSupplier.java b/apis/chef/src/main/java/org/jclouds/ohai/AutomaticSupplier.java
new file mode 100644
index 0000000..681558e
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/ohai/AutomaticSupplier.java
@@ -0,0 +1,48 @@
+/*
+ * 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.ohai;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.domain.JsonBall;
+import org.jclouds.ohai.functions.NestSlashKeys;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.Multimap;
+
+@Singleton
+public class AutomaticSupplier implements Supplier<Map<String, JsonBall>> {
+ private final Multimap<String, Supplier<JsonBall>> autoAttrs;
+ private final NestSlashKeys nester;
+
+ @Inject
+ AutomaticSupplier(@Automatic Multimap<String, Supplier<JsonBall>> autoAttrs, NestSlashKeys nester) {
+ this.autoAttrs = checkNotNull(autoAttrs, "autoAttrs");
+ this.nester = checkNotNull(nester, "nester");
+ }
+
+ @Override
+ public Map<String, JsonBall> get() {
+ return nester.apply(autoAttrs);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/config/ConfiguresOhai.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/ohai/config/ConfiguresOhai.java b/apis/chef/src/main/java/org/jclouds/ohai/config/ConfiguresOhai.java
new file mode 100644
index 0000000..1ca0df4
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/ohai/config/ConfiguresOhai.java
@@ -0,0 +1,28 @@
+/*
+ * 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.ohai.config;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Retention(RUNTIME)
+@Target(TYPE)
+public @interface ConfiguresOhai {
+}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java
----------------------------------------------------------------------
diff --git a/apis/chef/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java b/apis/chef/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java
new file mode 100644
index 0000000..a8d01f7
--- /dev/null
+++ b/apis/chef/src/main/java/org/jclouds/ohai/config/JMXOhaiModule.java
@@ -0,0 +1,48 @@
+/*
+ * 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.ohai.config;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+
+import javax.inject.Singleton;
+
+import org.jclouds.domain.JsonBall;
+import org.jclouds.ohai.suppliers.UptimeSecondsSupplier;
+
+import com.google.common.base.Supplier;
+import com.google.inject.Provides;
+import com.google.inject.multibindings.MapBinder;
+
+/**
+ * Wires the components needed to parse ohai data from a JVM
+ */
+@ConfiguresOhai
+public class JMXOhaiModule extends OhaiModule {
+
+ @Provides
+ @Singleton
+ protected RuntimeMXBean provideRuntimeMXBean() {
+ return ManagementFactory.getRuntimeMXBean();
+ }
+
+ public MapBinder<String, Supplier<JsonBall>> bindOhai() {
+ MapBinder<String, Supplier<JsonBall>> mapBinder = super.bindOhai();
+ mapBinder.addBinding("uptime_seconds").to(UptimeSecondsSupplier.class);
+ return mapBinder;
+ }
+}