http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/BaseChefHttpApiModule.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/BaseChefHttpApiModule.java b/apis/chef/src/main/java/org/jclouds/chef/config/BaseChefHttpApiModule.java new file mode 100644 index 0000000..2fc4201 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/BaseChefHttpApiModule.java @@ -0,0 +1,208 @@ +/* + * 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.config; + +import static com.google.common.base.Suppliers.compose; +import static com.google.common.base.Suppliers.memoizeWithExpiration; +import static com.google.common.base.Throwables.propagate; +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; +import static org.jclouds.chef.config.ChefProperties.CHEF_VALIDATOR_CREDENTIAL; +import static org.jclouds.chef.config.ChefProperties.CHEF_VALIDATOR_NAME; +import static org.jclouds.crypto.Pems.privateKeySpec; + +import java.io.IOException; +import java.security.PrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +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.handlers.ChefApiErrorRetryHandler; +import org.jclouds.chef.handlers.ChefErrorHandler; +import org.jclouds.crypto.Crypto; +import org.jclouds.crypto.Pems; +import org.jclouds.date.DateService; +import org.jclouds.date.TimeStamp; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.JsonBall; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpRetryHandler; +import org.jclouds.http.annotation.ClientError; +import org.jclouds.http.annotation.Redirection; +import org.jclouds.http.annotation.ServerError; +import org.jclouds.rest.ConfiguresHttpApi; +import org.jclouds.rest.config.HttpApiModule; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Supplier; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.io.ByteSource; +import com.google.inject.ConfigurationException; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Provides; +import com.google.inject.name.Names; + +/** + * Configures the Chef connection. + */ +@ConfiguresHttpApi +public abstract class BaseChefHttpApiModule<S> extends HttpApiModule<S> { + + @Provides + @TimeStamp + protected String provideTimeStamp(@TimeStamp Supplier<String> cache) { + return cache.get(); + } + + /** + * borrowing concurrency code to ensure that caching takes place properly + */ + @Provides + @TimeStamp + Supplier<String> provideTimeStampCache(@Named(PROPERTY_SESSION_INTERVAL) long seconds, final DateService dateService) { + return memoizeWithExpiration(new Supplier<String>() { + @Override + public String get() { + return dateService.iso8601SecondsDateFormat(); + } + }, seconds, TimeUnit.SECONDS); + } + + // TODO: potentially change this + @Provides + @Singleton + public Supplier<PrivateKey> supplyKey(final LoadingCache<Credentials, PrivateKey> keyCache, + @org.jclouds.location.Provider final Supplier<Credentials> creds) { + return compose(new Function<Credentials, PrivateKey>() { + @Override + public PrivateKey apply(Credentials in) { + return keyCache.getUnchecked(in); + } + }, creds); + } + + @Provides + @Singleton + LoadingCache<Credentials, PrivateKey> privateKeyCache(PrivateKeyForCredentials loader) { + // throw out the private key related to old credentials + return CacheBuilder.newBuilder().maximumSize(2).build(loader); + } + + /** + * it is relatively expensive to extract a private key from a PEM. cache the + * relationship between current credentials so that the private key is only + * recalculated once. + */ + @VisibleForTesting + @Singleton + private static class PrivateKeyForCredentials extends CacheLoader<Credentials, PrivateKey> { + private final Crypto crypto; + + @Inject + private PrivateKeyForCredentials(Crypto crypto) { + this.crypto = crypto; + } + + @Override + public PrivateKey load(Credentials in) { + try { + return crypto.rsaKeyFactory().generatePrivate( + privateKeySpec(ByteSource.wrap(in.credential.getBytes(Charsets.UTF_8)))); + } catch (InvalidKeySpecException e) { + throw propagate(e); + } catch (IOException e) { + throw propagate(e); + } + } + } + + @Provides + @Singleton + @Validator + public Optional<String> provideValidatorName(Injector injector) { + // Named properties can not be injected as optional here, so let's use the + // injector to bypass it + Key<String> key = Key.get(String.class, Names.named(CHEF_VALIDATOR_NAME)); + try { + return Optional.<String> of(injector.getInstance(key)); + } catch (ConfigurationException ex) { + return Optional.<String> absent(); + } + } + + @Provides + @Singleton + @Validator + public Optional<PrivateKey> provideValidatorCredential(Crypto crypto, Injector injector) + throws InvalidKeySpecException, IOException { + // Named properties can not be injected as optional here, so let's use the + // injector to bypass it + Key<String> key = Key.get(String.class, Names.named(CHEF_VALIDATOR_CREDENTIAL)); + try { + String validatorCredential = injector.getInstance(key); + PrivateKey validatorKey = crypto.rsaKeyFactory().generatePrivate( + Pems.privateKeySpec(ByteSource.wrap(validatorCredential.getBytes(Charsets.UTF_8)))); + return Optional.<PrivateKey> of(validatorKey); + } catch (ConfigurationException ex) { + return Optional.<PrivateKey> absent(); + } + } + + @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); + } + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ChefErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ChefErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ChefErrorHandler.class); + } + + @Override + protected void bindRetryHandlers() { + bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(ChefApiErrorRetryHandler.class); + } + +}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/ChefBootstrapModule.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/ChefBootstrapModule.java b/apis/chef/src/main/java/org/jclouds/chef/config/ChefBootstrapModule.java new file mode 100644 index 0000000..a5fd231 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/ChefBootstrapModule.java @@ -0,0 +1,121 @@ +/* + * 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.config; + +import static org.jclouds.chef.config.ChefProperties.CHEF_GEM_SYSTEM_VERSION; +import static org.jclouds.chef.config.ChefProperties.CHEF_UPDATE_GEMS; +import static org.jclouds.chef.config.ChefProperties.CHEF_UPDATE_GEM_SYSTEM; +import static org.jclouds.chef.config.ChefProperties.CHEF_USE_OMNIBUS; +import static org.jclouds.chef.config.ChefProperties.CHEF_VERSION; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; +import org.jclouds.scriptbuilder.statements.chef.InstallChefGems; +import org.jclouds.scriptbuilder.statements.chef.InstallChefUsingOmnibus; +import org.jclouds.scriptbuilder.statements.ruby.InstallRuby; +import org.jclouds.scriptbuilder.statements.ruby.InstallRubyGems; + +import com.google.common.base.Optional; +import com.google.inject.AbstractModule; +import com.google.inject.Inject; +import com.google.inject.Provides; + +/** + * Provides bootstrap configuration for nodes. + */ +public class ChefBootstrapModule extends AbstractModule { + + @Provides + @Named("installChefGems") + @Singleton + Statement installChefGems(BootstrapProperties bootstrapProperties) { + InstallRubyGems installRubyGems = InstallRubyGems.builder() + .version(bootstrapProperties.gemSystemVersion().orNull()) + .updateSystem(bootstrapProperties.updateGemSystem(), bootstrapProperties.gemSystemVersion().orNull()) + .updateExistingGems(bootstrapProperties.updateGems()) // + .build(); + + Statement installChef = InstallChefGems.builder().version(bootstrapProperties.chefVersion().orNull()).build(); + + return new StatementList(InstallRuby.builder().build(), installRubyGems, installChef); + } + + @Provides + @Named("installChefOmnibus") + @Singleton + Statement installChefUsingOmnibus() { + return new InstallChefUsingOmnibus(); + } + + @Provides + @InstallChef + @Singleton + Statement installChef(BootstrapProperties bootstrapProperties, @Named("installChefGems") Statement installChefGems, + @Named("installChefOmnibus") Statement installChefOmnibus) { + return bootstrapProperties.useOmnibus() ? installChefOmnibus : installChefGems; + } + + @Singleton + private static class BootstrapProperties { + @Named(CHEF_VERSION) + @Inject(optional = true) + private String chefVersionProperty; + + @Named(CHEF_GEM_SYSTEM_VERSION) + @Inject(optional = true) + private String gemSystemVersionProperty; + + @Named(CHEF_UPDATE_GEM_SYSTEM) + @Inject + private String updateGemSystemProeprty; + + @Named(CHEF_UPDATE_GEMS) + @Inject + private String updateGemsProperty; + + @Named(CHEF_USE_OMNIBUS) + @Inject + private String useOmnibus; + + public Optional<String> chefVersion() { + return Optional.fromNullable(chefVersionProperty); + } + + public Optional<String> gemSystemVersion() { + return Optional.fromNullable(gemSystemVersionProperty); + } + + public boolean updateGemSystem() { + return Boolean.parseBoolean(updateGemSystemProeprty); + } + + public boolean updateGems() { + return Boolean.parseBoolean(updateGemsProperty); + } + + public boolean useOmnibus() { + return Boolean.parseBoolean(useOmnibus); + } + } + + @Override + protected void configure() { + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/ChefHttpApiModule.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/ChefHttpApiModule.java b/apis/chef/src/main/java/org/jclouds/chef/config/ChefHttpApiModule.java new file mode 100644 index 0000000..ffd3b0b --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/ChefHttpApiModule.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.chef.config; + +import org.jclouds.chef.ChefApi; +import org.jclouds.rest.ConfiguresHttpApi; + +/** + * Configures the Chef connection. + */ +@ConfiguresHttpApi +public class ChefHttpApiModule extends BaseChefHttpApiModule<ChefApi> { + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/ChefParserModule.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/ChefParserModule.java b/apis/chef/src/main/java/org/jclouds/chef/config/ChefParserModule.java new file mode 100644 index 0000000..c214236 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/ChefParserModule.java @@ -0,0 +1,321 @@ +/* + * 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.config; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Type; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.chef.domain.DatabagItem; +import org.jclouds.chef.functions.ParseCookbookDefinitionFromJson; +import org.jclouds.chef.functions.ParseCookbookVersionsV09FromJson; +import org.jclouds.chef.functions.ParseCookbookVersionsV10FromJson; +import org.jclouds.chef.functions.ParseKeySetFromJson; +import org.jclouds.chef.suppliers.ChefVersionSupplier; +import org.jclouds.crypto.Crypto; +import org.jclouds.crypto.Pems; +import org.jclouds.http.HttpResponse; +import org.jclouds.json.config.GsonModule.DateAdapter; +import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; +import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MapTypeAdapterFactory; +import org.jclouds.json.internal.NullHackJsonLiteralAdapter; + +import com.google.common.base.Charsets; +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.google.common.io.ByteSource; +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSyntaxException; +import com.google.gson.TypeAdapter; +import com.google.gson.internal.JsonReaderInternalAccess; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.google.inject.AbstractModule; +import com.google.inject.ImplementedBy; +import com.google.inject.Provides; + +public class ChefParserModule extends AbstractModule { + @ImplementedBy(PrivateKeyAdapterImpl.class) + public interface PrivateKeyAdapter extends JsonDeserializer<PrivateKey> { + + } + + @Singleton + public static class PrivateKeyAdapterImpl implements PrivateKeyAdapter { + private final Crypto crypto; + + @Inject + PrivateKeyAdapterImpl(Crypto crypto) { + this.crypto = crypto; + } + + @Override + public PrivateKey deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + String keyText = json.getAsString().replaceAll("\\n", "\n"); + try { + return crypto.rsaKeyFactory().generatePrivate( + Pems.privateKeySpec(ByteSource.wrap(keyText.getBytes(Charsets.UTF_8)))); + } catch (UnsupportedEncodingException e) { + Throwables.propagate(e); + return null; + } catch (InvalidKeySpecException e) { + Throwables.propagate(e); + return null; + } catch (IOException e) { + Throwables.propagate(e); + return null; + } + } + } + + @ImplementedBy(PublicKeyAdapterImpl.class) + public interface PublicKeyAdapter extends JsonDeserializer<PublicKey> { + + } + + @Singleton + public static class PublicKeyAdapterImpl implements PublicKeyAdapter { + private final Crypto crypto; + + @Inject + PublicKeyAdapterImpl(Crypto crypto) { + this.crypto = crypto; + } + + @Override + public PublicKey deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + String keyText = json.getAsString().replaceAll("\\n", "\n"); + try { + return crypto.rsaKeyFactory().generatePublic( + Pems.publicKeySpec(ByteSource.wrap(keyText.getBytes(Charsets.UTF_8)))); + } catch (UnsupportedEncodingException e) { + Throwables.propagate(e); + return null; + } catch (InvalidKeySpecException e) { + Throwables.propagate(e); + return null; + } catch (IOException e) { + Throwables.propagate(e); + return null; + } + } + } + + @ImplementedBy(X509CertificateAdapterImpl.class) + public interface X509CertificateAdapter extends JsonDeserializer<X509Certificate> { + + } + + @Singleton + public static class X509CertificateAdapterImpl implements X509CertificateAdapter { + private final Crypto crypto; + + @Inject + X509CertificateAdapterImpl(Crypto crypto) { + this.crypto = crypto; + } + + @Override + public X509Certificate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + String keyText = json.getAsString().replaceAll("\\n", "\n"); + try { + return Pems.x509Certificate(ByteSource.wrap(keyText.getBytes(Charsets.UTF_8)), + crypto.certFactory()); + } catch (UnsupportedEncodingException e) { + Throwables.propagate(e); + return null; + } catch (IOException e) { + Throwables.propagate(e); + return null; + } catch (CertificateException e) { + Throwables.propagate(e); + return null; + } + } + } + + /** + * writes or reads the literal directly + */ + @Singleton + public static class DataBagItemAdapter extends NullHackJsonLiteralAdapter<DatabagItem> { + final Gson gson = new Gson(); + + @Override + protected DatabagItem createJsonLiteralFromRawJson(String text) { + IdHolder idHolder = gson.fromJson(text, IdHolder.class); + checkState(idHolder.id != null, + "databag item must be a json hash ex. {\"id\":\"item1\",\"my_key\":\"my_data\"}; was %s", text); + text = text.replaceFirst(String.format("\\{\"id\"[ ]?:\"%s\",", idHolder.id), "{"); + return new DatabagItem(idHolder.id, text); + } + + @Override + protected String toString(DatabagItem value) { + String text = value.toString(); + + try { + IdHolder idHolder = gson.fromJson(text, IdHolder.class); + if (idHolder.id == null) { + text = text.replaceFirst("\\{", String.format("{\"id\":\"%s\",", value.getId())); + } else { + checkArgument(value.getId().equals(idHolder.id), + "incorrect id in databagItem text, should be %s: was %s", value.getId(), idHolder.id); + } + } catch (JsonSyntaxException e) { + throw new IllegalArgumentException(e); + } + + return text; + } + } + + private static class IdHolder { + private String id; + } + + // The NullFilteringTypeAdapterFactories.MapTypeAdapter class is final. Do + // the same logic here + private static final class KeepLastRepeatedKeyMapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> { + + protected final TypeAdapter<K> keyAdapter; + protected final TypeAdapter<V> valueAdapter; + + protected KeepLastRepeatedKeyMapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) { + this.keyAdapter = keyAdapter; + this.valueAdapter = valueAdapter; + nullSafe(); + } + + public void write(JsonWriter out, Map<K, V> value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + for (Map.Entry<K, V> element : value.entrySet()) { + out.name(String.valueOf(element.getKey())); + valueAdapter.write(out, element.getValue()); + } + out.endObject(); + } + + public Map<K, V> read(JsonReader in) throws IOException { + Map<K, V> result = Maps.newHashMap(); + in.beginObject(); + while (in.hasNext()) { + JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in); + K name = keyAdapter.read(in); + V value = valueAdapter.read(in); + if (value != null) { + // If there are repeated keys, overwrite them to only keep the last one + result.put(name, value); + } + } + in.endObject(); + return ImmutableMap.copyOf(result); + } + + @Override + public int hashCode() { + return Objects.hashCode(keyAdapter, valueAdapter); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + KeepLastRepeatedKeyMapTypeAdapter<?, ?> that = KeepLastRepeatedKeyMapTypeAdapter.class.cast(obj); + return equal(this.keyAdapter, that.keyAdapter) && equal(this.valueAdapter, that.valueAdapter); + } + + @Override + public String toString() { + return toStringHelper(this).add("keyAdapter", keyAdapter).add("valueAdapter", valueAdapter).toString(); + } + } + + public static class KeepLastRepeatedKeyMapTypeAdapterFactory extends MapTypeAdapterFactory { + + public KeepLastRepeatedKeyMapTypeAdapterFactory() { + super(Map.class); + } + + @SuppressWarnings("unchecked") + @Override + protected <K, V, T> TypeAdapter<T> newAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) { + return (TypeAdapter<T>) new KeepLastRepeatedKeyMapTypeAdapter<K, V>(keyAdapter, valueAdapter); + } + } + + @Provides + @Singleton + public Map<Type, Object> provideCustomAdapterBindings(DataBagItemAdapter adapter, PrivateKeyAdapter privateAdapter, + PublicKeyAdapter publicAdapter, X509CertificateAdapter certAdapter) { + return ImmutableMap.<Type, Object> of(DatabagItem.class, adapter, PrivateKey.class, privateAdapter, + PublicKey.class, publicAdapter, X509Certificate.class, certAdapter); + } + + @Provides + @Singleton + @CookbookParser + public Function<HttpResponse, Set<String>> provideCookbookDefinitionAdapter(ChefVersionSupplier chefVersionSupplier, + ParseCookbookDefinitionFromJson v10parser, ParseKeySetFromJson v09parser) { + return chefVersionSupplier.get() >= 10 ? v10parser : v09parser; + } + + @Provides + @Singleton + @CookbookVersionsParser + public Function<HttpResponse, Set<String>> provideCookbookDefinitionAdapter(ChefVersionSupplier chefVersionSupplier, + ParseCookbookVersionsV10FromJson v10parser, ParseCookbookVersionsV09FromJson v09parser) { + return chefVersionSupplier.get() >= 10 ? v10parser : v09parser; + } + + @Override + protected void configure() { + bind(DateAdapter.class).to(Iso8601DateAdapter.class); + bind(MapTypeAdapterFactory.class).to(KeepLastRepeatedKeyMapTypeAdapterFactory.class); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/ChefProperties.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/ChefProperties.java b/apis/chef/src/main/java/org/jclouds/chef/config/ChefProperties.java new file mode 100644 index 0000000..211b5d6 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/ChefProperties.java @@ -0,0 +1,110 @@ +/* + * 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.config; + + +/** + * Configuration properties and constants used in Chef connections. + */ +public interface ChefProperties { + + /** + * The name of the Chef logger. + */ + public static final String CHEF_LOGGER = "jclouds.chef"; + + /** + * Databag that holds chef bootstrap hints, should be a json ball in the + * following format: + * <p> + * {"tag":{"run_list":["recipe[apache2]"]}} + */ + public static final String CHEF_BOOTSTRAP_DATABAG = "chef.bootstrap-databag"; + + /** + * The name of the validator client used to allow nodes to autoregister in + * the Chef server. + * <p> + * This property must be set prior to running the + * {@link ChefService#createBootstrapScriptForGroup(String)} method. + */ + public static final String CHEF_VALIDATOR_NAME = "chef.validator-name"; + + /** + * The credential of the validator client used to allow nodes to autoregister + * in the Chef server. + * <p> + * This property must be set prior to running the + * {@link ChefService#createBootstrapScriptForGroup(String)} method. + */ + public static final String CHEF_VALIDATOR_CREDENTIAL = "chef.validator-credential"; + + /** + * The version of the Chef gem to install when bootstrapping nodes. + * <p> + * If this property is not set, by default the latest available Chef gem will + * be installed. The values can be fixed versions such as '0.10.8' or + * constrained values such as '>= 0.10.8'. + * <p> + * This property must be set prior to running the + * {@link ChefService#createBootstrapScriptForGroup(String)} method. + */ + public static final String CHEF_VERSION = "chef.version"; + + /** + * Boolean property. Default (false). + * <p> + * When bootstrapping a node, forces a gem system update before installing + * the Chef gems. + * <p> + * This property must be set prior to running the + * {@link ChefService#createBootstrapScriptForGroup(String)} method. + */ + public static final String CHEF_UPDATE_GEM_SYSTEM = "chef.update-gem-system"; + + /** + * To be used in conjunction with {@link #CHEF_UPDATE_GEM_SYSTEM}. This + * property will force the version of RubyGems to update the system to. + * <p> + * This property must be set prior to running the + * {@link ChefService#createBootstrapScriptForGroup(String)} method. + */ + public static final String CHEF_GEM_SYSTEM_VERSION = "chef.gem-system-version"; + + /** + * Boolean property. Default (false). + * <p> + * When bootstrapping a node, updates the existing gems before installing + * Chef. + * <p> + * This property must be set prior to running the + * {@link ChefService#createBootstrapScriptForGroup(String)} method. + */ + public static final String CHEF_UPDATE_GEMS = "chef.update-gems"; + + /** + * Boolean property. Default (true). + * <p> + * When bootstrapping a node, install the Chef client using the Omnibus + * installer. + * <p> + * This property must be set prior to running the + * {@link ChefService#createBootstrapScriptForGroup(String)} method. + */ + public static final String CHEF_USE_OMNIBUS = "chef.use-omnibus"; + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/CookbookParser.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/CookbookParser.java b/apis/chef/src/main/java/org/jclouds/chef/config/CookbookParser.java new file mode 100644 index 0000000..34eedde --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/CookbookParser.java @@ -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.config; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Used to configure the cookbook Json parser. + * <p> + * Chef Server version 0.9 and 0.10 return a different Json when rquesting the + * cookbook definitions. This annotation can be used to setup the cookbook + * parser. + */ +@Target({ METHOD, PARAMETER, FIELD }) +@Retention(RUNTIME) +@Qualifier +public @interface CookbookParser { + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/CookbookVersionsParser.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/CookbookVersionsParser.java b/apis/chef/src/main/java/org/jclouds/chef/config/CookbookVersionsParser.java new file mode 100644 index 0000000..c946917 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/CookbookVersionsParser.java @@ -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.config; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Used to configure the cookbook versions Json parser. + * <p> + * Chef Server version 0.9 and 0.10 return a different Json when rquesting the + * cookbook versions. This annotation can be used to setup the cookbook versions + * parser. + */ +@Target({ METHOD, PARAMETER, FIELD }) +@Retention(RUNTIME) +@Qualifier +public @interface CookbookVersionsParser { + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/InstallChef.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/InstallChef.java b/apis/chef/src/main/java/org/jclouds/chef/config/InstallChef.java new file mode 100644 index 0000000..d40ae91 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/InstallChef.java @@ -0,0 +1,37 @@ +/* + * 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.config; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Used to configure the Chef install script. + */ +@Target({ METHOD, PARAMETER, FIELD }) +@Retention(RUNTIME) +@Qualifier +public @interface InstallChef { + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/config/Validator.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/config/Validator.java b/apis/chef/src/main/java/org/jclouds/chef/config/Validator.java new file mode 100644 index 0000000..99825d8 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/config/Validator.java @@ -0,0 +1,40 @@ +/* + * 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.config; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.inject.Qualifier; + +/** + * Used to configure the validator client information. + * <p> + * In a Chef server it must be only one validator client. This client is used by + * new nodes to autoregister themselves in the Chef server. + */ +@Target({ METHOD, PARAMETER, FIELD }) +@Retention(RUNTIME) +@Qualifier +public @interface Validator { + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/domain/Attribute.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/Attribute.java b/apis/chef/src/main/java/org/jclouds/chef/domain/Attribute.java new file mode 100644 index 0000000..34be6b7 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/Attribute.java @@ -0,0 +1,235 @@ +/* + * 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.domain; + +import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.util.List; +import java.util.Set; + +import org.jclouds.domain.JsonBall; +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.gson.annotations.SerializedName; + +/** + * An attribute in a cookbook metadata. + */ +public class Attribute { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String required; + private boolean calculated; + private ImmutableSet.Builder<String> choice = ImmutableSet.builder(); + private JsonBall defaultValue; + private String type; + private ImmutableList.Builder<String> recipes = ImmutableList.builder(); + private String displayName; + private String description; + + public Builder required(String required) { + this.required = checkNotNull(required, "required"); + return this; + } + + public Builder calculated(boolean calculated) { + this.calculated = calculated; + return this; + } + + public Builder choice(String choice) { + this.choice.add(checkNotNull(choice, "choice")); + return this; + } + + public Builder choices(Iterable<String> choices) { + this.choice.addAll(checkNotNull(choices, "choices")); + return this; + } + + public Builder defaultValue(JsonBall defaultValue) { + this.defaultValue = checkNotNull(defaultValue, "defaultValue"); + return this; + } + + public Builder type(String type) { + this.type = checkNotNull(type, "type"); + return this; + } + + public Builder recipe(String recipe) { + this.recipes.add(checkNotNull(recipe, "recipe")); + return this; + } + + public Builder recipes(Iterable<String> recipes) { + this.recipes.addAll(checkNotNull(recipes, "recipes")); + return this; + } + + public Builder displayName(String displayName) { + this.displayName = checkNotNull(displayName, "displayName"); + return this; + } + + public Builder description(String description) { + this.description = checkNotNull(description, "description"); + return this; + } + + public Attribute build() { + return new Attribute(required, calculated, choice.build(), defaultValue, type, recipes.build(), displayName, + description); + } + } + + private final String required; + private final boolean calculated; + private final Set<String> choice; + @SerializedName("default") + private final JsonBall defaultValue; + private final String type; + private final List<String> recipes; + @SerializedName("display_name") + private final String displayName; + private final String description; + + @ConstructorProperties({ "required", "calculated", "choice", "default", "type", "recipes", "display_name", + "description" }) + protected Attribute(String required, boolean calculated, @Nullable Set<String> choice, JsonBall defaultValue, + String type, @Nullable List<String> recipes, String displayName, String description) { + this.required = required; + this.calculated = calculated; + this.choice = copyOfOrEmpty(choice); + this.defaultValue = defaultValue; + this.type = type; + this.recipes = copyOfOrEmpty(recipes); + this.displayName = displayName; + this.description = description; + } + + public String getRequired() { + return required; + } + + public boolean isCalculated() { + return calculated; + } + + public Set<String> getChoice() { + return choice; + } + + public JsonBall getDefaultValue() { + return defaultValue; + } + + public String getType() { + return type; + } + + public List<String> getRecipes() { + return recipes; + } + + public String getDisplayName() { + return displayName; + } + + public String getDescription() { + return description; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (calculated ? 1231 : 1237); + result = prime * result + ((choice == null) ? 0 : choice.hashCode()); + result = prime * result + ((defaultValue == null) ? 0 : defaultValue.hashCode()); + result = prime * result + ((description == null) ? 0 : description.hashCode()); + result = prime * result + ((displayName == null) ? 0 : displayName.hashCode()); + result = prime * result + ((recipes == null) ? 0 : recipes.hashCode()); + result = prime * result + ((required == null) ? 0 : required.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Attribute other = (Attribute) obj; + if (calculated != other.calculated) + return false; + if (choice == null) { + if (other.choice != null) + return false; + } else if (!choice.equals(other.choice)) + return false; + if (defaultValue == null) { + if (other.defaultValue != null) + return false; + } else if (!defaultValue.equals(other.defaultValue)) + return false; + if (description == null) { + if (other.description != null) + return false; + } else if (!description.equals(other.description)) + return false; + if (displayName == null) { + if (other.displayName != null) + return false; + } else if (!displayName.equals(other.displayName)) + return false; + if (recipes == null) { + if (other.recipes != null) + return false; + } else if (!recipes.equals(other.recipes)) + return false; + if (required == null) { + if (other.required != null) + return false; + } else if (!required.equals(other.required)) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equals(other.type)) + return false; + return true; + } + + @Override + public String toString() { + return "Attribute [calculated=" + calculated + ", choice=" + choice + ", defaultValue=" + defaultValue + + ", description=" + description + ", displayName=" + displayName + ", recipes=" + recipes + ", required=" + + required + ", type=" + type + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/domain/BootstrapConfig.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/BootstrapConfig.java b/apis/chef/src/main/java/org/jclouds/chef/domain/BootstrapConfig.java new file mode 100644 index 0000000..c10c150 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/BootstrapConfig.java @@ -0,0 +1,95 @@ +/* + * 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.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; + +import org.jclouds.domain.JsonBall; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +/** + * Configures how the nodes in a group will bootstrap. + * + * @since 1.7 + */ +public class BootstrapConfig { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private ImmutableList.Builder<String> runList = ImmutableList.builder(); + private String environment; + private JsonBall attribtues; + + /** + * Sets the run list that will be executed in the nodes of the group. + */ + public Builder runList(Iterable<String> runList) { + this.runList.addAll(checkNotNull(runList, "runList")); + return this; + } + + /** + * Sets the environment where the nodes in the group will be deployed. + */ + public Builder environment(String environment) { + this.environment = checkNotNull(environment, "environment"); + return this; + } + + /** + * Sets the attributes that will be populated to the deployed nodes. + */ + public Builder attributes(JsonBall attributes) { + this.attribtues = checkNotNull(attributes, "attributes"); + return this; + } + + public BootstrapConfig build() { + return new BootstrapConfig(runList.build(), Optional.fromNullable(environment), + Optional.fromNullable(attribtues)); + } + } + + private final List<String> runList; + private final Optional<String> environment; + private final Optional<JsonBall> attribtues; + + protected BootstrapConfig(List<String> runList, Optional<String> environment, Optional<JsonBall> attribtues) { + this.runList = checkNotNull(runList, "runList"); + this.environment = checkNotNull(environment, "environment"); + this.attribtues = checkNotNull(attribtues, "attributes"); + } + + public List<String> getRunList() { + return runList; + } + + public Optional<String> getEnvironment() { + return environment; + } + + public Optional<JsonBall> getAttribtues() { + return attribtues; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/domain/ChecksumStatus.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/ChecksumStatus.java b/apis/chef/src/main/java/org/jclouds/chef/domain/ChecksumStatus.java new file mode 100644 index 0000000..e5a48ca --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/ChecksumStatus.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.domain; + +import static com.google.common.base.Preconditions.checkNotNull; +import java.beans.ConstructorProperties; +import java.net.URI; + +import com.google.gson.annotations.SerializedName; + +/** + * The checksum of an uploaded resource. + */ +public class ChecksumStatus { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private URI url; + private boolean needsUpload; + + public Builder url(URI url) { + this.url = checkNotNull(url, "url"); + return this; + } + + public Builder needsUpload(boolean needsUpload) { + this.needsUpload = needsUpload; + return this; + } + + public ChecksumStatus build() { + return new ChecksumStatus(url, needsUpload); + } + } + + private final URI url; + @SerializedName("needs_upload") + private final boolean needsUpload; + + @ConstructorProperties({ "url", "needs_upload" }) + protected ChecksumStatus(URI url, boolean needsUpload) { + this.url = url; + this.needsUpload = needsUpload; + } + + public URI getUrl() { + return url; + } + + public boolean needsUpload() { + return needsUpload; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (needsUpload ? 1231 : 1237); + result = prime * result + ((url == null) ? 0 : url.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ChecksumStatus other = (ChecksumStatus) obj; + if (needsUpload != other.needsUpload) + return false; + if (url == null) { + if (other.url != null) + return false; + } else if (!url.equals(other.url)) + return false; + return true; + } + + @Override + public String toString() { + return "ChecksumStatus [needsUpload=" + needsUpload + ", url=" + url + "]"; + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/domain/Client.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/Client.java b/apis/chef/src/main/java/org/jclouds/chef/domain/Client.java new file mode 100644 index 0000000..7335609 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/Client.java @@ -0,0 +1,182 @@ +/* + * 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.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.gson.annotations.SerializedName; + +/** + * Client object. + */ +public class Client { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private X509Certificate certificate; + private PrivateKey privateKey; + private String orgname; + private String clientname; + private String name; + private boolean validator; + + public Builder certificate(X509Certificate certificate) { + this.certificate = checkNotNull(certificate, "certificate"); + return this; + } + + public Builder privateKey(PrivateKey privateKey) { + this.privateKey = checkNotNull(privateKey, "privateKey"); + return this; + } + + public Builder orgname(String orgname) { + this.orgname = checkNotNull(orgname, "orgname"); + return this; + } + + public Builder clientname(String clientname) { + this.clientname = checkNotNull(clientname, "clientname"); + return this; + } + + public Builder name(String name) { + this.name = checkNotNull(name, "name"); + return this; + } + + public Builder isValidator(boolean validator) { + this.validator = validator; + return this; + } + + public Client build() { + return new Client(certificate, orgname, clientname, name, validator, privateKey); + } + } + + private final X509Certificate certificate; + @SerializedName("private_key") + private final PrivateKey privateKey; + private final String orgname; + private final String clientname; + private final String name; + private final boolean validator; + + @ConstructorProperties({ "certificate", "orgname", "clientname", "name", "validator", "private_key" }) + protected Client(X509Certificate certificate, String orgname, String clientname, String name, boolean validator, + @Nullable PrivateKey privateKey) { + this.certificate = certificate; + this.orgname = orgname; + this.clientname = clientname; + this.name = name; + this.validator = validator; + this.privateKey = privateKey; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + public X509Certificate getCertificate() { + return certificate; + } + + public String getOrgname() { + return orgname; + } + + public String getClientname() { + return clientname; + } + + public String getName() { + return name; + } + + public boolean isValidator() { + return validator; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((certificate == null) ? 0 : certificate.hashCode()); + result = prime * result + ((clientname == null) ? 0 : clientname.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((orgname == null) ? 0 : orgname.hashCode()); + result = prime * result + ((privateKey == null) ? 0 : privateKey.hashCode()); + result = prime * result + (validator ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Client other = (Client) obj; + if (certificate == null) { + if (other.certificate != null) + return false; + } else if (!certificate.equals(other.certificate)) + return false; + if (clientname == null) { + if (other.clientname != null) + return false; + } else if (!clientname.equals(other.clientname)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (orgname == null) { + if (other.orgname != null) + return false; + } else if (!orgname.equals(other.orgname)) + return false; + if (privateKey == null) { + if (other.privateKey != null) + return false; + } else if (!privateKey.equals(other.privateKey)) + return false; + if (validator != other.validator) + return false; + return true; + } + + @Override + public String toString() { + return "Client [name=" + name + ", clientname=" + clientname + ", orgname=" + orgname + ", isValidator=" + + validator + ", certificate=" + certificate + ", privateKey=" + (privateKey == null ? "not " : "") + + "present]"; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java b/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java new file mode 100644 index 0000000..17db702 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookDefinition.java @@ -0,0 +1,217 @@ +/* + * 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.domain; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty; + +import java.beans.ConstructorProperties; +import java.net.URI; +import java.util.Set; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.collect.ImmutableSet; + +/** + * Cookbook definition as returned by the Chef server >= 0.10.8. + */ +public class CookbookDefinition { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String name; + private URI url; + private ImmutableSet.Builder<Version> versions = ImmutableSet.builder(); + + public Builder name(String name) { + this.name = checkNotNull(name, "name"); + return this; + } + + public Builder url(URI url) { + this.url = checkNotNull(url, "url"); + return this; + } + + public Builder version(Version version) { + this.versions.add(checkNotNull(version, "version")); + return this; + } + + public Builder versions(Iterable<Version> versions) { + this.versions.addAll(checkNotNull(versions, "versions")); + return this; + } + + public Builder from(CookbookDefinition def) { + this.url = checkNotNull(def.getUrl(), "url"); + this.versions.addAll(checkNotNull(def.getVersions(), "versions")); + this.name = def.getName(); + return this; + } + + public CookbookDefinition build() { + return new CookbookDefinition(name, url, versions.build()); + } + } + + private final String name; + private final URI url; + private final Set<Version> versions; + + @ConstructorProperties({"name", "url", "versions" }) + protected CookbookDefinition(String name, URI url, @Nullable Set<Version> versions) { + this.name = name; + this.url = url; + this.versions = copyOfOrEmpty(versions); + } + + public String getName() { + return name; + } + + public URI getUrl() { + return url; + } + + public Set<Version> getVersions() { + return versions; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((url == null) ? 0 : url.hashCode()); + result = prime * result + ((versions == null) ? 0 : versions.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CookbookDefinition other = (CookbookDefinition) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (url == null) { + if (other.url != null) + return false; + } else if (!url.equals(other.url)) + return false; + if (versions == null) { + if (other.versions != null) + return false; + } else if (!versions.equals(other.versions)) + return false; + return true; + } + + @Override + public String toString() { + return "CookbookDefinition [name=" + name + ", url=" + url + ", versions=" + versions + "]"; + } + + public static class Version { + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private URI url; + private String version; + + public Builder url(URI url) { + this.url = checkNotNull(url, "url"); + return this; + } + + public Builder version(String version) { + this.version = checkNotNull(version, "version"); + return this; + } + + public Version build() { + return new Version(url, version); + } + } + + private final URI url; + private final String version; + + @ConstructorProperties({ "url", "version" }) + protected Version(URI url, String version) { + this.url = url; + this.version = version; + } + + public URI getUrl() { + return url; + } + + public String getVersion() { + return version; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((url == null) ? 0 : url.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Version other = (Version) obj; + if (url == null) { + if (other.url != null) + return false; + } else if (!url.equals(other.url)) + return false; + if (version == null) { + if (other.version != null) + return false; + } else if (!version.equals(other.version)) + return false; + return true; + } + + @Override + public String toString() { + return "Version [url=" + url + ", version=" + version + "]"; + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookVersion.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookVersion.java b/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookVersion.java new file mode 100644 index 0000000..df9bd82 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/CookbookVersion.java @@ -0,0 +1,369 @@ +/* + * 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.domain; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.chef.util.CollectionUtils.copyOfOrEmpty; + +import java.beans.ConstructorProperties; +import java.util.Set; + +import org.jclouds.javax.annotation.Nullable; + +import com.google.common.collect.ImmutableSet; +import com.google.gson.annotations.SerializedName; + +/** + * Cookbook object. + */ +public class CookbookVersion { + public static Builder builder(String name, String version) { + return new Builder(name, version); + } + + public static class Builder { + private String cookbookName; + private ImmutableSet.Builder<Resource> definitions = ImmutableSet.builder(); + private ImmutableSet.Builder<Attribute> attributes = ImmutableSet.builder(); + private ImmutableSet.Builder<Resource> files = ImmutableSet.builder(); + private Metadata metadata = Metadata.builder().build(); + private ImmutableSet.Builder<Resource> providers = ImmutableSet.builder(); + private ImmutableSet.Builder<Resource> resources = ImmutableSet.builder(); + private ImmutableSet.Builder<Resource> templates = ImmutableSet.builder(); + private ImmutableSet.Builder<Resource> libraries = ImmutableSet.builder(); + private String version; + private ImmutableSet.Builder<Resource> recipes = ImmutableSet.builder(); + private ImmutableSet.Builder<Resource> rootFiles = ImmutableSet.builder(); + + public Builder(String name, String version) { + this.cookbookName = checkNotNull(name, "name"); + this.version = checkNotNull(version, "version"); + } + + public Builder cookbookName(String cookbookName) { + this.cookbookName = checkNotNull(cookbookName, "cookbookName"); + return this; + } + + public Builder definition(Resource definition) { + this.definitions.add(checkNotNull(definition, "definition")); + return this; + } + + public Builder definitions(Iterable<Resource> definitions) { + this.definitions.addAll(checkNotNull(definitions, "definitions")); + return this; + } + + public Builder attribute(Attribute attribute) { + this.attributes.add(checkNotNull(attribute, "attribute")); + return this; + } + + public Builder attributes(Iterable<Attribute> attributes) { + this.attributes.addAll(checkNotNull(attributes, "attributes")); + return this; + } + + public Builder file(Resource file) { + this.files.add(checkNotNull(file, "file")); + return this; + } + + public Builder files(Iterable<Resource> files) { + this.files.addAll(checkNotNull(files, "files")); + return this; + } + + public Builder metadata(Metadata metadata) { + this.metadata = checkNotNull(metadata, "metadata"); + return this; + } + + public Builder provider(Resource provider) { + this.providers.add(checkNotNull(provider, "provider")); + return this; + } + + public Builder providers(Iterable<Resource> providers) { + this.providers.addAll(checkNotNull(providers, "providers")); + return this; + } + + public Builder resource(Resource resource) { + this.resources.add(checkNotNull(resource, "resource")); + return this; + } + + public Builder resources(Iterable<Resource> resources) { + this.resources.addAll(checkNotNull(resources, "resources")); + return this; + } + + public Builder template(Resource template) { + this.templates.add(checkNotNull(template, "template")); + return this; + } + + public Builder templates(Iterable<Resource> templates) { + this.templates.addAll(checkNotNull(templates, "templates")); + return this; + } + + public Builder library(Resource library) { + this.libraries.add(checkNotNull(library, "library")); + return this; + } + + public Builder libraries(Iterable<Resource> libraries) { + this.libraries.addAll(checkNotNull(libraries, "libraries")); + return this; + } + + public Builder version(String version) { + this.version = checkNotNull(version, "version"); + return this; + } + + public Builder recipe(Resource recipe) { + this.recipes.add(checkNotNull(recipe, "recipe")); + return this; + } + + public Builder recipes(Iterable<Resource> recipes) { + this.recipes.addAll(checkNotNull(recipes, "recipes")); + return this; + } + + public Builder rootFile(Resource rootFile) { + this.rootFiles.add(checkNotNull(rootFile, "rootFile")); + return this; + } + + public Builder rootFiles(Iterable<Resource> rootFiles) { + this.rootFiles.addAll(checkNotNull(rootFiles, "rootFiles")); + return this; + } + + public CookbookVersion build() { + return new CookbookVersion(checkNotNull(cookbookName, "name") + "-" + checkNotNull(version, "version"), + definitions.build(), attributes.build(), files.build(), metadata, providers.build(), cookbookName, + resources.build(), templates.build(), libraries.build(), version, recipes.build(), rootFiles.build()); + } + } + + private final String name; + private final Set<Resource> definitions; + private final Set<Attribute> attributes; + private final Set<Resource> files; + private final Metadata metadata; + private final Set<Resource> providers; + @SerializedName("cookbook_name") + private final String cookbookName; + private final Set<Resource> resources; + private final Set<Resource> templates; + private final Set<Resource> libraries; + private final String version; + private final Set<Resource> recipes; + @SerializedName("root_files") + private final Set<Resource> rootFiles; + + // internal + @SerializedName("json_class") + private String _jsonClass = "Chef::CookbookVersion"; + @SerializedName("chef_type") + private String _chefType = "cookbook_version"; + + @ConstructorProperties({ "name", "definitions", "attributes", "files", "metadata", "providers", "cookbook_name", + "resources", "templates", "libraries", "version", "recipes", "root_files" }) + protected CookbookVersion(String name, @Nullable Set<Resource> definitions, @Nullable Set<Attribute> attributes, + @Nullable Set<Resource> files, Metadata metadata, @Nullable Set<Resource> providers, String cookbookName, + @Nullable Set<Resource> resources, @Nullable Set<Resource> templates, @Nullable Set<Resource> libraries, + String version, @Nullable Set<Resource> recipes, @Nullable Set<Resource> rootFiles) { + this.name = name; + this.definitions = copyOfOrEmpty(definitions); + this.attributes = copyOfOrEmpty(attributes); + this.files = copyOfOrEmpty(files); + this.metadata = metadata; + this.providers = copyOfOrEmpty(providers); + this.cookbookName = cookbookName; + this.resources = copyOfOrEmpty(resources); + this.templates = copyOfOrEmpty(templates); + this.libraries = copyOfOrEmpty(libraries); + this.version = version; + this.recipes = copyOfOrEmpty(recipes); + this.rootFiles = copyOfOrEmpty(rootFiles); + } + + public String getName() { + return name; + } + + public Set<Resource> getDefinitions() { + return definitions; + } + + public Set<Attribute> getAttributes() { + return attributes; + } + + public Set<Resource> getFiles() { + return files; + } + + public Metadata getMetadata() { + return metadata; + } + + public Set<Resource> getSuppliers() { + return providers; + } + + public String getCookbookName() { + return cookbookName; + } + + public Set<Resource> getResources() { + return resources; + } + + public Set<Resource> getTemplates() { + return templates; + } + + public Set<Resource> getLibraries() { + return libraries; + } + + public String getVersion() { + return version; + } + + public Set<Resource> getRecipes() { + return recipes; + } + + public Set<Resource> getRootFiles() { + return rootFiles; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((attributes == null) ? 0 : attributes.hashCode()); + result = prime * result + ((cookbookName == null) ? 0 : cookbookName.hashCode()); + result = prime * result + ((definitions == null) ? 0 : definitions.hashCode()); + result = prime * result + ((files == null) ? 0 : files.hashCode()); + result = prime * result + ((libraries == null) ? 0 : libraries.hashCode()); + result = prime * result + ((metadata == null) ? 0 : metadata.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((providers == null) ? 0 : providers.hashCode()); + result = prime * result + ((recipes == null) ? 0 : recipes.hashCode()); + result = prime * result + ((resources == null) ? 0 : resources.hashCode()); + result = prime * result + ((rootFiles == null) ? 0 : rootFiles.hashCode()); + result = prime * result + ((templates == null) ? 0 : templates.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CookbookVersion other = (CookbookVersion) obj; + if (attributes == null) { + if (other.attributes != null) + return false; + } else if (!attributes.equals(other.attributes)) + return false; + if (cookbookName == null) { + if (other.cookbookName != null) + return false; + } else if (!cookbookName.equals(other.cookbookName)) + return false; + if (definitions == null) { + if (other.definitions != null) + return false; + } else if (!definitions.equals(other.definitions)) + return false; + if (files == null) { + if (other.files != null) + return false; + } else if (!files.equals(other.files)) + return false; + if (libraries == null) { + if (other.libraries != null) + return false; + } else if (!libraries.equals(other.libraries)) + return false; + if (metadata == null) { + if (other.metadata != null) + return false; + } else if (!metadata.equals(other.metadata)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (providers == null) { + if (other.providers != null) + return false; + } else if (!providers.equals(other.providers)) + return false; + if (recipes == null) { + if (other.recipes != null) + return false; + } else if (!recipes.equals(other.recipes)) + return false; + if (resources == null) { + if (other.resources != null) + return false; + } else if (!resources.equals(other.resources)) + return false; + if (rootFiles == null) { + if (other.rootFiles != null) + return false; + } else if (!rootFiles.equals(other.rootFiles)) + return false; + if (templates == null) { + if (other.templates != null) + return false; + } else if (!templates.equals(other.templates)) + return false; + if (version == null) { + if (other.version != null) + return false; + } else if (!version.equals(other.version)) + return false; + return true; + } + + @Override + public String toString() { + return "Cookbook [attributes=" + attributes + ", cookbookName=" + cookbookName + ", definitions=" + definitions + + ", files=" + files + ", libraries=" + libraries + ", metadata=" + metadata + ", name=" + name + + ", providers=" + providers + ", recipes=" + recipes + ", resources=" + resources + ", rootFiles=" + + rootFiles + ", templates=" + templates + ", version=" + version + "]"; + } + +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/867c7a40/apis/chef/src/main/java/org/jclouds/chef/domain/DatabagItem.java ---------------------------------------------------------------------- diff --git a/apis/chef/src/main/java/org/jclouds/chef/domain/DatabagItem.java b/apis/chef/src/main/java/org/jclouds/chef/domain/DatabagItem.java new file mode 100644 index 0000000..ec68d99 --- /dev/null +++ b/apis/chef/src/main/java/org/jclouds/chef/domain/DatabagItem.java @@ -0,0 +1,63 @@ +/* + * 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.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.jclouds.domain.JsonBall; + +/** + * An item in a data bag. + */ +public class DatabagItem extends JsonBall { + + private final String id; + + public DatabagItem(String id, String value) { + super(value); + this.id = checkNotNull(id, "id"); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + DatabagItem other = (DatabagItem) obj; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + return true; + } + + public String getId() { + return id; + } +}
