diff --git a/labs/aws-iam/src/test/java/org/jclouds/aws/iam/features/AWSRoleApiLiveTest.java b/labs/aws-iam/src/test/java/org/jclouds/aws/iam/features/AWSRoleApiLiveTest.java new file mode 100644 index 0000000000..5bc3d9b556 --- /dev/null +++ b/labs/aws-iam/src/test/java/org/jclouds/aws/iam/features/AWSRoleApiLiveTest.java @@ -0,0 +1,32 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.aws.iam.features; + +import org.jclouds.iam.features.RoleApiLiveTest; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "live", testName = "AWSRoleApiLiveTest") +public class AWSRoleApiLiveTest extends RoleApiLiveTest { + public AWSRoleApiLiveTest() { + provider = "aws-iam"; + } +} diff --git a/labs/iam/src/main/java/org/jclouds/iam/IAMApi.java b/labs/iam/src/main/java/org/jclouds/iam/IAMApi.java index 65b0fb3f12..ae158745ac 100644 --- a/labs/iam/src/main/java/org/jclouds/iam/IAMApi.java +++ b/labs/iam/src/main/java/org/jclouds/iam/IAMApi.java @@ -19,6 +19,7 @@ package org.jclouds.iam; import org.jclouds.iam.domain.User; +import org.jclouds.iam.features.RoleApi; import org.jclouds.iam.features.UserApi; import org.jclouds.rest.annotations.Delegate; @@ -42,4 +43,10 @@ public interface IAMApi { */ @Delegate UserApi getUserApi(); + + /** + * Provides synchronous access to Role features. + */ + @Delegate + RoleApi getRoleApi(); } diff --git a/labs/iam/src/main/java/org/jclouds/iam/IAMAsyncApi.java b/labs/iam/src/main/java/org/jclouds/iam/IAMAsyncApi.java index 6978582741..4b8e0041c9 100644 --- a/labs/iam/src/main/java/org/jclouds/iam/IAMAsyncApi.java +++ b/labs/iam/src/main/java/org/jclouds/iam/IAMAsyncApi.java @@ -24,6 +24,7 @@ import javax.ws.rs.Path; import org.jclouds.aws.filters.FormSigner; import org.jclouds.iam.domain.User; +import org.jclouds.iam.features.RoleAsyncApi; import org.jclouds.iam.features.UserAsyncApi; import org.jclouds.iam.xml.UserHandler; import org.jclouds.rest.annotations.Delegate; @@ -62,4 +63,10 @@ public interface IAMAsyncApi { */ @Delegate UserAsyncApi getUserApi(); + + /** + * Provides asynchronous access to Role features. + */ + @Delegate + RoleAsyncApi getRoleApi(); } diff --git a/labs/iam/src/main/java/org/jclouds/iam/config/IAMRestClientModule.java b/labs/iam/src/main/java/org/jclouds/iam/config/IAMRestClientModule.java index 1b80c35ab1..cf7bff27d6 100644 --- a/labs/iam/src/main/java/org/jclouds/iam/config/IAMRestClientModule.java +++ b/labs/iam/src/main/java/org/jclouds/iam/config/IAMRestClientModule.java @@ -25,6 +25,8 @@ import java.util.Map; import org.jclouds.aws.config.FormSigningRestClientModule; import org.jclouds.iam.IAMApi; import org.jclouds.iam.IAMAsyncApi; +import org.jclouds.iam.features.RoleApi; +import org.jclouds.iam.features.RoleAsyncApi; import org.jclouds.iam.features.UserApi; import org.jclouds.iam.features.UserAsyncApi; import org.jclouds.rest.ConfiguresRestClient; @@ -40,6 +42,7 @@ import com.google.common.collect.ImmutableMap; public class IAMRestClientModule extends FormSigningRestClientModule { public static final Map, Class> DELEGATE_MAP = ImmutableMap., Class> builder()// .put(UserApi.class, UserAsyncApi.class) + .put(RoleApi.class, RoleAsyncApi.class) .build(); public IAMRestClientModule() { diff --git a/labs/iam/src/main/java/org/jclouds/iam/domain/Role.java b/labs/iam/src/main/java/org/jclouds/iam/domain/Role.java new file mode 100644 index 0000000000..9e9f39a101 --- /dev/null +++ b/labs/iam/src/main/java/org/jclouds/iam/domain/Role.java @@ -0,0 +1,190 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Date; + +import com.google.common.base.Objects; + +/** + * @see + * + * @author Adrian Cole + */ +public final class Role { + + private final String arn; + private final String id; + private final String name; + private final String path; + private final Date createDate; + private final String assumeRolePolicy; + + private Role(String arn, String id, String name, String path, Date createDate, String assumeRolePolicy) { + this.arn = checkNotNull(arn, "arn"); + this.id = checkNotNull(id, "id for %s", arn); + this.name = checkNotNull(name, "name for %s", arn); + this.path = checkNotNull(path, "path for %s", arn); + this.createDate = checkNotNull(createDate, "createDate for %s", arn); + this.assumeRolePolicy = checkNotNull(assumeRolePolicy, "assumeRolePolicy for %s", + assumeRolePolicy); + } + + /** + * how to specify the resource in the access policy language ex. + * {@code arn:aws::::} + */ + public String getArn() { + return arn; + } + + /** + * a globally unique identifier (GUID), returned from the api. + */ + public String getId() { + return id; + } + + /** + * friendly name ex. {@code Developers} + */ + public String getName() { + return name; + } + + /** + * path ex {@code /division_abc/subdivision_xyz/product_1234/engineering/} + */ + public String getPath() { + return path; + } + + /** + * Date the role was created + */ + public Date getCreateDate() { + return createDate; + } + + /** + * The policy that grants an entity permission to assume the role. + */ + public String getAssumeRolePolicy() { + return assumeRolePolicy; + } + + @Override + public int hashCode() { + return Objects.hashCode(arn, id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + Role that = Role.class.cast(obj); + return equal(this.arn, that.arn) && equal(this.id, that.id); + } + + @Override + public String toString() { + return toStringHelper(this).add("arn", arn).add("id", id).add("name", name).add("path", path) + .add("createDate", createDate).add("assumeRolePolicy", assumeRolePolicy).toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().from(this); + } + + public static class Builder { + private String arn; + private String id; + private String name; + private String path; + private Date createDate; + private String assumeRolePolicy; + + /** + * @see Role#getArn() + */ + public Builder arn(String arn) { + this.arn = arn; + return this; + } + + /** + * @see Role#getId() + */ + public Builder id(String id) { + this.id = id; + return this; + } + + /** + * @see Role#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see Role#getPath() + */ + public Builder path(String path) { + this.path = path; + return this; + } + + /** + * @see Role#getCreateDate() + */ + public Builder createDate(Date createDate) { + this.createDate = createDate; + return this; + } + + /** + * @see Role#getAssumeRolePolicy() + */ + public Builder assumeRolePolicy(String assumeRolePolicy) { + this.assumeRolePolicy = assumeRolePolicy; + return this; + } + + public Role build() { + return new Role(arn, id, name, path, createDate, assumeRolePolicy); + } + + public Builder from(Role in) { + return arn(in.arn).id(in.id).name(in.name).path(in.path).createDate(in.createDate) + .assumeRolePolicy(in.assumeRolePolicy); + } + } +} diff --git a/labs/iam/src/main/java/org/jclouds/iam/domain/User.java b/labs/iam/src/main/java/org/jclouds/iam/domain/User.java index 9d9d7ff8ca..003355536f 100644 --- a/labs/iam/src/main/java/org/jclouds/iam/domain/User.java +++ b/labs/iam/src/main/java/org/jclouds/iam/domain/User.java @@ -18,6 +18,8 @@ */ package org.jclouds.iam.domain; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Date; @@ -32,27 +34,20 @@ import com.google.common.base.Optional; */ public final class User { - private final Optional path; - private final Optional name; - private final String id; private final String arn; + private final String id; + private final Optional name; + private final Optional path; private final Date createDate; - private User(String id, String arn, Optional path, Optional name, Date createDate) { - this.id = checkNotNull(id, "id"); - this.arn = checkNotNull(arn, "arn for %s", id); - this.path = checkNotNull(path, "path for %s", arn); + private User(String arn, String id, Optional name, Optional path, Date createDate) { + this.arn = checkNotNull(arn, "arn"); + this.id = checkNotNull(id, "id for %s", arn); this.name = checkNotNull(name, "name for %s", arn); + this.path = checkNotNull(path, "path for %s", arn); this.createDate = checkNotNull(createDate, "createDate for %s", arn); } - /** - * a globally unique identifier (GUID), returned from the api. - */ - public String getId() { - return id; - } - /** * how to specify the resource in the access policy language ex. * {@code arn:aws::::} @@ -62,10 +57,10 @@ public final class User { } /** - * path ex {@code /division_abc/subdivision_xyz/product_1234/engineering/} + * a globally unique identifier (GUID), returned from the api. */ - public Optional getPath() { - return path; + public String getId() { + return id; } /** @@ -75,6 +70,13 @@ public final class User { return name; } + /** + * path ex {@code /division_abc/subdivision_xyz/product_1234/engineering/} + */ + public Optional getPath() { + return path; + } + /** * Date the user was created */ @@ -82,34 +84,25 @@ public final class User { return createDate; } - /** - * {@inheritDoc} - */ @Override public int hashCode() { - return Objects.hashCode(id, arn); + return Objects.hashCode(arn, id); } - /** - * {@inheritDoc} - */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; - User other = (User) obj; - return Objects.equal(this.id, other.id) && Objects.equal(this.arn, other.arn); + User that = User.class.cast(obj); + return equal(this.arn, that.arn) && equal(this.id, that.id); } - /** - * {@inheritDoc} - */ @Override public String toString() { - return Objects.toStringHelper(this).add("path", path).add("name", name).add("id", id).add("arn", arn) - .add("createDate", createDate).toString(); + return toStringHelper(this).omitNullValues().add("arn", arn).add("id", id).add("name", name.orNull()) + .add("path", path.orNull()).add("createDate", createDate).toString(); } public static Builder builder() { @@ -121,17 +114,17 @@ public final class User { } public static class Builder { - private Optional path = Optional.absent(); + private String arn; private String id; private Optional name = Optional.absent(); - private String arn; + private Optional path = Optional.absent(); private Date createDate; /** - * @see User#getPath() + * @see User#getArn() */ - public Builder path(String path) { - this.path = Optional.fromNullable(path); + public Builder arn(String arn) { + this.arn = arn; return this; } @@ -152,10 +145,10 @@ public final class User { } /** - * @see User#getArn() + * @see User#getPath() */ - public Builder arn(String arn) { - this.arn = arn; + public Builder path(String path) { + this.path = Optional.fromNullable(path); return this; } @@ -168,11 +161,11 @@ public final class User { } public User build() { - return new User(id, arn, path, name, createDate); + return new User(arn, id, name, path, createDate); } public Builder from(User in) { - return this.path(in.path.orNull()).name(in.name.orNull()).id(in.id).arn(in.arn).createDate(in.createDate); + return arn(in.arn).id(in.id).name(in.name.orNull()).path(in.path.orNull()).createDate(in.createDate); } } } diff --git a/labs/iam/src/main/java/org/jclouds/iam/features/RoleApi.java b/labs/iam/src/main/java/org/jclouds/iam/features/RoleApi.java new file mode 100644 index 0000000000..a6ecc3c511 --- /dev/null +++ b/labs/iam/src/main/java/org/jclouds/iam/features/RoleApi.java @@ -0,0 +1,109 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.features; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.iam.domain.Role; +import org.jclouds.javax.annotation.Nullable; + +/** + * @see RoleAsyncApi + * @author Adrian Cole + */ +public interface RoleApi { + + /** + * Creates a new role for your AWS account + * + * @param name + * Name of the role to create. + * @param assumeRolePolicy + * The policy that grants an entity permission to assume the role.} + * @return the new role + */ + Role createWithPolicy(String name, String assumeRolePolicy); + + /** + * like {@link #createWithPolicy(String, String)}, except you can specify a path. + */ + Role createWithPolicyAndPath(String name, String assumeRolePolicy, String path); + + /** + * returns all roles in order. + */ + PagedIterable list(); + + /** + * retrieves up to 100 roles in order. + */ + IterableWithMarker listFirstPage(); + + /** + * retrieves up to 100 roles in order, starting at {@code marker} + * + * @param marker + * starting point to resume the list + */ + IterableWithMarker listAt(String marker); + + /** + * returns all roles in order at the specified {@code pathPrefix}. + * + * @param pathPrefix + * ex. {@code /division_abc/subdivision_xyz/} + */ + PagedIterable listPathPrefix(String pathPrefix); + + /** + * retrieves up to 100 roles in order at the specified {@code pathPrefix}. + * + * @param pathPrefix + * ex. {@code /division_abc/subdivision_xyz/} + */ + IterableWithMarker listPathPrefixFirstPage(String pathPrefix); + + /** + * retrieves up to 100 roles in order at the specified {@code pathPrefix}, starting at {@code marker}. + * + * @param pathPrefix + * ex. {@code /division_abc/subdivision_xyz/} + * @param marker + * starting point to resume the list + */ + IterableWithMarker listPathPrefixAt(String pathPrefix, String marker); + + /** + * Retrieves information about the specified role, including the role's path, GUID, and ARN. + * + * @param name + * Name of the role to get information about. + * @return null if not found + */ + @Nullable + Role get(String name); + + /** + * Deletes the specified role. The role must not have any policies attached. + * + * @param name + * Name of the role to delete + */ + void delete(String name); +} diff --git a/labs/iam/src/main/java/org/jclouds/iam/features/RoleAsyncApi.java b/labs/iam/src/main/java/org/jclouds/iam/features/RoleAsyncApi.java new file mode 100644 index 0000000000..afb9c44c09 --- /dev/null +++ b/labs/iam/src/main/java/org/jclouds/iam/features/RoleAsyncApi.java @@ -0,0 +1,159 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.features; + +import javax.inject.Named; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.Fallbacks.VoidOnNotFoundOr404; +import org.jclouds.aws.filters.FormSigner; +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.PagedIterable; +import org.jclouds.iam.domain.Role; +import org.jclouds.iam.functions.RolesToPagedIterable; +import org.jclouds.iam.xml.ListRolesResultHandler; +import org.jclouds.iam.xml.RoleHandler; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.FormParams; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.Transform; +import org.jclouds.rest.annotations.VirtualHost; +import org.jclouds.rest.annotations.XMLResponseParser; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * Provides access to Amazon IAM via the Query API + *

+ * + * @see + * @author Adrian Cole + */ +@RequestFilters(FormSigner.class) +@VirtualHost +public interface RoleAsyncApi { + /** + * @see RoleApi#createWithPolicy + */ + @Named("CreateRole") + @POST + @Path("/") + @FormParams(keys = "Action", values = "CreateRole") + @XMLResponseParser(RoleHandler.class) + ListenableFuture createWithPolicy(@FormParam("RoleName") String name, + @FormParam("AssumeRolePolicyDocument") String assumeRolePolicy); + + /** + * @see RoleApi#createWithPolicyAndPath + */ + @Named("CreateRole") + @POST + @Path("/") + @FormParams(keys = "Action", values = "CreateRole") + @XMLResponseParser(RoleHandler.class) + ListenableFuture createWithPolicyAndPath(@FormParam("RoleName") String name, + @FormParam("AssumeRolePolicyDocument") String assumeRolePolicy, @FormParam("Path") String path); + + /** + * @see RoleApi#list() + */ + @Named("ListRoles") + @POST + @Path("/") + @FormParams(keys = "Action", values = "ListRoles") + @XMLResponseParser(ListRolesResultHandler.class) + @Transform(RolesToPagedIterable.class) + ListenableFuture> list(); + + /** + * @see RoleApi#listFirstPage + */ + @Named("ListRoles") + @POST + @Path("/") + @FormParams(keys = "Action", values = "ListRoles") + @XMLResponseParser(ListRolesResultHandler.class) + ListenableFuture> listFirstPage(); + + /** + * @see RoleApi#listAt(String) + */ + @Named("ListRoles") + @POST + @Path("/") + @FormParams(keys = "Action", values = "ListRoles") + @XMLResponseParser(ListRolesResultHandler.class) + ListenableFuture> listAt(@FormParam("Marker") String marker); + + /** + * @see RoleApi#listPathPrefix(String) + */ + @Named("ListRoles") + @POST + @Path("/") + @FormParams(keys = "Action", values = "ListRoles") + @XMLResponseParser(ListRolesResultHandler.class) + @Transform(RolesToPagedIterable.class) + ListenableFuture> listPathPrefix(@FormParam("PathPrefix") String pathPrefix); + + /** + * @see RoleApi#listPathPrefixFirstPage(String) + */ + @Named("ListRoles") + @POST + @Path("/") + @FormParams(keys = "Action", values = "ListRoles") + @XMLResponseParser(ListRolesResultHandler.class) + ListenableFuture> listPathPrefixFirstPage(@FormParam("PathPrefix") String pathPrefix); + + /** + * @see RoleApi#listPathPrefixAt(String, String) + */ + @Named("ListRoles") + @POST + @Path("/") + @FormParams(keys = "Action", values = "ListRoles") + @XMLResponseParser(ListRolesResultHandler.class) + ListenableFuture> listPathPrefixAt(@FormParam("PathPrefix") String pathPrefix, + @FormParam("Marker") String marker); + + /** + * @see RoleApi#get() + */ + @Named("GetRole") + @POST + @Path("/") + @XMLResponseParser(RoleHandler.class) + @FormParams(keys = "Action", values = "GetRole") + @Fallback(NullOnNotFoundOr404.class) + ListenableFuture get(@FormParam("RoleName") String name); + + /** + * @see RoleApi#delete() + */ + @Named("DeleteRole") + @POST + @Path("/") + @FormParams(keys = "Action", values = "DeleteRole") + @Fallback(VoidOnNotFoundOr404.class) + ListenableFuture delete(@FormParam("RoleName") String name); +} diff --git a/labs/iam/src/main/java/org/jclouds/iam/features/UserApi.java b/labs/iam/src/main/java/org/jclouds/iam/features/UserApi.java index bca4eae459..52f73fe51a 100644 --- a/labs/iam/src/main/java/org/jclouds/iam/features/UserApi.java +++ b/labs/iam/src/main/java/org/jclouds/iam/features/UserApi.java @@ -24,10 +24,8 @@ import org.jclouds.iam.domain.User; import org.jclouds.javax.annotation.Nullable; /** - * Provides access to Amazon IAM via the Query API - *

* - * @see + * @see UserAsyncApi * @author Adrian Cole */ public interface UserApi { diff --git a/labs/iam/src/main/java/org/jclouds/iam/functions/RolesToPagedIterable.java b/labs/iam/src/main/java/org/jclouds/iam/functions/RolesToPagedIterable.java new file mode 100644 index 0000000000..afe260055a --- /dev/null +++ b/labs/iam/src/main/java/org/jclouds/iam/functions/RolesToPagedIterable.java @@ -0,0 +1,90 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.functions; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.internal.Arg0ToPagedIterable; +import org.jclouds.iam.IAMApi; +import org.jclouds.iam.domain.Role; +import org.jclouds.iam.features.RoleApi; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Optional; + +/** + * @author Adrian Cole + */ +@Beta +public class RolesToPagedIterable extends Arg0ToPagedIterable { + + private final RoleApi api; + + @Inject + protected RolesToPagedIterable(IAMApi api) { + this.api = checkNotNull(api, "api").getRoleApi(); + } + + @Override + protected Function> markerToNextForArg0(Optional pathPrefix) { + if (pathPrefix.isPresent()) + return new ListRolesUnderPathPrefixAtMarker(api, pathPrefix.get().toString()); + return new ListRolesAtMarker(api); + } + + private static class ListRolesUnderPathPrefixAtMarker implements Function> { + private final RoleApi api; + private final String pathPrefix; + + @Inject + protected ListRolesUnderPathPrefixAtMarker(RoleApi api, String pathPrefix) { + this.api = checkNotNull(api, "api"); + this.pathPrefix = checkNotNull(pathPrefix, "pathPrefix"); + } + + public IterableWithMarker apply(Object input) { + return api.listPathPrefixAt(pathPrefix, input.toString()); + } + + public String toString() { + return "ListRolesUnderPathPrefixAtMarker(" + pathPrefix + ")"; + } + } + + private static class ListRolesAtMarker implements Function> { + private final RoleApi api; + + @Inject + protected ListRolesAtMarker(RoleApi api) { + this.api = checkNotNull(api, "api"); + } + + public IterableWithMarker apply(Object input) { + return api.listAt(input.toString()); + } + + public String toString() { + return "listRolesAtMarker()"; + } + } +} diff --git a/labs/iam/src/main/java/org/jclouds/iam/xml/ListRolesResultHandler.java b/labs/iam/src/main/java/org/jclouds/iam/xml/ListRolesResultHandler.java new file mode 100644 index 0000000000..022b9ade66 --- /dev/null +++ b/labs/iam/src/main/java/org/jclouds/iam/xml/ListRolesResultHandler.java @@ -0,0 +1,97 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.xml; + +import static org.jclouds.util.SaxUtils.currentOrNull; +import static org.jclouds.util.SaxUtils.equalsOrSuffix; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.IterableWithMarkers; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.iam.domain.Role; +import org.xml.sax.Attributes; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.inject.Inject; + +/** + * @see + * + * @author Adrian Cole + */ +public class ListRolesResultHandler extends ParseSax.HandlerForGeneratedRequestWithResult> { + + private final RoleHandler roleHandler; + + private StringBuilder currentText = new StringBuilder(); + private Builder roles = ImmutableList. builder(); + private boolean inRoles; + private String afterMarker; + + @Inject + public ListRolesResultHandler(RoleHandler roleHandler) { + this.roleHandler = roleHandler; + } + + @Override + public IterableWithMarker getResult() { + try { + return IterableWithMarkers.from(roles.build(), afterMarker); + } finally { + roles = ImmutableList. builder(); + } + } + + @Override + public void startElement(String url, String name, String qName, Attributes attributes) { + if (equalsOrSuffix(qName, "Roles")) { + inRoles = true; + } + if (inRoles) { + roleHandler.startElement(url, name, qName, attributes); + } + } + + @Override + public void endElement(String uri, String name, String qName) { + if (inRoles) { + if (qName.equals("Roles")) { + inRoles = false; + } else if (qName.equals("member")) { + roles.add(roleHandler.getResult()); + } else { + roleHandler.endElement(uri, name, qName); + } + } else if (qName.equals("Marker")) { + afterMarker = currentOrNull(currentText); + } + + currentText = new StringBuilder(); + } + + @Override + public void characters(char ch[], int start, int length) { + if (inRoles) { + roleHandler.characters(ch, start, length); + } else { + currentText.append(ch, start, length); + } + } +} diff --git a/labs/iam/src/main/java/org/jclouds/iam/xml/RoleHandler.java b/labs/iam/src/main/java/org/jclouds/iam/xml/RoleHandler.java new file mode 100644 index 0000000000..0c3357b445 --- /dev/null +++ b/labs/iam/src/main/java/org/jclouds/iam/xml/RoleHandler.java @@ -0,0 +1,87 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.xml; + +import static org.jclouds.util.SaxUtils.currentOrNull; +import static org.jclouds.util.Strings2.urlDecode; + +import javax.inject.Inject; + +import org.jclouds.date.DateService; +import org.jclouds.http.functions.ParseSax; +import org.jclouds.iam.domain.Role; +import org.xml.sax.Attributes; + +/** + * @see + * + * @author Adrian Cole + */ +public class RoleHandler extends ParseSax.HandlerForGeneratedRequestWithResult { + private final DateService dateService; + + @Inject + protected RoleHandler(DateService dateService) { + this.dateService = dateService; + } + + private StringBuilder currentText = new StringBuilder(); + private Role.Builder builder = Role.builder(); + + @Override + public Role getResult() { + try { + return builder.build(); + } finally { + builder = Role.builder(); + } + } + + @Override + public void startElement(String url, String name, String qName, Attributes attributes) { + } + + @Override + public void endElement(String uri, String name, String qName) { + if (qName.equals("Path")) { + builder.path(currentOrNull(currentText)); + } else if (qName.equals("RoleName")) { + builder.name(currentOrNull(currentText)); + } else if (qName.equals("RoleId")) { + builder.id(currentOrNull(currentText)); + } else if (qName.equals("Arn")) { + builder.arn(currentOrNull(currentText)); + } else if (qName.equals("AssumeRolePolicyDocument")) { + builder.assumeRolePolicy(urlDecode(currentOrNull(currentText))); + } else if (qName.equals("CreateDate")) { + try { + builder.createDate(dateService.iso8601SecondsDateParse(currentOrNull(currentText))); + } catch (IllegalArgumentException e) { + // on create, milliseconds are present + builder.createDate(dateService.iso8601DateParse(currentOrNull(currentText))); + } + } + currentText = new StringBuilder(); + } + + @Override + public void characters(char ch[], int start, int length) { + currentText.append(ch, start, length); + } +} diff --git a/labs/iam/src/test/java/org/jclouds/iam/features/RoleApiExpectTest.java b/labs/iam/src/test/java/org/jclouds/iam/features/RoleApiExpectTest.java new file mode 100644 index 0000000000..5d3ee9ade6 --- /dev/null +++ b/labs/iam/src/test/java/org/jclouds/iam/features/RoleApiExpectTest.java @@ -0,0 +1,272 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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 + * + * Unles 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 expres or implied. See the License for the + * specific language governing permisions and limitations + * under the License. + */ +package org.jclouds.iam.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.iam.IAMApi; +import org.jclouds.iam.internal.BaseIAMApiExpectTest; +import org.jclouds.iam.parse.GetRoleResponseTest; +import org.jclouds.iam.parse.ListRolesResponseTest; +import org.jclouds.rest.ResourceNotFoundException; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "RoleApiExpectTest") +public class RoleApiExpectTest extends BaseIAMApiExpectTest { + String policy = "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"; + + HttpRequest create = HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "CreateRole") + .addFormParam("AssumeRolePolicyDocument", policy) + .addFormParam("RoleName", "name") + .addFormParam("Signature", "zl7UtZElpvnkjo81NmA%2BCvYu0xFEeXQlSRtqTgok2OU%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + public void testCreateWhenResponseIs2xx() throws Exception { + + HttpResponse getResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/get_role.xml", "text/xml")).build(); + + IAMApi apiWhenExist = requestSendsResponse(create, getResponse); + + assertEquals(apiWhenExist.getRoleApi().createWithPolicy("name", policy).toString(), new GetRoleResponseTest().expected().toString()); + } + + HttpRequest get = HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "GetRole") + .addFormParam("RoleName", "name") + .addFormParam("Signature", "OhV4oxbGMEJtWEDOUhR5n4u5TfGT9YtX/nVXHRyxDrs%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + public void testGetWhenResponseIs2xx() throws Exception { + + HttpResponse getResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/get_role.xml", "text/xml")).build(); + + IAMApi apiWhenExist = requestSendsResponse( + get, getResponse); + + assertEquals(apiWhenExist.getRoleApi().get("name").toString(), new GetRoleResponseTest().expected().toString()); + } + + public void testGetWhenResponseIs404() throws Exception { + + HttpResponse getResponse = HttpResponse.builder().statusCode(404).build(); + + IAMApi apiWhenDontExist = requestSendsResponse( + get, getResponse); + + assertNull(apiWhenDontExist.getRoleApi().get("name")); + } + + HttpRequest delete = HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "DeleteRole") + .addFormParam("RoleName", "name") + .addFormParam("Signature", "yhONyyLjFFtLgearEBrBNpSGTafh35LvRaaK8VagOVA%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + public void testDeleteWhenResponseIs2xx() throws Exception { + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/delete_role.xml", "text/xml")).build(); + + IAMApi apiWhenExist = requestSendsResponse(delete, deleteResponse); + + apiWhenExist.getRoleApi().delete("name"); + } + + public void testDeleteWhenResponseIs404() throws Exception { + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(404).build(); + + IAMApi apiWhenDontExist = requestSendsResponse(delete, deleteResponse); + + apiWhenDontExist.getRoleApi().delete("name"); + } + + HttpRequest list = HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "ListRoles") + .addFormParam("Signature", "aUfKE6CqT%2BAiRMmcRWmGrw/6wNpzrKCwd35UufAVEbs%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + public void testListWhenResponseIs2xx() throws Exception { + + HttpResponse listResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/list_roles.xml", "text/xml")).build(); + + IAMApi apiWhenExist = requestSendsResponse( + list, listResponse); + + assertEquals(apiWhenExist.getRoleApi().list().get(0).toString(), new ListRolesResponseTest().expected().toString()); + } + + public void testList2PagesWhenResponseIs2xx() throws Exception { + + HttpResponse listResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/list_roles_marker.xml", "text/xml")).build(); + + HttpRequest list2 = HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "ListRoles") + .addFormParam("Marker", "MARKER") + .addFormParam("Signature", "gOfxvq54UyrEck9AmMy4tm5zcNlRWwWtLBzGpKASskk%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + HttpResponse list2Response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/list_roles.xml", "text/xml")).build(); + + IAMApi apiWhenExist = requestsSendResponses(list, listResponse, list2, list2Response); + + assertEquals(apiWhenExist.getRoleApi().list().concat().toList(), + ImmutableList.copyOf(Iterables.concat(new ListRolesResponseTest().expected(), new ListRolesResponseTest().expected()))); + } + + HttpRequest listPathPrefix = HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "ListRoles") + .addFormParam("PathPrefix", "/subdivision") + .addFormParam("Signature", "ELuhOLquxfQw5pv9381CBuUfqiXv5FHl836m31HA2BI%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + public void testListPathPrefixWhenResponseIs2xx() throws Exception { + + HttpResponse listResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/list_roles.xml", "text/xml")).build(); + + IAMApi apiWhenExist = requestSendsResponse( + listPathPrefix, listResponse); + + assertEquals(apiWhenExist.getRoleApi().listPathPrefix("/subdivision").get(0).toString(), new ListRolesResponseTest().expected().toString()); + } + + public void testListPathPrefix2PagesWhenResponseIs2xx() throws Exception { + + HttpResponse listResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/list_roles_marker.xml", "text/xml")).build(); + + HttpRequest listPathPrefix2 = HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "ListRoles") + .addFormParam("Marker", "MARKER") + .addFormParam("PathPrefix", "/subdivision") + .addFormParam("Signature", "Y05M4vbhJpd35erXuhECszxjtx56cdIULGHnRaVr13s%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + HttpResponse list2Response = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/list_roles.xml", "text/xml")).build(); + + IAMApi apiWhenExist = requestsSendResponses(listPathPrefix, listResponse, listPathPrefix2, list2Response); + + assertEquals(apiWhenExist.getRoleApi().listPathPrefix("/subdivision").concat().toList(), + ImmutableList.copyOf(Iterables.concat(new ListRolesResponseTest().expected(), new ListRolesResponseTest().expected()))); + } + + // TODO: this should really be an empty set + @Test(expectedExceptions = ResourceNotFoundException.class) + public void testListWhenResponseIs404() throws Exception { + + HttpResponse listResponse = HttpResponse.builder().statusCode(404).build(); + + IAMApi apiWhenDontExist = requestSendsResponse( + list, listResponse); + + apiWhenDontExist.getRoleApi().list().get(0); + } + + public void testListPathPrefixAtWhenResponseIs2xx() throws Exception { + HttpRequest listWithOptions = + HttpRequest.builder() + .method("POST") + .endpoint("https://iam.amazonaws.com/") + .addHeader("Host", "iam.amazonaws.com") + .addFormParam("Action", "ListRoles") + .addFormParam("Marker", "MARKER") + .addFormParam("PathPrefix", "/foo") + .addFormParam("Signature", "HUXPIey7u7ajfog4wFgJn59fcFWpMSjd5yjomenL7jc%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2010-05-08") + .addFormParam("AWSAccessKeyId", "identity").build(); + + HttpResponse listWithOptionsResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/list_roles.xml", "text/xml")).build(); + + IAMApi apiWhenWithOptionsExist = requestSendsResponse(listWithOptions, + listWithOptionsResponse); + + assertEquals(apiWhenWithOptionsExist.getRoleApi().listPathPrefixAt("/foo", "MARKER").toString(), + new ListRolesResponseTest().expected().toString()); + } +} diff --git a/labs/iam/src/test/java/org/jclouds/iam/features/RoleApiLiveTest.java b/labs/iam/src/test/java/org/jclouds/iam/features/RoleApiLiveTest.java new file mode 100644 index 0000000000..1d4d4006a2 --- /dev/null +++ b/labs/iam/src/test/java/org/jclouds/iam/features/RoleApiLiveTest.java @@ -0,0 +1,91 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.features; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.logging.Logger.getAnonymousLogger; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.iam.domain.Role; +import org.jclouds.iam.internal.BaseIAMApiLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +/** + * @author Adrian Cole + */ +@Test(groups = "live", testName = "RoleApiLiveTest") +public class RoleApiLiveTest extends BaseIAMApiLiveTest { + + private void checkRole(Role role) { + checkNotNull(role.getArn(), "Arn cannot be null for Role %s", role); + checkNotNull(role.getId(), "Id cannot be null for Role %s", role); + checkNotNull(role.getName(), "Name cannot be null for Role %s", role); + checkNotNull(role.getPath(), "Path cannot be null for Role %s", role); + checkNotNull(role.getAssumeRolePolicy(), "AssumeRolePolicy cannot be null for Role %s", role); + checkNotNull(role.getCreateDate(), "CreateDate cannot be null for a Role Role %s", role); + } + + @Test + protected void testListRoles() { + ImmutableList roles = api().list().concat().toList(); + getAnonymousLogger().info("roles: " + roles.size()); + + for (Role role : roles) { + checkRole(role); + assertEquals(api().get(role.getName()), role); + ImmutableSet rolesAtPath = api().listPathPrefix(role.getPath()).concat().toSet(); + assertTrue(rolesAtPath.contains(role), role + " not in " + rolesAtPath); + } + } + + @Test + public void testGetRoleWhenNotFound() { + assertNull(api().get("AAAAAAAAAAAAAAAA")); + } + + @Test + public void testDeleteRoleWhenNotFound() { + api().delete("AAAAAAAAAAAAAAAA"); + } + + String policy = "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"; + + @Test + public void testCreateAndDeleteRole() { + String name = System.getProperty("user.name").replace('.', '-') + ".role.iamtest.jclouds.org."; + Role newRole; + try { + newRole = api().createWithPolicy(name, policy); + getAnonymousLogger().info("created role: " + newRole); + checkRole(newRole); + } finally { + api().delete(name); + assertNull(api().get(name)); + } + } + + protected RoleApi api() { + return context.getApi().getRoleApi(); + } +} diff --git a/labs/iam/src/test/java/org/jclouds/iam/features/UserApiExpectTest.java b/labs/iam/src/test/java/org/jclouds/iam/features/UserApiExpectTest.java index ab9aeaeff8..08b8fb0b9a 100644 --- a/labs/iam/src/test/java/org/jclouds/iam/features/UserApiExpectTest.java +++ b/labs/iam/src/test/java/org/jclouds/iam/features/UserApiExpectTest.java @@ -21,8 +21,6 @@ package org.jclouds.iam.features; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; -import java.util.TimeZone; - import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.jclouds.iam.IAMApi; @@ -41,10 +39,6 @@ import com.google.common.collect.Iterables; @Test(groups = "unit", testName = "UserApiExpectTest") public class UserApiExpectTest extends BaseIAMApiExpectTest { - public UserApiExpectTest() { - TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); - } - public void testGetCurrentWhenResponseIs2xx() throws Exception { HttpRequest get = HttpRequest.builder() .method("POST") diff --git a/labs/iam/src/test/java/org/jclouds/iam/features/UserApiLiveTest.java b/labs/iam/src/test/java/org/jclouds/iam/features/UserApiLiveTest.java index 5636781d7d..6c8369fd55 100644 --- a/labs/iam/src/test/java/org/jclouds/iam/features/UserApiLiveTest.java +++ b/labs/iam/src/test/java/org/jclouds/iam/features/UserApiLiveTest.java @@ -21,6 +21,7 @@ package org.jclouds.iam.features; import static com.google.common.base.Preconditions.checkNotNull; import static java.util.logging.Logger.getAnonymousLogger; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import org.jclouds.iam.domain.User; import org.jclouds.iam.internal.BaseIAMApiLiveTest; @@ -57,8 +58,10 @@ public class UserApiLiveTest extends BaseIAMApiLiveTest { for (User user : users) { checkUser(user); assertEquals(api().get(user.getId()), user); - if (user.getPath().isPresent()) - assertEquals(api().listPathPrefix(user.getPath().get()).toSet(), ImmutableSet.of(user)); + if (user.getPath().isPresent()) { + ImmutableSet usersAtPath = api().listPathPrefix(user.getPath().get()).concat().toSet(); + assertTrue(usersAtPath.contains(user), user + " not in " + usersAtPath); + } } } diff --git a/labs/iam/src/test/java/org/jclouds/iam/internal/BaseIAMExpectTest.java b/labs/iam/src/test/java/org/jclouds/iam/internal/BaseIAMExpectTest.java index 4fbb7e684d..b43af503e2 100644 --- a/labs/iam/src/test/java/org/jclouds/iam/internal/BaseIAMExpectTest.java +++ b/labs/iam/src/test/java/org/jclouds/iam/internal/BaseIAMExpectTest.java @@ -18,6 +18,8 @@ */ package org.jclouds.iam.internal; +import java.util.TimeZone; + import org.jclouds.date.DateService; import org.jclouds.iam.config.IAMRestClientModule; import org.jclouds.rest.ConfiguresRestClient; @@ -33,8 +35,9 @@ public class BaseIAMExpectTest extends BaseRestApiExpectTest { public BaseIAMExpectTest() { provider = "iam"; + TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); } - + @ConfiguresRestClient private static final class TestIAMRestClientModule extends IAMRestClientModule { diff --git a/labs/iam/src/test/java/org/jclouds/iam/parse/GetRoleResponseTest.java b/labs/iam/src/test/java/org/jclouds/iam/parse/GetRoleResponseTest.java new file mode 100644 index 0000000000..16bcfc4d2c --- /dev/null +++ b/labs/iam/src/test/java/org/jclouds/iam/parse/GetRoleResponseTest.java @@ -0,0 +1,63 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.parse; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; + +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.http.functions.BaseHandlerTest; +import org.jclouds.iam.domain.Role; +import org.jclouds.iam.xml.RoleHandler; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire +@Test(groups = "unit", testName = "GetRoleResponseTest") +public class GetRoleResponseTest extends BaseHandlerTest { + + public void test() { + InputStream is = getClass().getResourceAsStream("/get_role.xml"); + + Role expected = expected(); + + RoleHandler handler = injector.getInstance(RoleHandler.class); + Role result = factory.create(handler).parse(is); + + assertEquals(result, expected); + assertEquals(result.getPath(), expected.getPath()); + assertEquals(result.getName(), expected.getName()); + assertEquals(result.getCreateDate(), expected.getCreateDate()); + assertEquals(result.getAssumeRolePolicy(), expected.getAssumeRolePolicy()); + } + + public Role expected() { + return Role.builder() + .arn("arn:aws:iam::993194456877:role/foobie") + .id("AROAIBFDQ5TQHEMPBEUE4") + .name("foobie") + .path("/") + .assumeRolePolicy("{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}") + .createDate(new SimpleDateFormatDateService().iso8601SecondsDateParse("2013-02-25T01:51:35Z")).build(); + } + +} diff --git a/labs/iam/src/test/java/org/jclouds/iam/parse/ListRolesResponseTest.java b/labs/iam/src/test/java/org/jclouds/iam/parse/ListRolesResponseTest.java new file mode 100644 index 0000000000..9e57fe4022 --- /dev/null +++ b/labs/iam/src/test/java/org/jclouds/iam/parse/ListRolesResponseTest.java @@ -0,0 +1,72 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.iam.parse; + +import static org.testng.Assert.assertEquals; + +import java.io.InputStream; + +import org.jclouds.collect.IterableWithMarker; +import org.jclouds.collect.IterableWithMarkers; +import org.jclouds.date.internal.SimpleDateFormatDateService; +import org.jclouds.http.functions.BaseHandlerTest; +import org.jclouds.iam.domain.Role; +import org.jclouds.iam.xml.ListRolesResultHandler; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +/** + * @author Adrian Cole + */ +// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire +@Test(groups = "unit", testName = "ListRolesResponseTest") +public class ListRolesResponseTest extends BaseHandlerTest { + + public void test() { + InputStream is = getClass().getResourceAsStream("/list_roles.xml"); + + IterableWithMarker expected = expected(); + + ListRolesResultHandler handler = injector.getInstance(ListRolesResultHandler.class); + IterableWithMarker result = factory.create(handler).parse(is); + + assertEquals(result.toString(), expected.toString()); + + } + + public IterableWithMarker expected() { + return IterableWithMarkers.from(ImmutableSet.of( + Role.builder() + .arn("arn:aws:iam::993194456877:role/foobie") + .id("AROAIBFDQ5TQHEMPBEUE4") + .name("foobie") + .path("/") + .assumeRolePolicy("{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}") + .createDate(new SimpleDateFormatDateService().iso8601SecondsDateParse("2013-02-25T01:51:35Z")).build(), + Role.builder() + .arn("arn:aws:iam::993194456877:role/s3-read-only") + .id("AROAJZ7NAM67BRSDAJ6PA") + .name("s3-read-only") + .path("/") + .assumeRolePolicy("{\"Version\":\"2008-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}") + .createDate(new SimpleDateFormatDateService().iso8601SecondsDateParse("2013-02-25T01:48:59Z")).build())); + } + +} diff --git a/labs/iam/src/test/resources/create_role.xml b/labs/iam/src/test/resources/create_role.xml new file mode 100644 index 0000000000..a783a357b0 --- /dev/null +++ b/labs/iam/src/test/resources/create_role.xml @@ -0,0 +1,15 @@ + + + + / + arn:aws:iam::993194456877:role/adriancole.role.iamtest.jclouds.org. + adriancole.role.iamtest.jclouds.org. + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + 2013-02-25T02:40:42.201Z + AROAICHA6NH3SOP6PEC72 + + + + bf56e8fb-7ef4-11e2-87c7-6b7f31e39cd7 + + \ No newline at end of file diff --git a/labs/iam/src/test/resources/delete_role.xml b/labs/iam/src/test/resources/delete_role.xml new file mode 100644 index 0000000000..ecaa1ab7bb --- /dev/null +++ b/labs/iam/src/test/resources/delete_role.xml @@ -0,0 +1,5 @@ + + + 913e3f37-99ed-11e1-a4c3-270EXAMPLE04 + + \ No newline at end of file diff --git a/labs/iam/src/test/resources/get_role.xml b/labs/iam/src/test/resources/get_role.xml new file mode 100644 index 0000000000..a658234fc1 --- /dev/null +++ b/labs/iam/src/test/resources/get_role.xml @@ -0,0 +1,15 @@ + + + + / + arn:aws:iam::993194456877:role/foobie + foobie + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + 2013-02-25T01:51:35Z + AROAIBFDQ5TQHEMPBEUE4 + + + + 22fda32f-7eee-11e2-87c7-6b7f31e39cd7 + + \ No newline at end of file diff --git a/labs/iam/src/test/resources/list_roles.xml b/labs/iam/src/test/resources/list_roles.xml new file mode 100644 index 0000000000..e641d3a754 --- /dev/null +++ b/labs/iam/src/test/resources/list_roles.xml @@ -0,0 +1,28 @@ + + + + + / + arn:aws:iam::993194456877:role/foobie + foobie + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + + 2013-02-25T01:51:35Z + AROAIBFDQ5TQHEMPBEUE4 + + + / + arn:aws:iam::993194456877:role/s3-read-only + s3-read-only + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + + 2013-02-25T01:48:59Z + AROAJZ7NAM67BRSDAJ6PA + + + false + + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + + \ No newline at end of file diff --git a/labs/iam/src/test/resources/list_roles_marker.xml b/labs/iam/src/test/resources/list_roles_marker.xml new file mode 100644 index 0000000000..f2b7fdd46e --- /dev/null +++ b/labs/iam/src/test/resources/list_roles_marker.xml @@ -0,0 +1,29 @@ + + + + + / + arn:aws:iam::993194456877:role/foobie + foobie + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + + 2013-02-25T01:51:35Z + AROAIBFDQ5TQHEMPBEUE4 + + + / + arn:aws:iam::993194456877:role/s3-read-only + s3-read-only + %7B%22Version%22%3A%222008-10-17%22%2C%22Statement%22%3A%5B%7B%22Sid%22%3A%22%22%2C%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22Service%22%3A%22ec2.amazonaws.com%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D + + 2013-02-25T01:48:59Z + AROAJZ7NAM67BRSDAJ6PA + + + MARKER + false + + + 7a62c49f-347e-4fc4-9331-6e8eEXAMPLE + + \ No newline at end of file