http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java new file mode 100644 index 0000000..2f601e9 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/VolumeApi.java @@ -0,0 +1,170 @@ +/* + * 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.cloudstack.features; + +import java.util.Set; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.Fallbacks.VoidOnNotFoundOr404; +import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.Volume; +import org.jclouds.cloudstack.filters.AuthenticationFilter; +import org.jclouds.cloudstack.options.ListVolumesOptions; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.OnlyElement; +import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.Unwrap; + +/** + * Provides synchronous access to cloudstack via their REST API. + * <p/> + * + * @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" /> + */ +@RequestFilters(AuthenticationFilter.class) +@QueryParams(keys = "response", values = "json") +public interface VolumeApi { + /** + * Create a volume with given name and diskOfferingId + * + * @param name name of the volume + * @param diskOfferingId the ID of the disk offering. + * @param zoneId the ID of the availability zone + * @return AsyncCreateResponse job response used to track creation + */ + @Named("listVolumes") + @GET + @QueryParams(keys = { "command", "listAll" }, values = { "listVolumes", "true" }) + @SelectJson("volume") + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<Volume> listVolumes(ListVolumesOptions... options); + + /** + * Create a volume with given name, size and diskOfferingId + * + * @param name name of the volume + * @param diskOfferingId the ID of the disk offering (the offering should have the custom disk size flag set) + * @param zoneId the ID of the availability zone + * @param size the size of volume required (in GB) + * @return AsyncCreateResponse job response used to track creation + */ + @Named("listVolumes") + @GET + @Consumes(MediaType.APPLICATION_JSON) + @QueryParams(keys = { "command", "listAll" }, values = { "listVolumes", "true" }) + @SelectJson("volume") + @OnlyElement + @Fallback(NullOnNotFoundOr404.class) + Volume getVolume(@QueryParam("id") String id); + + + /** + * Create a volume with given name and snapshotId + * + * @param name name of the volume + * @param snapshotId Snapshot id to be used while creating the volume + * @param zoneId the ID of the availability zone + * @return AsyncCreateResponse job response used to track creation + */ + @Named("createVolume") + @GET + @QueryParams(keys = "command", values = "createVolume") + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + AsyncCreateResponse createVolumeFromDiskOfferingInZone(@QueryParam("name") String name, + @QueryParam("diskofferingid") String diskOfferingId, + @QueryParam("zoneid") String zoneId); + + /** + * List volumes + * + * @return volume list, empty if not found + */ + @GET + @QueryParams(keys = "command", values = "createVolume") + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + AsyncCreateResponse createVolumeFromCustomDiskOfferingInZone(@QueryParam("name") String name, + @QueryParam("diskofferingid") String diskOfferingId, + @QueryParam("zoneid") String zoneId, + @QueryParam("size") int size); + + /** + * Get volume by id + * + * @param id the volume id to retrieve + * @return volume or null if not found + */ + @Named("createVolume") + @GET + @QueryParams(keys = "command", values = "createVolume") + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + AsyncCreateResponse createVolumeFromSnapshotInZone(@QueryParam("name") String name, + @QueryParam("snapshotid") String snapshotId, + @QueryParam("zoneid") String zoneId); + + /** + * Deletes a attached disk volume + * + * @param id id of the volume + */ + @Named("attachVolume") + @GET + @QueryParams(keys = "command", values = "attachVolume") + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + AsyncCreateResponse attachVolume(@QueryParam("id") String volumeId, + @QueryParam("virtualmachineid") String virtualMachineId); + + /** + * Attaches a disk volume to a virtual machine. + * + * @param volumeId the ID of the disk volume + * @param virtualMachineId the ID of the virtual machine + * @return AsyncCreateResponse job response used to track creation + */ + @Named("detachVolume") + @GET + @QueryParams(keys = "command", values = "detachVolume") + @Unwrap + @Consumes(MediaType.APPLICATION_JSON) + AsyncCreateResponse detachVolume(@QueryParam("id") String volumeId); + + /** + * Detaches a disk volume to a virtual machine. + * + * @param volumeId the ID of the disk volume + * @return AsyncCreateResponse job response used to track creation + */ + @Named("deleteVolume") + @GET + @QueryParams(keys = "command", values = "deleteVolume") + @Fallback(VoidOnNotFoundOr404.class) + void deleteVolume(@QueryParam("id") String id); + +}
http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.java new file mode 100644 index 0000000..d7e8ff3 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/features/ZoneApi.java @@ -0,0 +1,79 @@ +/* + * 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.cloudstack.features; + +import java.util.Set; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404; +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.cloudstack.domain.Zone; +import org.jclouds.cloudstack.filters.AuthenticationFilter; +import org.jclouds.cloudstack.options.ListZonesOptions; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.OnlyElement; +import org.jclouds.rest.annotations.QueryParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; + +/** + * Provides synchronous access to cloudstack via their REST API. + * <p/> + * + * @see <a href="http://download.cloud.com/releases/2.2.0/api_2.2.12/TOC_User.html" /> + */ +@RequestFilters(AuthenticationFilter.class) +@QueryParams(keys = "response", values = "json") +public interface ZoneApi { + + /** + * Lists zones + * + * @param options + * if present, how to constrain the list. + * @return zones matching query, or empty set, if no zones are found + */ + @Named("listZones") + @GET + @QueryParams(keys = { "command", "listAll" }, values = { "listZones", "true" }) + @SelectJson("zone") + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(EmptySetOnNotFoundOr404.class) + Set<Zone> listZones(ListZonesOptions... options); + + /** + * get a specific zone by id + * + * @param id + * zone to get + * @return zone or null if not found + */ + @Named("listZones") + @GET + @QueryParams(keys = { "command", "listAll" }, values = { "listZones", "true" }) + @SelectJson("zone") + @OnlyElement + @Consumes(MediaType.APPLICATION_JSON) + @Fallback(NullOnNotFoundOr404.class) + Zone getZone(@QueryParam("id") String id); + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java new file mode 100644 index 0000000..f08c0e8 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AddSessionKeyAndJSessionIdToRequest.java @@ -0,0 +1,55 @@ +/* + * 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.cloudstack.filters; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.domain.LoginResponse; +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpRequest.Builder; + +import com.google.common.base.Supplier; +import com.google.common.net.HttpHeaders; + +/** + * + * @see <a href="http://docs.cloud.com/CloudStack_Documentation/Customizing_the_CloudStack_UI#Cross_Site_Request_Forgery_%28CSRF%29" + * /> + */ +@Singleton +public class AddSessionKeyAndJSessionIdToRequest implements AuthenticationFilter { + + private final Supplier<LoginResponse> loginResponseSupplier; + + @Inject + public AddSessionKeyAndJSessionIdToRequest(Supplier<LoginResponse> loginResponseSupplier) { + this.loginResponseSupplier = loginResponseSupplier; + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + LoginResponse loginResponse = loginResponseSupplier.get(); + Builder<?> builder = request.toBuilder(); + builder.replaceHeader(HttpHeaders.COOKIE, "JSESSIONID=" + loginResponse.getJSessionId()); + builder.replaceQueryParam("sessionkey", loginResponse.getSessionKey()); + return builder.build(); + + } + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java new file mode 100644 index 0000000..1e567a6 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/AuthenticationFilter.java @@ -0,0 +1,30 @@ +/* + * 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.cloudstack.filters; + +import org.jclouds.http.HttpRequestFilter; + +import com.google.inject.ImplementedBy; + +/** + * Marker interface that determines how we authenticate http requests in cloudstack. default to sign + * requests as opposed to login. + */ +@ImplementedBy(QuerySigner.class) +public interface AuthenticationFilter extends HttpRequestFilter { + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java new file mode 100644 index 0000000..04610cc --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/filters/QuerySigner.java @@ -0,0 +1,141 @@ +/* + * 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.cloudstack.filters; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; +import static com.google.common.io.BaseEncoding.base64; +import static com.google.common.io.ByteStreams.readBytes; +import static org.jclouds.Constants.LOGGER_SIGNATURE; +import static org.jclouds.crypto.Macs.asByteProcessor; +import static org.jclouds.http.Uris.uriBuilder; +import static org.jclouds.http.utils.Queries.queryParser; +import static org.jclouds.util.Strings2.toInputStream; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.util.Map; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import com.google.common.base.Joiner; +import org.jclouds.crypto.Crypto; +import org.jclouds.domain.Credentials; +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpUtils; +import org.jclouds.http.internal.SignatureWire; +import org.jclouds.location.Provider; +import org.jclouds.logging.Logger; +import org.jclouds.rest.RequestSigner; +import org.jclouds.util.Strings2; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Multimap; +import com.google.common.io.ByteProcessor; + +/** + * + * @see <a href= "http://download.cloud.com/releases/2.2.0/api/user/2.2api_security_details.html" /> + */ +@Singleton +public class QuerySigner implements AuthenticationFilter, RequestSigner { + + private final SignatureWire signatureWire; + private final Supplier<Credentials> creds; + private final Crypto crypto; + private final HttpUtils utils; + + @Resource + @Named(LOGGER_SIGNATURE) + private Logger signatureLog = Logger.NULL; + + @Inject + public QuerySigner(SignatureWire signatureWire, @Provider Supplier<Credentials> creds, Crypto crypto, HttpUtils utils) { + this.signatureWire = signatureWire; + this.creds = creds; + this.crypto = crypto; + this.utils = utils; + } + + public HttpRequest filter(HttpRequest request) throws HttpException { + checkNotNull(request, "request must be present"); + Multimap<String, String> decodedParams = queryParser().apply(request.getEndpoint().getRawQuery()); + addSigningParams(decodedParams); + String stringToSign = createStringToSign(request, decodedParams); + String signature = sign(stringToSign); + addSignature(decodedParams, signature); + request = request.toBuilder().endpoint(uriBuilder(request.getEndpoint()).query(decodedParams).build()).build(); + utils.logRequest(signatureLog, request, "<<"); + return request; + } + + @VisibleForTesting + void addSignature(Multimap<String, String> params, String signature) { + params.replaceValues("signature", ImmutableList.of(signature)); + } + + @VisibleForTesting + public String sign(String toSign) { + String signature; + try { + ByteProcessor<byte[]> hmacSHA1 = asByteProcessor(crypto.hmacSHA1(creds.get().credential.getBytes())); + signature = base64().encode(readBytes(toInputStream(toSign), hmacSHA1)); + if (signatureWire.enabled()) + signatureWire.input(toInputStream(signature)); + return signature; + } catch (InvalidKeyException e) { + throw propagate(e); + } catch (IOException e) { + throw propagate(e); + } + } + + @VisibleForTesting + public String createStringToSign(HttpRequest request, Multimap<String, String> decodedParams) { + utils.logRequest(signatureLog, request, ">>"); + // encode each parameter value first, + ImmutableSortedSet.Builder<String> builder = ImmutableSortedSet.naturalOrder(); + for (Map.Entry<String, String> entry : decodedParams.entries()) + builder.add(entry.getKey() + "=" + Strings2.urlEncode(entry.getValue())); + // then, lower case the entire query string + String stringToSign = Joiner.on('&').join(builder.build()).toLowerCase(); + if (signatureWire.enabled()) + signatureWire.output(stringToSign); + + return stringToSign; + } + + @VisibleForTesting + void addSigningParams(Multimap<String, String> params) { + params.replaceValues("apiKey", ImmutableList.of(creds.get().identity)); + params.removeAll("signature"); + } + + public String createStringToSign(HttpRequest input) { + Multimap<String, String> decodedParams = queryParser().apply(input.getEndpoint().getQuery()); + addSigningParams(decodedParams); + return createStringToSign(input, decodedParams); + } + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.java new file mode 100644 index 0000000..50185ed --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CloudStackFallbacks.java @@ -0,0 +1,52 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.util.concurrent.Futures.immediateFuture; +import static org.jclouds.Fallbacks.valOnNotFoundOr404; +import static org.jclouds.util.Throwables2.getFirstThrowableOfType; + +import org.jclouds.Fallback; + +import com.google.common.util.concurrent.ListenableFuture; + +public final class CloudStackFallbacks { + private CloudStackFallbacks() { + } + + /** + * CloudStack is currently sending 431 errors with the text "Unable to find account owner for ip ". In this case, we + * have to ignore as there's no means for us to avoid the problem, or action to take. + */ + public static final class VoidOnNotFoundOr404OrUnableToFindAccountOwner implements Fallback<Void> { + @Override + public ListenableFuture<Void> create(Throwable t) throws Exception { + return immediateFuture(createOrPropagate(t)); + } + + @Override + public Void createOrPropagate(Throwable t) throws Exception { + IllegalStateException e = getFirstThrowableOfType(checkNotNull(t, "throwable"), IllegalStateException.class); + if (e != null && e.getMessage().indexOf("Unable to find account owner for") != -1) { + return null; + } else { + return valOnNotFoundOr404(null, t); + } + } + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.java new file mode 100644 index 0000000..dd15e19 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateFirewallRulesForIP.java @@ -0,0 +1,90 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.FirewallRule; +import org.jclouds.cloudstack.domain.PublicIPAddress; +import org.jclouds.cloudstack.options.CreateFirewallRuleOptions; +import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; + +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.ImmutableSet.Builder; + +@Singleton +public class CreateFirewallRulesForIP { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final CloudStackApi client; + private final BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult; + private final LoadingCache<String, Set<FirewallRule>> getFirewallRulesByVirtualMachine; + + @Inject + public CreateFirewallRulesForIP(CloudStackApi client, + BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult, + LoadingCache<String, Set<FirewallRule>> getFirewallRulesByVirtualMachine) { + this.client = checkNotNull(client, "client"); + this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult, + "blockUntilJobCompletesAndReturnResult"); + this.getFirewallRulesByVirtualMachine = checkNotNull(getFirewallRulesByVirtualMachine, + "getFirewallRulesByVirtualMachine"); + } + + public Set<FirewallRule> apply(PublicIPAddress ip, Iterable<Integer> ports) { + return apply(ip, "tcp", ports); + } + + public Set<FirewallRule> apply(PublicIPAddress ip, String protocol, Iterable<Integer> ports) { + checkState(ip.getVirtualMachineId() != null, + "ip %s should be static NATed to a virtual machine before applying rules", ip); + if (Iterables.isEmpty(ports)) + return ImmutableSet.<FirewallRule> of(); + Builder<AsyncCreateResponse> responses = ImmutableSet.builder(); + for (int port : ports) { + AsyncCreateResponse response = client.getFirewallApi().createFirewallRuleForIpAndProtocol(ip.getId(), FirewallRule.Protocol.fromValue(protocol), + CreateFirewallRuleOptions.Builder.startPort(port).endPort(port)); + logger.debug(">> creating firewall rule IPAddress(%s) for protocol(%s), port(%s); response(%s)", + ip.getId(), protocol, port, response); + responses.add(response); + } + Builder<FirewallRule> rules = ImmutableSet.builder(); + for (AsyncCreateResponse response : responses.build()) { + FirewallRule rule = blockUntilJobCompletesAndReturnResult.<FirewallRule> apply(response); + rules.add(rule); + getFirewallRulesByVirtualMachine.asMap().put(ip.getVirtualMachineId(), ImmutableSet.of(rule)); + } + return rules.build(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java new file mode 100644 index 0000000..dd09f77 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreatePortForwardingRulesForIP.java @@ -0,0 +1,88 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.IPForwardingRule; +import org.jclouds.cloudstack.domain.PublicIPAddress; +import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; + +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.ImmutableSet.Builder; + +@Singleton +public class CreatePortForwardingRulesForIP { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final CloudStackApi client; + private final BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult; + private final LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRulesByVirtualMachine; + + @Inject + public CreatePortForwardingRulesForIP(CloudStackApi client, + BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult, + LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRulesByVirtualMachine) { + this.client = checkNotNull(client, "client"); + this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult, + "blockUntilJobCompletesAndReturnResult"); + this.getIPForwardingRulesByVirtualMachine = checkNotNull(getIPForwardingRulesByVirtualMachine, + "getIPForwardingRulesByVirtualMachine"); + } + + public Set<IPForwardingRule> apply(PublicIPAddress ip, Iterable<Integer> ports) { + return apply(ip, "tcp", ports); + } + + public Set<IPForwardingRule> apply(PublicIPAddress ip, String protocol, Iterable<Integer> ports) { + checkState(ip.getVirtualMachineId() != null, + "ip %s should be static NATed to a virtual machine before applying rules", ip); + if (Iterables.isEmpty(ports)) + return ImmutableSet.<IPForwardingRule> of(); + Builder<AsyncCreateResponse> responses = ImmutableSet.builder(); + for (int port : ports) { + AsyncCreateResponse response = client.getNATApi().createIPForwardingRule(ip.getId(), protocol, port); + logger.debug(">> creating IP forwarding rule IPAddress(%s) for protocol(%s), port(%s); response(%s)", + ip.getId(), protocol, port, response); + responses.add(response); + } + Builder<IPForwardingRule> rules = ImmutableSet.builder(); + for (AsyncCreateResponse response : responses.build()) { + IPForwardingRule rule = blockUntilJobCompletesAndReturnResult.<IPForwardingRule> apply(response); + rules.add(rule); + getIPForwardingRulesByVirtualMachine.asMap().put(ip.getVirtualMachineId(), ImmutableSet.of(rule)); + } + return rules.build(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java new file mode 100644 index 0000000..8360977 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/CreateSecurityGroupIfNeeded.java @@ -0,0 +1,111 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.cloudstack.predicates.SecurityGroupPredicates.portInRangeForCidr; +import static org.jclouds.cloudstack.predicates.ZonePredicates.supportsSecurityGroups; + +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.domain.SecurityGroup; +import org.jclouds.cloudstack.domain.Zone; +import org.jclouds.cloudstack.domain.ZoneSecurityGroupNamePortsCidrs; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; + +@Singleton +public class CreateSecurityGroupIfNeeded implements Function<ZoneSecurityGroupNamePortsCidrs, SecurityGroup> { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + protected final CloudStackApi client; + protected final Supplier<LoadingCache<String, Zone>> zoneIdToZone; + protected final Predicate<String> jobComplete; + + @Inject + public CreateSecurityGroupIfNeeded(CloudStackApi client, + Predicate<String> jobComplete, + Supplier<LoadingCache<String, Zone>> zoneIdToZone) { + this.client = checkNotNull(client, "client"); + this.jobComplete = checkNotNull(jobComplete, "jobComplete"); + this.zoneIdToZone = zoneIdToZone; + } + + @Override + public SecurityGroup apply(ZoneSecurityGroupNamePortsCidrs input) { + checkNotNull(input, "input"); + + String zoneId = input.getZone(); + Zone zone = zoneIdToZone.get().getUnchecked(zoneId); + + checkArgument(supportsSecurityGroups().apply(zone), + "Security groups are required, but the zone %s does not support security groups", zoneId); + logger.debug(">> creating securityGroup %s", input); + try { + + SecurityGroup securityGroup = client.getSecurityGroupApi().createSecurityGroup(input.getName()); + + logger.debug("<< created securityGroup(%s)", securityGroup); + ImmutableSet<String> cidrs; + if (!input.getCidrs().isEmpty()) { + cidrs = ImmutableSet.copyOf(input.getCidrs()); + } else { + cidrs = ImmutableSet.of("0.0.0.0/0"); + } + for (int port : input.getPorts()) { + authorizeGroupToItselfAndToTCPPortAndCidr(client, securityGroup, port, cidrs); + } + return securityGroup; + } catch (IllegalStateException e) { + logger.trace("<< trying to find securityGroup(%s): %s", input, e.getMessage()); + SecurityGroup group = client.getSecurityGroupApi().getSecurityGroupByName(input.getName()); + logger.debug("<< reused securityGroup(%s)", group.getId()); + return group; + } + } + + private void authorizeGroupToItselfAndToTCPPortAndCidr(CloudStackApi client, + SecurityGroup securityGroup, + int port, + Set<String> cidrs) { + for (String cidr : cidrs) { + logger.debug(">> authorizing securityGroup(%s) permission to %s on port %d", securityGroup, cidr, port); + if (!portInRangeForCidr(port, cidr).apply(securityGroup)) { + jobComplete.apply(client.getSecurityGroupApi().authorizeIngressPortsToCIDRs(securityGroup.getId(), + "TCP", + port, + port, + ImmutableSet.of(cidr))); + logger.debug("<< authorized securityGroup(%s) permission to %s on port %d", securityGroup, cidr, port); + } + } + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java new file mode 100644 index 0000000..cddb19d --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/DateToYyyyMmDd.java @@ -0,0 +1,39 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import com.google.common.base.Function; + +/** + * Convert a Date object into a "yyyy-MM-dd" String + */ +public class DateToYyyyMmDd implements Function<Object, String> { + + public String apply(Object input) { + checkNotNull(input, "input cannot be null"); + checkArgument(input instanceof Date, "input must be a Date"); + + return new SimpleDateFormat("yyyy-MM-dd").format((Date)input); + } + +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.java new file mode 100644 index 0000000..3fc73ab --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetFirewallRulesByVirtualMachine.java @@ -0,0 +1,49 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.cache.CacheLoader; +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.domain.FirewallRule; +import org.jclouds.cloudstack.options.ListFirewallRulesOptions; + +@Singleton +public class GetFirewallRulesByVirtualMachine extends CacheLoader<String, Set<FirewallRule>> { + private final CloudStackApi client; + + @Inject + public GetFirewallRulesByVirtualMachine(CloudStackApi client) { + this.client = checkNotNull(client, "client"); + } + + /** + * @throws org.jclouds.rest.ResourceNotFoundException + * when there is no ip forwarding rule available for the VM + */ + @Override + public Set<FirewallRule> load(String input) { + String publicIPId = client.getVirtualMachineApi().getVirtualMachine(input).getPublicIPId(); + Set<FirewallRule> rules = client.getFirewallApi() + .listFirewallRules(ListFirewallRulesOptions.Builder.ipAddressId(publicIPId)); + return rules != null ? rules : ImmutableSet.<FirewallRule>of(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.java new file mode 100644 index 0000000..02e6fa1 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/GetIPForwardingRulesByVirtualMachine.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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.domain.IPForwardingRule; + +import com.google.common.cache.CacheLoader; + +@Singleton +public class GetIPForwardingRulesByVirtualMachine extends CacheLoader<String, Set<IPForwardingRule>> { + private final CloudStackApi client; + + @Inject + public GetIPForwardingRulesByVirtualMachine(CloudStackApi client) { + this.client = checkNotNull(client, "client"); + } + + /** + * @throws org.jclouds.rest.ResourceNotFoundException + * when there is no ip forwarding rule available for the VM + */ + @Override + public Set<IPForwardingRule> load(String input) { + return client.getNATApi().getIPForwardingRulesForVirtualMachine(input); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.java new file mode 100644 index 0000000..3095729 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobFromHttpResponse.java @@ -0,0 +1,51 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; + +import javax.inject.Singleton; + +import org.jclouds.cloudstack.domain.AsyncJob; +import org.jclouds.domain.JsonBall; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.UnwrapOnlyJsonValue; + +import com.google.common.base.Function; +import com.google.inject.Inject; + +@Singleton +public class ParseAsyncJobFromHttpResponse implements Function<HttpResponse, AsyncJob<?>> { + private final UnwrapOnlyJsonValue<AsyncJob<Map<String, JsonBall>>> parser; + private final ParseTypedAsyncJob parseTyped; + + @Inject + public ParseAsyncJobFromHttpResponse(ParseTypedAsyncJob parseTyped, + UnwrapOnlyJsonValue<AsyncJob<Map<String, JsonBall>>> parser) { + this.parseTyped = checkNotNull(parseTyped, "parseTyped"); + this.parser = checkNotNull(parser, "parser"); + } + + public AsyncJob<?> apply(HttpResponse response) { + checkNotNull(response, "response"); + AsyncJob<Map<String, JsonBall>> toParse = parser.apply(response); + checkNotNull(toParse, "parsed result from %s", response); + return parseTyped.apply(toParse); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.java new file mode 100644 index 0000000..59f479f --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseAsyncJobsFromHttpResponse.java @@ -0,0 +1,58 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; +import java.util.Set; + +import javax.inject.Singleton; + +import org.jclouds.cloudstack.domain.AsyncJob; +import org.jclouds.domain.JsonBall; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.ParseFirstJsonValueNamed; +import org.jclouds.json.internal.GsonWrapper; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; + +@Singleton +public class ParseAsyncJobsFromHttpResponse implements Function<HttpResponse, Set<AsyncJob<?>>> { + private final ParseFirstJsonValueNamed<Set<AsyncJob<Map<String, JsonBall>>>> parser; + private final ParseTypedAsyncJob parseTyped; + + @Inject + public ParseAsyncJobsFromHttpResponse(ParseTypedAsyncJob parseTyped, GsonWrapper gsonView) { + this.parseTyped = checkNotNull(parseTyped, "parseTyped"); + this.parser = new ParseFirstJsonValueNamed<Set<AsyncJob<Map<String, JsonBall>>>>( + checkNotNull(gsonView, "gsonView"), + new TypeLiteral<Set<AsyncJob<Map<String, JsonBall>>>>() { }, + "asyncjobs"); + } + + public Set<AsyncJob<?>> apply(HttpResponse response) { + checkNotNull(response, "response"); + Set<AsyncJob<Map<String, JsonBall>>> toParse = parser.apply(response); + checkNotNull(toParse, "parsed result from %s", response); + return ImmutableSet.copyOf(Iterables.transform(toParse, parseTyped)); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.java new file mode 100644 index 0000000..552a6e8 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseEventTypesFromHttpResponse.java @@ -0,0 +1,79 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Set; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.ParseFirstJsonValueNamed; +import org.jclouds.json.internal.GsonWrapper; + +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSet.Builder; +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; + +@Singleton +public class ParseEventTypesFromHttpResponse implements Function<HttpResponse, Set<String>> { + private final ParseFirstJsonValueNamed<Set<EventType>> parser; + + private static class EventType { + private String name; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EventType that = (EventType) o; + + if (!Objects.equal(name, that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } + } + + @Inject + public ParseEventTypesFromHttpResponse(GsonWrapper gsonView) { + this.parser = new ParseFirstJsonValueNamed<Set<EventType>>(checkNotNull(gsonView, "gsonView"), + new TypeLiteral<Set<EventType>>() { + }, "eventtype"); + } + + public Set<String> apply(HttpResponse response) { + checkNotNull(response, "response"); + Set<EventType> toParse = parser.apply(response); + checkNotNull(toParse, "parsed result from %s", response); + Builder<String> builder = ImmutableSet.builder(); + for (EventType entry : toParse) + builder.add(entry.name); + return builder.build(); + } +} + + http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java new file mode 100644 index 0000000..936e5aa --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameEntryFromHttpResponse.java @@ -0,0 +1,46 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpResponse; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; + +@Singleton +public class ParseIdToNameEntryFromHttpResponse implements Function<HttpResponse, Map.Entry<String, String>> { + private final ParseIdToNameFromHttpResponse parser; + + @Inject + public ParseIdToNameEntryFromHttpResponse(ParseIdToNameFromHttpResponse parser) { + this.parser = checkNotNull(parser, "parser"); + } + + public Map.Entry<String, String> apply(HttpResponse response) { + checkNotNull(response, "response"); + Map<String, String> toParse = parser.apply(response); + checkNotNull(toParse, "parsed result from %s", response); + return Iterables.getFirst(toParse.entrySet(), null); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.java new file mode 100644 index 0000000..d2ba0a7 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseIdToNameFromHttpResponse.java @@ -0,0 +1,80 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; +import java.util.Set; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.ParseFirstJsonValueNamed; +import org.jclouds.json.internal.GsonWrapper; + +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.ImmutableMap.Builder; +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; + +@Singleton +public class ParseIdToNameFromHttpResponse implements Function<HttpResponse, Map<String, String>> { + private final ParseFirstJsonValueNamed<Set<IdName>> parser; + + private static class IdName { + private String id; + private String name; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + IdName that = (IdName) o; + + if (!Objects.equal(id, that.id)) return false; + if (!Objects.equal(name, that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return Objects.hashCode(id, name); + } + } + + @Inject + public ParseIdToNameFromHttpResponse(GsonWrapper gsonView) { + this.parser = new ParseFirstJsonValueNamed<Set<IdName>>(checkNotNull(gsonView, "gsonView"), + new TypeLiteral<Set<IdName>>() { + }, "oscategory"); + } + + public Map<String, String> apply(HttpResponse response) { + checkNotNull(response, "response"); + Set<IdName> toParse = parser.apply(response); + checkNotNull(toParse, "parsed result from %s", response); + Builder<String, String> builder = ImmutableSortedMap.naturalOrder(); + for (IdName entry : toParse) + builder.put(entry.id, entry.name); + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java new file mode 100644 index 0000000..317aa28 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseLoginResponseFromHttpResponse.java @@ -0,0 +1,55 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Iterables.get; +import static com.google.common.collect.Iterables.getOnlyElement; + +import org.jclouds.cloudstack.domain.LoginResponse; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.ParseFirstJsonValueNamed; +import org.jclouds.json.internal.GsonWrapper; + +import com.google.common.base.Function; +import com.google.common.base.Splitter; +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; + +public class ParseLoginResponseFromHttpResponse implements Function<HttpResponse, LoginResponse> { + + private ParseFirstJsonValueNamed<LoginResponse> parser; + + @Inject + ParseLoginResponseFromHttpResponse(GsonWrapper gson) { + this.parser = new ParseFirstJsonValueNamed<LoginResponse>(checkNotNull(gson, "gsonView"), + new TypeLiteral<LoginResponse>(){}, "loginresponse"); + } + + @Override + public LoginResponse apply(HttpResponse response) { + checkNotNull(response, "response"); + + LoginResponse login = parser.apply(response); + checkNotNull(login, "loginResponse"); + + String jSessionId = get(Splitter.on("=").split(get(Splitter.on(";").trimResults().split( + getOnlyElement(response.getHeaders().get("Set-Cookie"))), 0)), 1); + + return LoginResponse.builder().fromLoginResponse(login).jSessionId(jSessionId).build(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.java new file mode 100644 index 0000000..f30c6a4 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseNamesFromHttpResponse.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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Set; + +import javax.inject.Singleton; + +import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.ParseFirstJsonValueNamed; +import org.jclouds.json.internal.GsonWrapper; + +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSet.Builder; +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; + +@Singleton +public class ParseNamesFromHttpResponse implements Function<HttpResponse, Set<String>> { + private final ParseFirstJsonValueNamed<Set<Name>> parser; + + private static class Name { + private String name; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Name that = (Name) o; + + if (!Objects.equal(name, that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } + } + + @Inject + public ParseNamesFromHttpResponse(GsonWrapper gsonView) { + this.parser = new ParseFirstJsonValueNamed<Set<Name>>(checkNotNull(gsonView, "gsonView"), + new TypeLiteral<Set<Name>>() { + }, "hypervisor"); + } + + public Set<String> apply(HttpResponse response) { + checkNotNull(response, "response"); + Set<Name> toParse = parser.apply(response); + checkNotNull(toParse, "parsed result from %s", response); + Builder<String> builder = ImmutableSet.builder(); + for (Name entry : toParse) + builder.add(entry.name); + return builder.build(); + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java new file mode 100644 index 0000000..0082ea8 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ParseTypedAsyncJob.java @@ -0,0 +1,129 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Map; +import java.util.Map.Entry; + +import javax.annotation.Resource; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.domain.Account; +import org.jclouds.cloudstack.domain.AsyncJob; +import org.jclouds.cloudstack.domain.AsyncJobError; +import org.jclouds.cloudstack.domain.FirewallRule; +import org.jclouds.cloudstack.domain.IPForwardingRule; +import org.jclouds.cloudstack.domain.LoadBalancerRule; +import org.jclouds.cloudstack.domain.Network; +import org.jclouds.cloudstack.domain.PortForwardingRule; +import org.jclouds.cloudstack.domain.PublicIPAddress; +import org.jclouds.cloudstack.domain.SecurityGroup; +import org.jclouds.cloudstack.domain.Snapshot; +import org.jclouds.cloudstack.domain.Template; +import org.jclouds.cloudstack.domain.TemplateExtraction; +import org.jclouds.cloudstack.domain.User; +import org.jclouds.cloudstack.domain.VirtualMachine; +import org.jclouds.cloudstack.domain.Volume; +import org.jclouds.cloudstack.domain.AsyncJob.Builder; +import org.jclouds.cloudstack.domain.AsyncJobError.ErrorCode; +import org.jclouds.domain.JsonBall; +import org.jclouds.json.Json; +import org.jclouds.logging.Logger; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.inject.Inject; + +@Singleton +public class ParseTypedAsyncJob implements Function<AsyncJob<Map<String, JsonBall>>, AsyncJob<?>> { + @Resource + protected Logger logger = Logger.NULL; + + @Inject(optional = true) + @VisibleForTesting + @Named("jclouds.cloudstack.jobresult-type-map") + Map<String, Class<?>> typeMap = ImmutableMap.<String, Class<?>>builder() + .put("user", User.class) + .put("account", Account.class) + .put("securitygroup", SecurityGroup.class) + .put("portforwardingrule", PortForwardingRule.class) + .put("ipforwardingrule", IPForwardingRule.class) + .put("firewallrule", FirewallRule.class) + .put("network", Network.class) + .put("ipaddress", PublicIPAddress.class) + .put("virtualmachine", VirtualMachine.class) + .put("loadbalancer", LoadBalancerRule.class) + .put("snapshot", Snapshot.class) + .put("template", Template.class) + .put("volume", Volume.class).build(); + private final Json json; + + @Inject + public ParseTypedAsyncJob(Json json) { + this.json = checkNotNull(json, "json"); + } + + public AsyncJob<?> apply(AsyncJob<Map<String, JsonBall>> toParse) { + AsyncJob<?> result = toParse; + if (toParse.getResult() != null) { + if (toParse.getResult().size() == 1) { + @SuppressWarnings({"unchecked", "rawtypes"}) + Builder<?, Object> builder = AsyncJob.Builder.fromAsyncJobUntyped((AsyncJob) toParse); + if (toParse.getResult().containsKey("success")) { + builder.result(null); + } else { + Entry<String, JsonBall> entry = Iterables.get(toParse.getResult().entrySet(), 0); + if ("template".equals(entry.getKey())) { + // Sometimes Cloudstack will say 'template' and the payload is a Template object. + // Sometimes Cloudstack will say 'template' and the payload is a TemplateExtraction object. + // The 'state' field only exists on TemplateExtraction, so we can test this to work out what we have actually been given. + Template template = json.fromJson(entry.getValue().toString(), Template.class); + TemplateExtraction templateExtraction = json.fromJson(entry.getValue().toString(), TemplateExtraction.class); + boolean isTemplate = Strings.isNullOrEmpty(templateExtraction.getState()); + builder.result(isTemplate ? template : templateExtraction); + } else if (typeMap.containsKey(entry.getKey())) { + builder.result(json.fromJson(entry.getValue().toString(), typeMap.get(entry.getKey()))); + } else { + logger.warn( + "type key %s not configured. please override default for Map<String, Class<?>> bound to name jclouds.cloudstack.jobresult-type-map", + entry.getKey()); + builder.result(entry.getValue().toString()); + } + } + result = builder.build(); + } else if (toParse.getResult().containsKey("errorcode")) { + @SuppressWarnings({"unchecked", "rawtypes"}) + Builder<?, Object> builder = AsyncJob.Builder.fromAsyncJobUntyped((AsyncJob) toParse); + builder.result(null); // avoid classcastexceptions + builder.error(AsyncJobError.builder().errorCode(ErrorCode.fromValue(toParse.getResult().get("errorcode").toString())) + .errorText(toParse.getResult().containsKey("errortext") ? toParse.getResult().get("errortext").toString().replace("\"", "") : null) + .build()); + result = builder.build(); + } else if (toParse.getResult().size() > 1) { + logger.warn("unexpected size of async job result; expecting a map with a single element", + toParse.getResult()); + } + } + return result; + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java new file mode 100644 index 0000000..7ea19b2 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/ReuseOrAssociateNewPublicIPAddress.java @@ -0,0 +1,101 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Predicates.and; +import static com.google.common.collect.Iterables.find; +import static org.jclouds.cloudstack.options.AssociateIPAddressOptions.Builder.networkId; +import static org.jclouds.cloudstack.options.ListPublicIPAddressesOptions.Builder.allocatedOnly; +import static org.jclouds.cloudstack.predicates.PublicIPAddressPredicates.associatedWithNetwork; +import static org.jclouds.cloudstack.predicates.PublicIPAddressPredicates.available; +import static org.jclouds.compute.reference.ComputeServiceConstants.COMPUTE_LOGGER; + +import java.util.NoSuchElementException; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.domain.AsyncCreateResponse; +import org.jclouds.cloudstack.domain.Network; +import org.jclouds.cloudstack.domain.PublicIPAddress; +import org.jclouds.cloudstack.features.AddressApi; +import org.jclouds.cloudstack.strategy.BlockUntilJobCompletesAndReturnResult; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; + +@Singleton +public class ReuseOrAssociateNewPublicIPAddress implements Function<Network, PublicIPAddress> { + private final CloudStackApi client; + private final BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult; + @Resource + @Named(COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + @Inject + public ReuseOrAssociateNewPublicIPAddress(CloudStackApi client, + BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult) { + this.client = checkNotNull(client, "client"); + this.blockUntilJobCompletesAndReturnResult = checkNotNull(blockUntilJobCompletesAndReturnResult, + "blockUntilJobCompletesAndReturnResult"); + } + + /** + * Finds existing addresses who are ready for use and not assigned to a + * machine. + * + * @param networkId + * network id to search + * @param client + * address client + * @return address to use + * @throws NoSuchElementException + * if there's no existing ip address that is free for use + */ + public static PublicIPAddress findAvailableAndAssociatedWithNetwork(String networkId, AddressApi client) { + return find(client.listPublicIPAddresses(allocatedOnly(true).networkId(networkId)), + and(associatedWithNetwork(networkId), available())); + } + + public static PublicIPAddress associateIPAddressInNetwork(Network network, CloudStackApi client, + BlockUntilJobCompletesAndReturnResult blockUntilJobCompletesAndReturnResult) { + AsyncCreateResponse job = client.getAddressApi().associateIPAddressInZone(network.getZoneId(), + networkId(network.getId())); + PublicIPAddress ip = blockUntilJobCompletesAndReturnResult.<PublicIPAddress> apply(job); + assert ip.getZoneId().equals(network.getZoneId()); + return ip; + } + + @Override + public PublicIPAddress apply(Network input) { + try { + logger.debug(">> looking for existing address in network(%s)", input.getId()); + PublicIPAddress returnVal = findAvailableAndAssociatedWithNetwork(input.getId(), client.getAddressApi()); + logger.debug("<< reused address(%s)", returnVal.getId()); + return returnVal; + } catch (NoSuchElementException e) { + logger.debug(">> associating new address in network(%s)", input.getId()); + PublicIPAddress returnVal = associateIPAddressInNetwork(input, client, blockUntilJobCompletesAndReturnResult); + logger.debug("<< associated address(%s)", returnVal.getId()); + return returnVal; + } + } +} http://git-wip-us.apache.org/repos/asf/stratos/blob/86fd5cf2/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java ---------------------------------------------------------------------- diff --git a/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java new file mode 100644 index 0000000..87fc128 --- /dev/null +++ b/dependencies/jclouds/apis/cloudstack/1.8.0-stratos/src/main/java/org/jclouds/cloudstack/functions/StaticNATVirtualMachineInNetwork.java @@ -0,0 +1,78 @@ +/* + * 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.cloudstack.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.cloudstack.CloudStackApi; +import org.jclouds.cloudstack.domain.Network; +import org.jclouds.cloudstack.domain.PublicIPAddress; +import org.jclouds.cloudstack.domain.VirtualMachine; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; +import com.google.inject.assistedinject.Assisted; + +@Singleton +public class StaticNATVirtualMachineInNetwork implements Function<VirtualMachine, PublicIPAddress> { + public interface Factory { + StaticNATVirtualMachineInNetwork create(Network in); + } + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final CloudStackApi client; + private final ReuseOrAssociateNewPublicIPAddress reuseOrAssociate; + private final Network network; + + @Inject + public StaticNATVirtualMachineInNetwork(CloudStackApi client, + ReuseOrAssociateNewPublicIPAddress reuseOrAssociate, @Assisted Network network) { + this.client = checkNotNull(client, "client"); + this.reuseOrAssociate = checkNotNull(reuseOrAssociate, "reuseOrAssociate"); + this.network = checkNotNull(network, "network"); + } + + public PublicIPAddress apply(VirtualMachine vm) { + PublicIPAddress ip; + for (ip = reuseOrAssociate.apply(network); !ip.isStaticNAT() || ip.getVirtualMachineId() != vm.getId(); ip = reuseOrAssociate + .apply(network)) { + // check to see if someone already grabbed this ip + if (ip.getVirtualMachineId() != null && ip.getVirtualMachineId() != vm.getId()) + continue; + try { + logger.debug(">> static NATing IPAddress(%s) to virtualMachine(%s)", ip.getId(), vm.getId()); + client.getNATApi().enableStaticNATForVirtualMachine(vm.getId(), ip.getId()); + ip = client.getAddressApi().getPublicIPAddress(ip.getId()); + if (ip.isStaticNAT() && ip.getVirtualMachineId().equals(vm.getId())) + break; + } catch (IllegalStateException e) { + // very likely an ip conflict, so retry; + } + return ip; + } + return ip; + } +}
