Repository: jclouds-labs Updated Branches: refs/heads/master 8054a5949 -> 6e5082f71
- Adding structure for Dimension Data CloudControl API JClouds implementation - Adding single API for user account retrieval, with mock and live tests - Adding HTTP request filter that adds organization value to API request paths Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs/commit/6e5082f7 Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs/tree/6e5082f7 Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs/diff/6e5082f7 Branch: refs/heads/master Commit: 6e5082f71c6eac9749826b76d011b4770500c023 Parents: 8054a59 Author: John Clarke <[email protected]> Authored: Fri Mar 24 12:14:30 2017 +0000 Committer: Ignasi Barrera <[email protected]> Committed: Fri Mar 24 15:06:08 2017 +0100 ---------------------------------------------------------------------- .../DimensionDataCloudControlApi.java | 28 ++++ .../DimensionDataCloudControlApiMetadata.java | 74 +++++++++ ...mensionDataCloudControlProviderMetadata.java | 75 ++++++++++ .../DimensionDataCloudControlHttpApiModule.java | 59 ++++++++ .../DimensionDataCloudControlParserModule.java | 27 ++++ .../config/OrganisationIdForAccount.java | 43 ++++++ .../cloudcontrol/domain/Account.java | 150 ++++++++++++++++--- .../cloudcontrol/domain/BaseImage.java | 50 +++++++ .../domain/PaginatedCollection.java | 3 +- .../cloudcontrol/domain/RoleType.java | 49 ------ .../cloudcontrol/domain/Roles.java | 59 -------- .../cloudcontrol/domain/Server.java | 6 +- .../cloudcontrol/domain/Status.java | 84 ----------- .../domain/internal/ServerWithExternalIp.java | 54 +++++++ .../cloudcontrol/features/AccountApi.java | 40 +++++ .../filters/OrganisationIdFilter.java | 63 ++++++++ .../DimensionDataCloudControlErrorHandler.java | 76 ++++++++++ .../features/AccountApiLiveTest.java | 48 ++++++ .../features/AccountApiMockTest.java | 48 ++++++ .../filters/OrganisationIdFilterTest.java | 59 ++++++++ ...aseDimensionDataCloudControlApiLiveTest.java | 36 +++++ .../BaseDimensionDataCloudControlMockTest.java | 141 +++++++++++++++++ dimensiondata/src/test/resources/account.json | 26 ++++ 23 files changed, 1080 insertions(+), 218 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.java new file mode 100644 index 0000000..dc87737 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApi.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.dimensiondata.cloudcontrol; + +import org.jclouds.dimensiondata.cloudcontrol.features.AccountApi; +import org.jclouds.rest.annotations.Delegate; + +import java.io.Closeable; + +public interface DimensionDataCloudControlApi extends Closeable { + + @Delegate + AccountApi getAccountApi(); +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApiMetadata.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApiMetadata.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApiMetadata.java new file mode 100644 index 0000000..7a5c8c1 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlApiMetadata.java @@ -0,0 +1,74 @@ +/* + * 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.dimensiondata.cloudcontrol; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; +import org.jclouds.apis.ApiMetadata; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlHttpApiModule; +import org.jclouds.dimensiondata.cloudcontrol.config.DimensionDataCloudControlParserModule; +import org.jclouds.rest.internal.BaseHttpApiMetadata; + +import java.net.URI; + +import static org.jclouds.reflect.Reflection2.typeToken; + +public class DimensionDataCloudControlApiMetadata extends BaseHttpApiMetadata<DimensionDataCloudControlApi> { + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public DimensionDataCloudControlApiMetadata() { + this(new Builder()); + } + + protected DimensionDataCloudControlApiMetadata(Builder builder) { + super(builder); + } + + public static class Builder extends BaseHttpApiMetadata.Builder<DimensionDataCloudControlApi, Builder> { + + protected Builder() { + id("dimensiondata-cloudcontrol").name("DimensionData CloudControl API").identityName("user name") + .credentialName("user password") + .documentation(URI.create("http://www.dimensiondata.com/en-US/Solutions/Cloud")) + .defaultEndpoint("https://api-REGION.dimensiondata.com/").version("2.4") + .defaultProperties(DimensionDataCloudControlApiMetadata.defaultProperties()) + .view(typeToken(ComputeServiceContext.class)).defaultModules( + ImmutableSet.<Class<? extends Module>>builder().add(DimensionDataCloudControlHttpApiModule.class) + .add(DimensionDataCloudControlParserModule.class).build()); + } + + @Override + public DimensionDataCloudControlApiMetadata build() { + return new DimensionDataCloudControlApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + + @Override + public Builder fromApiMetadata(ApiMetadata in) { + return this; + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlProviderMetadata.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlProviderMetadata.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlProviderMetadata.java new file mode 100644 index 0000000..82f8f10 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/DimensionDataCloudControlProviderMetadata.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.dimensiondata.cloudcontrol; + +import com.google.auto.service.AutoService; +import org.jclouds.providers.ProviderMetadata; +import org.jclouds.providers.internal.BaseProviderMetadata; + +import java.net.URI; +import java.util.Properties; + +/** + * Implementation of {@link ProviderMetadata} for DimensionData CloudController. + */ +@AutoService(ProviderMetadata.class) +public class DimensionDataCloudControlProviderMetadata extends BaseProviderMetadata { + + public static Builder builder() { + return new Builder(); + } + + @Override + public Builder toBuilder() { + return builder().fromProviderMetadata(this); + } + + public DimensionDataCloudControlProviderMetadata() { + super(builder()); + } + + public DimensionDataCloudControlProviderMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + Properties properties = DimensionDataCloudControlApiMetadata.defaultProperties(); + return properties; + } + + public static class Builder extends BaseProviderMetadata.Builder { + + protected Builder() { + id("dimensiondata-cloudcontrol").name("DimensionData Cloud Control") + .apiMetadata(new DimensionDataCloudControlApiMetadata()) + .homepage(URI.create("https://na-cloud.dimensiondata.com/")) + .console(URI.create("https://na-cloud.dimensiondata.com/")).endpoint("https://api-na.dimensiondata.com/") + .defaultProperties(DimensionDataCloudControlProviderMetadata.defaultProperties()); + } + + @Override + public DimensionDataCloudControlProviderMetadata build() { + return new DimensionDataCloudControlProviderMetadata(this); + } + + @Override + public Builder fromProviderMetadata(ProviderMetadata in) { + super.fromProviderMetadata(in); + return this; + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlHttpApiModule.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlHttpApiModule.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlHttpApiModule.java new file mode 100644 index 0000000..0c138e8 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlHttpApiModule.java @@ -0,0 +1,59 @@ +/* + * 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.dimensiondata.cloudcontrol.config; + +import com.google.common.base.Supplier; +import com.google.inject.Provides; +import org.jclouds.collect.Memoized; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi; +import org.jclouds.dimensiondata.cloudcontrol.handlers.DimensionDataCloudControlErrorHandler; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.annotation.ClientError; +import org.jclouds.http.annotation.Redirection; +import org.jclouds.http.annotation.ServerError; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ConfiguresHttpApi; +import org.jclouds.rest.config.HttpApiModule; +import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier; + +import javax.inject.Named; +import javax.inject.Singleton; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; + +@ConfiguresHttpApi +public class DimensionDataCloudControlHttpApiModule extends HttpApiModule<DimensionDataCloudControlApi> { + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(DimensionDataCloudControlErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(DimensionDataCloudControlErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(DimensionDataCloudControlErrorHandler.class); + } + + @Provides + @Singleton + @Memoized + public final Supplier<String> getOrganisationIdForAccount(AtomicReference<AuthorizationException> authException, + @Named(PROPERTY_SESSION_INTERVAL) long seconds, DimensionDataCloudControlApi api) { + return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier + .create(authException, new OrganisationIdForAccount(api), seconds, TimeUnit.SECONDS); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlParserModule.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlParserModule.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlParserModule.java new file mode 100644 index 0000000..f5023da --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/DimensionDataCloudControlParserModule.java @@ -0,0 +1,27 @@ +/* + * 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.dimensiondata.cloudcontrol.config; + +import com.google.inject.AbstractModule; + +public class DimensionDataCloudControlParserModule extends AbstractModule { + + @Override + protected void configure() { + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/OrganisationIdForAccount.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/OrganisationIdForAccount.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/OrganisationIdForAccount.java new file mode 100644 index 0000000..728983a --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/config/OrganisationIdForAccount.java @@ -0,0 +1,43 @@ +/* + * 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.dimensiondata.cloudcontrol.config; + +import com.google.common.base.Supplier; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi; +import org.jclouds.dimensiondata.cloudcontrol.domain.Account; +import org.jclouds.dimensiondata.cloudcontrol.features.AccountApi; + +import static com.google.common.base.Preconditions.checkNotNull; + +@Singleton +public class OrganisationIdForAccount implements Supplier<String> { + + private final AccountApi api; + + @Inject + OrganisationIdForAccount(DimensionDataCloudControlApi api) { + this.api = api.getAccountApi(); + } + + @Override + public String get() { + Account account = checkNotNull(api.getMyAccount(), "account"); + return account.organization().id(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Account.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Account.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Account.java index 1149a07..323dbcb 100644 --- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Account.java +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Account.java @@ -17,15 +17,16 @@ package org.jclouds.dimensiondata.cloudcontrol.domain; import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; import org.jclouds.javax.annotation.Nullable; import org.jclouds.json.SerializedNames; +import java.util.List; + @AutoValue public abstract class Account { - public abstract String userName(); - @Nullable - public abstract String password(); + public abstract String userName(); public abstract String fullName(); @@ -36,6 +37,12 @@ public abstract class Account { public abstract String emailAddress(); @Nullable + public abstract List<RoleType> roles(); + + @Nullable + public abstract AccountPhoneNumber phone(); + + @Nullable public abstract String department(); @Nullable @@ -44,36 +51,31 @@ public abstract class Account { @Nullable public abstract String customDefined2(); - public abstract String orgId(); + public abstract AccountOrganization organization(); @Nullable - public abstract Roles roles(); + public abstract String state(); Account() { } - public static Builder builder() { - return new AutoValue_Account.Builder(); + @SerializedNames({ "userName", "fullName", "firstName", "lastName", "emailAddress", "roles", "phone", "department", + "customDefined1", "customDefined2", "organization", "state" }) + public static Account create(String userName, String fullName, String firstName, String lastName, + String emailAddress, List<RoleType> roles, AccountPhoneNumber phone, String department, String customDefined1, + String customDefined2, AccountOrganization organization, String state) { + return builder().userName(userName).fullName(fullName).firstName(firstName).lastName(lastName) + .emailAddress(emailAddress).roles(roles).phone(phone).department(department).customDefined1(customDefined1) + .customDefined2(customDefined2).organization(organization).state(state).build(); } - @SerializedNames({ "userName", "password", "fullName", "firstName", "lastName", "emailAddress", "department", - "customDefined1", "customDefined2", "orgId", "roles" }) - public static Account create(String userName, String password, String fullName, String firstName, String lastName, - String emailAddress, String department, String customDefined1, String customDefined2, String orgId, - Roles roles) { - return builder().userName(userName).password(password).fullName(fullName).firstName(firstName).lastName(lastName) - .emailAddress(emailAddress).department(department).customDefined1(customDefined1) - .customDefined2(customDefined2).orgId(orgId).roles(roles).build(); + public static Builder builder() { + return new AutoValue_Account.Builder(); } - public abstract Builder toBuilder(); - @AutoValue.Builder public abstract static class Builder { - - public abstract Builder userName(String userName); - - public abstract Builder password(String password); + public abstract Builder userName(String username); public abstract Builder fullName(String fullName); @@ -83,17 +85,117 @@ public abstract class Account { public abstract Builder emailAddress(String emailAddress); + public abstract Builder roles(List<RoleType> roles); + + public abstract Builder phone(AccountPhoneNumber phone); + public abstract Builder department(String department); public abstract Builder customDefined1(String customDefined1); public abstract Builder customDefined2(String customDefined2); - public abstract Builder orgId(String orgId); + public abstract Builder organization(AccountOrganization organization); + + public abstract Builder state(String state); + + abstract Account autoBuild(); + + abstract List<RoleType> roles(); - public abstract Builder roles(Roles roles); + public Account build() { + roles(roles() != null ? ImmutableList.copyOf(roles()) : null); + return autoBuild(); + } - public abstract Account build(); } + @AutoValue + public abstract static class AccountOrganization { + + public abstract String id(); + + public abstract String name(); + + public abstract String homeGeoName(); + + public abstract String homeGeoApiHost(); + + public abstract String homeGeoId(); + + @SerializedNames({ "id", "name", "homeGeoName", "homeGeoApiHost", "homeGeoId" }) + public static AccountOrganization create(String id, String name, String homeGeoName, String homeGeoApiHost, + String homeGeoId) { + return builder().id(id).name(name).homeGeoName(homeGeoName).homeGeoApiHost(homeGeoApiHost).homeGeoId(homeGeoId) + .build(); + } + + public static Builder builder() { + return new AutoValue_Account_AccountOrganization.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder id(String id); + + public abstract Builder name(String name); + + public abstract Builder homeGeoName(String homeGeoName); + + public abstract Builder homeGeoApiHost(String homeGeoApiHost); + + public abstract Builder homeGeoId(String homeGeoId); + + public abstract AccountOrganization build(); + } + } + + @AutoValue + public abstract static class AccountPhoneNumber { + + public abstract String countryCode(); + + public abstract String number(); + + @SerializedNames({ "countryCode", "number" }) + public static AccountPhoneNumber create(String countryCode, String number) { + return builder().countryCode(countryCode).number(number).build(); + } + + public static Builder builder() { + return new AutoValue_Account_AccountPhoneNumber.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder countryCode(String countryCode); + + public abstract Builder number(String number); + + public abstract AccountPhoneNumber build(); + } + + } + + @AutoValue + public abstract static class RoleType { + + public abstract String name(); + + @SerializedNames({ "role" }) + public static RoleType create(String name) { + return builder().name(name).build(); + } + + public static Builder builder() { + return new AutoValue_Account_RoleType.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder name(String name); + + public abstract RoleType build(); + } + } } http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/BaseImage.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/BaseImage.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/BaseImage.java new file mode 100644 index 0000000..fc3c57b --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/BaseImage.java @@ -0,0 +1,50 @@ +/* + * 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.dimensiondata.cloudcontrol.domain; + +import java.util.Date; +import java.util.List; + +public abstract class BaseImage { + public static final String IMAGE_TYPE_METADATA_KEY = "IMAGE_TYPE"; + public static final String OS_FAMILY_METADATA_KEY = "OS_FAMILY"; + + public static final String OS_FAMILY_UNIX = "UNIX"; + public static final String OS_FAMILY_WINDOWS = "WINDOWS"; + + public String type; + + public abstract String id(); + + public abstract String datacenterId(); + + public abstract String name(); + + public abstract String description(); + + public abstract OperatingSystem operatingSystem(); + + public abstract CPU cpu(); + + public abstract Integer memoryGb(); + + public abstract List<Disk> disk(); + + public abstract List<Object> softwareLabel(); + + public abstract Date createTime(); +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/PaginatedCollection.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/PaginatedCollection.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/PaginatedCollection.java index f8876cc..d8eca4d 100644 --- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/PaginatedCollection.java +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/PaginatedCollection.java @@ -87,8 +87,9 @@ public class PaginatedCollection<T> extends IterableWithMarker<T> { @Override public Optional<Object> nextMarker() { - if (totalCount < pageSize) + if (totalCount < pageSize) { return Optional.absent(); + } if ((float) pageNumber < ((float) totalCount / (float) pageSize)) { return Optional.of(toPaginationOptions(pageNumber + 1)); http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/RoleType.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/RoleType.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/RoleType.java deleted file mode 100644 index cad05ad..0000000 --- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/RoleType.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.dimensiondata.cloudcontrol.domain; - -import com.google.auto.value.AutoValue; -import org.jclouds.json.SerializedNames; - -@AutoValue -public abstract class RoleType { - public abstract String name(); - - RoleType() { - } - - public static Builder builder() { - return new AutoValue_RoleType.Builder(); - } - - @SerializedNames({ "role" }) - public static RoleType create(String name) { - return builder().name(name).build(); - } - - public abstract Builder toBuilder(); - - @AutoValue.Builder - public abstract static class Builder { - - public abstract Builder name(String name); - - public abstract RoleType build(); - } - -} - http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Roles.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Roles.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Roles.java deleted file mode 100644 index 0471922..0000000 --- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Roles.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.dimensiondata.cloudcontrol.domain; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; -import org.jclouds.json.SerializedNames; - -import java.util.List; - -@AutoValue -public abstract class Roles { - public abstract List<RoleType> role(); - - Roles() { - } - - public static Builder builder() { - return new AutoValue_Roles.Builder(); - } - - @SerializedNames({ "role" }) - public static Roles create(List<RoleType> role) { - return builder().role(role).build(); - } - - public abstract Builder toBuilder(); - - @AutoValue.Builder - public abstract static class Builder { - - public abstract Builder role(List<RoleType> role); - - abstract Roles autoBuild(); - - abstract List<RoleType> role(); - - public Roles build() { - role(role() != null ? ImmutableList.copyOf(role()) : ImmutableList.<RoleType>of()); - return autoBuild(); - } - } - -} - http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java index 96760d9..9be5f33 100644 --- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Server.java @@ -31,7 +31,7 @@ import static com.google.common.base.Preconditions.checkNotNull; public abstract class Server { public enum State { - NORMAL, PENDING_DELETE, DELETED, UNRECOGNIZED; + NORMAL, FAILED_ADD, FAILED_CHANGE, FAILED_DELETE, PENDING_DELETE, DELETED, UNRECOGNIZED; @Override public String toString() { @@ -45,6 +45,10 @@ public abstract class Server { return UNRECOGNIZED; } } + + public boolean isFailed() { + return this == FAILED_ADD || this == FAILED_CHANGE || this == FAILED_DELETE; + } } Server() { http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Status.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Status.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Status.java deleted file mode 100644 index 4027943..0000000 --- a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/Status.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.dimensiondata.cloudcontrol.domain; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; -import org.jclouds.javax.annotation.Nullable; -import org.jclouds.json.SerializedNames; - -import java.util.List; - -/** - * - */ -@AutoValue -public abstract class Status { - - public enum ResultType { - ERROR, SUCCESS, WARNING - } - - Status() { - } - - public abstract ResultType result(); - - public abstract String resultDetail(); - - public abstract String resultCode(); - - public abstract String operation(); - - @Nullable - public abstract List<AdditionalInformationType> additionalInformation(); - - @SerializedNames({ "result", "resultDetail", "resultCode", "additionalInformation" }) - public static Status create(ResultType result, String resultDetail, String resultCode, - List<AdditionalInformationType> additionalInformation, String operation) { - return builder().result(result).resultDetail(resultDetail).resultCode(resultCode) - .additionalInformation(additionalInformation).operation(operation).build(); - } - - public abstract Builder toBuilder(); - - @AutoValue.Builder - public abstract static class Builder { - public abstract Builder result(ResultType result); - - public abstract Builder resultDetail(String result); - - public abstract Builder resultCode(String resultCode); - - public abstract Builder additionalInformation(List<AdditionalInformationType> additionalInformation); - - public abstract Builder operation(String operation); - - abstract Status autoBuild(); - - abstract List<AdditionalInformationType> additionalInformation(); - - public Status build() { - additionalInformation(additionalInformation() != null ? ImmutableList.copyOf(additionalInformation()) : null); - return autoBuild(); - } - } - - public static Builder builder() { - return new AutoValue_Status.Builder(); - } -} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/internal/ServerWithExternalIp.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/internal/ServerWithExternalIp.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/internal/ServerWithExternalIp.java new file mode 100644 index 0000000..cb2db3d --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/domain/internal/ServerWithExternalIp.java @@ -0,0 +1,54 @@ +/* + * 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.dimensiondata.cloudcontrol.domain.internal; + +import com.google.auto.value.AutoValue; +import org.jclouds.dimensiondata.cloudcontrol.domain.Server; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +@AutoValue +public abstract class ServerWithExternalIp { + + ServerWithExternalIp() { + } + + public static Builder builder() { + return new AutoValue_ServerWithExternalIp.Builder(); + } + + public abstract Server server(); + + @Nullable + public abstract String externalIp(); + + @SerializedNames({ "server", "externalIp" }) + public static ServerWithExternalIp create(Server server, String externalIp) { + return builder().server(server).externalIp(externalIp).build(); + } + + public abstract Builder toBuilder(); + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder server(Server server); + + public abstract Builder externalIp(String externalIp); + + public abstract ServerWithExternalIp build(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApi.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApi.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApi.java new file mode 100644 index 0000000..d3f782e --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApi.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.dimensiondata.cloudcontrol.features; + +import org.jclouds.Fallbacks; +import org.jclouds.dimensiondata.cloudcontrol.domain.Account; +import org.jclouds.http.filters.BasicAuthentication; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import java.io.Closeable; + +@RequestFilters({ BasicAuthentication.class }) +@Consumes("application/json") +@Path("/caas/{jclouds.api-version}/user") +public interface AccountApi extends Closeable { + @Named("myuser:get") + @Path("/myUser") + @GET + @Fallback(Fallbacks.NullOnNotFoundOr404.class) + Account getMyAccount(); +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilter.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilter.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilter.java new file mode 100644 index 0000000..cf1ec1b --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilter.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.dimensiondata.cloudcontrol.filters; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.jclouds.collect.Memoized; +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpRequestFilter; + +import java.util.List; + +/** + * Accepts requests and modifies the endpoint path so that it is injected with the organisation id. + * Handles both oec and caas based URLs. + */ +@Singleton +public class OrganisationIdFilter implements HttpRequestFilter { + + private static final int ORGANIZATION_ID_INDEX = 3; + private final Supplier<String> organisationIdSupplier; + + @Inject + OrganisationIdFilter(@Memoized Supplier<String> organisationIdSupplier) { + this.organisationIdSupplier = organisationIdSupplier; + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + return request.toBuilder().replacePath(injectOrganisationId(request.getEndpoint().getPath())).build(); + } + + @VisibleForTesting + String injectOrganisationId(String path) { + String organisationId = organisationIdSupplier.get(); + List<String> list = Lists.newArrayList(Splitter.on("/").split(path)); + if (list.size() > ORGANIZATION_ID_INDEX && !list.get(ORGANIZATION_ID_INDEX).equals(organisationId)) { + list.add(ORGANIZATION_ID_INDEX, organisationId); + } + return Joiner.on("/").join(list); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/handlers/DimensionDataCloudControlErrorHandler.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/handlers/DimensionDataCloudControlErrorHandler.java b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/handlers/DimensionDataCloudControlErrorHandler.java new file mode 100644 index 0000000..65b28f0 --- /dev/null +++ b/dimensiondata/src/main/java/org/jclouds/dimensiondata/cloudcontrol/handlers/DimensionDataCloudControlErrorHandler.java @@ -0,0 +1,76 @@ +/* + * 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.dimensiondata.cloudcontrol.handlers; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.ResourceAlreadyExistsException; +import org.jclouds.rest.ResourceNotFoundException; + +import javax.inject.Singleton; + +import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; + +/** + * This will org.jclouds.dimensiondata.cloudcontrol.parse and set an appropriate exception on the command object. + */ +@Singleton +public class DimensionDataCloudControlErrorHandler implements HttpErrorHandler { + + public void handleError(HttpCommand command, HttpResponse response) { + // it is important to always read fully and close streams + byte[] data = closeClientButKeepContentStream(response); + String message = data != null ? new String(data) : null; + + Exception exception = message != null ? + new HttpResponseException(command, response, message) : + new HttpResponseException(command, response); + message = message != null ? + message : + String.format("%s -> %s", command.getCurrentRequest().getRequestLine(), response.getStatusLine()); + switch (response.getStatusCode()) { + case 400: + if (message.contains("RESOURCE_NOT_FOUND") || message.contains("OPERATION_NOT_SUPPORTED")) { + exception = new ResourceNotFoundException(message, exception); + } else if (message.contains("INVALID_INPUT_DATA") || message.contains("ORGANIZATION_NOT_VERIFIED") + || message.contains("SYSTEM_ERROR") && !message.contains("RETRYABLE_SYSTEM_ERROR") || message + .contains("CPU_SPEED_NOT_AVAILABLE") || message.contains("CONFIGURATION_NOT_SUPPORTED")) { + exception = new IllegalStateException(message, exception); + } else if (message.contains("RESOURCE_BUSY") || message.contains("UNEXPECTED_ERROR")) { + exception = new ResourceNotFoundException(message, exception); + } else if (message.contains("NAME_NOT_UNIQUE")) { + exception = new ResourceAlreadyExistsException(message, exception); + } + break; + case 401: + exception = new AuthorizationException(message, exception); + break; + case 403: + exception = new AuthorizationException(message, exception); + break; + case 404: + if (!command.getCurrentRequest().getMethod().equals("DELETE")) { + exception = new ResourceNotFoundException(message, exception); + } + break; + } + command.setException(exception); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiLiveTest.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiLiveTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiLiveTest.java new file mode 100644 index 0000000..62bdab1 --- /dev/null +++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiLiveTest.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.dimensiondata.cloudcontrol.features; + +import org.jclouds.dimensiondata.cloudcontrol.domain.Account; +import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlApiLiveTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertNotNull; + +@Test(groups = "live", testName = "AccountApiLiveTest") +public class AccountApiLiveTest extends BaseDimensionDataCloudControlApiLiveTest { + @Test + public void testGetAccount() { + Account account = api().getMyAccount(); + assertNotNull(account); + assertNotNull(account.userName()); + assertNotNull(account.fullName()); + assertNotNull(account.firstName()); + assertNotNull(account.lastName()); + assertNotNull(account.emailAddress()); + assertNotNull(account.organization()); + assertNotNull(account.organization().id()); + assertNotNull(account.organization().name()); + assertNotNull(account.organization().homeGeoName()); + assertNotNull(account.organization().homeGeoApiHost()); + assertNotNull(account.organization().homeGeoId()); + assertNotNull(account.state()); + } + + private AccountApi api() { + return api.getAccountApi(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiMockTest.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiMockTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiMockTest.java new file mode 100644 index 0000000..12da0ba --- /dev/null +++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/features/AccountApiMockTest.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.dimensiondata.cloudcontrol.features; + +import com.squareup.okhttp.mockwebserver.MockResponse; +import org.jclouds.dimensiondata.cloudcontrol.domain.Account; +import org.jclouds.dimensiondata.cloudcontrol.internal.BaseDimensionDataCloudControlMockTest; +import org.testng.annotations.Test; + +import javax.ws.rs.HttpMethod; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +@Test(groups = "unit", testName = "AccountApiMockTest", singleThreaded = true) +public class AccountApiMockTest extends BaseDimensionDataCloudControlMockTest { + + @Test + public void testGetAccount() throws Exception { + server.enqueue(jsonResponse("/account.json")); + Account account = api.getAccountApi().getMyAccount(); + assertNotNull(account); + assertSent("GET", "/caas/2.4/user/myUser"); + } + + @Test + public void testGetAccount_404() throws Exception { + server.enqueue(new MockResponse().setStatus("HTTP/1.1 404 Not Found")); + Account account = api.getAccountApi().getMyAccount(); + assertNull(account); + assertSent(HttpMethod.GET, "/caas/2.4/user/myUser"); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilterTest.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilterTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilterTest.java new file mode 100644 index 0000000..d7f72e3 --- /dev/null +++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/filters/OrganisationIdFilterTest.java @@ -0,0 +1,59 @@ +/* + * 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.dimensiondata.cloudcontrol.filters; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +@Test(groups = "unit", testName = "OrganisationIdFilterTest") +public class OrganisationIdFilterTest { + + private Supplier<String> orgIdSupplier; + + @BeforeMethod + public void setup() { + orgIdSupplier = Suppliers.ofInstance("6ac1e746-b1ea-4da5-a24e-caf1a978789d"); + } + + @Test + public void testCaasUrl() { + String expectedPath = "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/0896551e-4fe3-4450-a627-ad5548e7e83a?clone=trevor-test2&desc=trevor-description2"; + String updatedPath = new OrganisationIdFilter(orgIdSupplier).injectOrganisationId( + "/caas/2.4/server/0896551e-4fe3-4450-a627-ad5548e7e83a?clone=trevor-test2&desc=trevor-description2"); + assertEquals(updatedPath, expectedPath); + } + + @Test + public void testDontAddIfAlreadyPresent() { + String expectedPath = "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/0896551e-4fe3-4450-a627-ad5548e7e83a"; + String updatedPath = new OrganisationIdFilter(orgIdSupplier).injectOrganisationId( + "/caas/2.4/6ac1e746-b1ea-4da5-a24e-caf1a978789d/server/0896551e-4fe3-4450-a627-ad5548e7e83a"); + assertEquals(updatedPath, expectedPath); + } + + @Test + public void testPathSegmentsLessThan3() { + String expectedPath = "/caas/2.4"; + String updatedPath = new OrganisationIdFilter(orgIdSupplier).injectOrganisationId("/caas/2.4"); + assertEquals(updatedPath, expectedPath); + } + +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java new file mode 100644 index 0000000..1fea43b --- /dev/null +++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlApiLiveTest.java @@ -0,0 +1,36 @@ +/* + * 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.dimensiondata.cloudcontrol.internal; + +import org.jclouds.apis.ApiMetadata; +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApiMetadata; +import org.testng.annotations.Test; + +@Test(groups = "live") +public class BaseDimensionDataCloudControlApiLiveTest extends BaseApiLiveTest<DimensionDataCloudControlApi> { + + public BaseDimensionDataCloudControlApiLiveTest() { + provider = "dimensiondata-cloudcontrol"; + } + + @Override + protected ApiMetadata createApiMetadata() { + return new DimensionDataCloudControlApiMetadata(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.java new file mode 100644 index 0000000..0ea17cf --- /dev/null +++ b/dimensiondata/src/test/java/org/jclouds/dimensiondata/cloudcontrol/internal/BaseDimensionDataCloudControlMockTest.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.dimensiondata.cloudcontrol.internal; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Resources; +import com.google.gson.JsonParser; +import com.google.inject.Module; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; +import org.jclouds.ContextBuilder; +import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlApi; +import org.jclouds.dimensiondata.cloudcontrol.DimensionDataCloudControlProviderMetadata; +import org.jclouds.json.Json; +import org.jclouds.rest.ApiContext; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.util.Properties; +import java.util.Set; + +import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Base class for all DimensionDataCloudController mock tests. + */ +public class BaseDimensionDataCloudControlMockTest { + + private static final String DEFAULT_ENDPOINT = new DimensionDataCloudControlProviderMetadata().getEndpoint(); + + private final Set<Module> modules = ImmutableSet.<Module>of(new ExecutorServiceModule(sameThreadExecutor())); + + protected MockWebServer server; + protected DimensionDataCloudControlApi api; + protected ApiContext<DimensionDataCloudControlApi> ctx; + private Json json; + + // So that we can ignore formatting. + private final JsonParser parser = new JsonParser(); + + @BeforeMethod + public void start() throws IOException { + server = new MockWebServer(); + server.play(); + ctx = ContextBuilder.newBuilder(DimensionDataCloudControlProviderMetadata.builder().build()).credentials("", "") + .endpoint(url("")).modules(modules).overrides(overrides()).build(); + json = ctx.utils().injector().getInstance(Json.class); + api = ctx.getApi(); + } + + @AfterMethod(alwaysRun = true) + public void stop() throws IOException { + server.shutdown(); + api.close(); + } + + protected Properties overrides() { + return new Properties(); + } + + protected String url(String path) { + return server.getUrl(path).toString(); + } + + protected MockResponse jsonResponse(String resource) { + return new MockResponse().addHeader("Content-Type", "application/json").setBody(stringFromResource(resource)); + } + + /** + * Mocked standard Dimension Data Unexpected Error 400 response + * + * @return {@link MockResponse} + */ + protected MockResponse responseUnexpectedError() { + return new MockResponse().setResponseCode(400).setStatus("HTTP/1.1 400 Bad Request") + .setBody("content: [{\"operation\":\"OPERATION\",\"responseCode\":\"UNEXPECTED_ERROR\"}]"); + } + + /** + * Mocked standard Dimension Data Resource Not Found 400 response + * + * @return {@link MockResponse} + */ + protected MockResponse responseResourceNotFound() { + return new MockResponse().setResponseCode(400).setStatus("HTTP/1.1 400 Bad Request") + .setBody("content: [{\"operation\":\"OPERATION\",\"responseCode\":\"RESOURCE_NOT_FOUND\"}]"); + } + + /** + * Mocked OK 200 Response + * + * @return {@link MockResponse} + */ + protected MockResponse response200() { + return new MockResponse().setResponseCode(200); + } + + protected String stringFromResource(String resourceName) { + try { + return Resources.toString(getClass().getResource(resourceName), Charsets.UTF_8) + .replace(DEFAULT_ENDPOINT, url("")); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + protected RecordedRequest assertSent(String method, String path) throws InterruptedException { + RecordedRequest request = server.takeRequest(); + assertThat(request.getMethod()).isEqualTo(method); + assertThat(request.getPath()).isEqualTo(path); + assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON); + assertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo("Basic Og=="); + return request; + } + + protected void assertBodyContains(RecordedRequest recordedRequest, String expectedText) { + assertThat(recordedRequest.getUtf8Body()).contains(expectedText); + } +} http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/6e5082f7/dimensiondata/src/test/resources/account.json ---------------------------------------------------------------------- diff --git a/dimensiondata/src/test/resources/account.json b/dimensiondata/src/test/resources/account.json new file mode 100644 index 0000000..d393768 --- /dev/null +++ b/dimensiondata/src/test/resources/account.json @@ -0,0 +1,26 @@ +{ + "userName": "devlab1-online-vendor-devuser1", + "fullName": "Donal Lunny", + "firstName": "Donal", + "lastName": "Lunny", + "emailAddress": "[email protected]", + "role": [ + "storage", + "primary administrator" + ], + "phone": { + "countryCode": "1", + "number": "1234567" + }, + "department": "Marketing", + "customDefined1": "custom defined 1", + "customDefined2": "custom defined 2", + "organization": { + "name": "Eng Customer of DevLab1-homed online sign-up Vendor", + "homeGeoName": "DevLab1Geo1", + "homeGeoApiHost": "apidevlab1.opsourcecloud.net", + "homeGeoId": "DEVLAB1GEO1", + "id": "6ac1e746-b1ea-4da5-a24e-caf1a978789d" + }, + "state": "NORMAL" +} \ No newline at end of file
