diff --git a/README.md b/README.md index f6104e64a9d3..f2d4050c8ddd 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ This client supports the following Google Cloud Platform services: - [Google Cloud Datastore] (#google-cloud-datastore) - [Google Cloud Storage] (#google-cloud-storage) +- [Google Cloud Resource Manager] (#google-cloud-resource-manager) > Note: This client is a work-in-progress, and may occasionally > make backwards-incompatible changes. @@ -182,6 +183,37 @@ if (blob == null) { } ``` +Google Cloud Resource Manager +---------------------- + +- [API Documentation][resourcemanager-api] +- [Official Documentation][cloud-resourcemanager-docs] + +#### Preview + +Here is a code snippet showing a simple usage example. Note that you must supply Google SDK credentials for this service, not other forms of authentication listed in the [Authentication section](#authentication). + +```java +import com.google.gcloud.resourcemanager.ProjectInfo; +import com.google.gcloud.resourcemanager.ResourceManager; +import com.google.gcloud.resourcemanager.ResourceManagerOptions; + +import java.util.Iterator; + +ResourceManager resourceManager = ResourceManagerOptions.defaultInstance().service(); +ProjectInfo myProject = resourceManager.get("some-project-id"); // Use an existing project's ID +ProjectInfo newProjectInfo = resourceManager.replace(myProject.toBuilder() + .addLabel("launch-status", "in-development").build()); +System.out.println("Updated the labels of project " + newProjectInfo.projectId() + + " to be " + newProjectInfo.labels()); +// List all the projects you have permission to view. +Iterator projectIterator = resourceManager.list().iterateAll(); +System.out.println("Projects I can view:"); +while (projectIterator.hasNext()) { + System.out.println(projectIterator.next().projectId()); +} +``` + Troubleshooting --------------- @@ -241,3 +273,6 @@ Apache 2.0 - See [LICENSE] for more information. [cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets [cloud-storage-activation]: https://cloud.google.com/storage/docs/signup [storage-api]: http://googlecloudplatform.github.io/gcloud-java/apidocs/index.html?com/google/gcloud/storage/package-summary.html + +[resourcemanager-api]:http://googlecloudplatform.github.io/gcloud-java/apidocs/index.html?com/google/gcloud/resourcemanager/package-summary.html +[cloud-resourcemanager-docs]:https://cloud.google.com/resource-manager/ diff --git a/TESTING.md b/TESTING.md index 02a3d14ab0bf..74c9504c9198 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,6 +1,10 @@ ## gcloud-java tools for testing -This library provides tools to help write tests for code that uses gcloud-java services. +This library provides tools to help write tests for code that uses the following gcloud-java services: + +- [Datastore] (#testing-code-that-uses-datastore) +- [Storage] (#testing-code-that-uses-storage) +- [Resource Manager] (#testing-code-that-uses-resource-manager) ### Testing code that uses Datastore @@ -65,5 +69,38 @@ Here is an example that clears the bucket created in Step 3 with a timeout of 5 RemoteGcsHelper.forceDelete(storage, bucket, 5, TimeUnit.SECONDS); ``` +### Testing code that uses Resource Manager + +#### On your machine + +You can test against a temporary local Resource Manager by following these steps: + +1. Before running your testing code, start the Resource Manager emulator `LocalResourceManagerHelper`. This can be done as follows: + + ```java + import com.google.gcloud.resourcemanager.testing.LocalResourceManagerHelper; + + LocalResourceManagerHelper helper = LocalResourceManagerHelper.create(); + helper.start(); + ``` + + This will spawn a server thread that listens to `localhost` at an ephemeral port for Resource Manager requests. + +2. In your program, create and use a Resource Manager service object whose host is set to `localhost` at the appropriate port. For example: + + ```java + ResourceManager resourceManager = LocalResourceManagerHelper.options().service(); + ``` + +3. Run your tests. + +4. Stop the Resource Manager emulator. + + ```java + helper.stop(); + ``` + + This method will block until the server thread has been terminated. + [cloud-platform-storage-authentication]:https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts diff --git a/gcloud-java-resourcemanager/README.md b/gcloud-java-resourcemanager/README.md index 11c505c14920..4e6ebecbbe5c 100644 --- a/gcloud-java-resourcemanager/README.md +++ b/gcloud-java-resourcemanager/README.md @@ -17,8 +17,22 @@ Java idiomatic client for [Google Cloud Resource Manager] (https://cloud.google. Quickstart ---------- -This library is currently under development and will be available soon! - +If you are using Maven, add this to your pom.xml file +```xml + + com.google.gcloud + gcloud-java-resourcemanager + 0.1.0 + +``` +If you are using Gradle, add this to your dependencies +```Groovy +compile 'com.google.gcloud:gcloud-java-resourcemanager:jar:0.1.0' +``` +If you are using SBT, add this to your dependencies +```Scala +libraryDependencies += "com.google.gcloud" % "gcloud-java-resourcemanager" % "0.1.0" +``` +Getting Started +--------------- +#### Prerequisites +You will need to set up the local development environment by [installing the Google Cloud SDK](https://cloud.google.com/sdk/) and running the following command in command line: `gcloud auth login`. + +> Note: You don't need a project ID to use this service. If you have a project ID set in the Google Cloud SDK, you can unset it by typing `gcloud config unset project` in command line. + +#### Installation and setup +You'll need to obtain the `gcloud-java-resourcemanager` library. See the [Quickstart](#quickstart) section to add `gcloud-java-resourcemanager` as a dependency in your code. + +#### Creating an authorized service object +To make authenticated requests to Google Cloud Resource Manager, you must create a service object with Google Cloud SDK credentials. You can then make API calls by calling methods on the Resource Manager service object. The simplest way to authenticate is to use [Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials). These credentials are automatically inferred from your environment, so you only need the following code to create your service object: + +```java +import com.google.gcloud.resourcemanager.ResourceManager; +import com.google.gcloud.resourcemanager.ResourceManagerOptions; + +ResourceManager resourceManager = ResourceManagerOptions.defaultInstance().service(); +``` + +#### Creating a project +All you need to create a project is a globally unique project ID. You can also optionally attach a non-unique name and labels to your project. Read more about naming guidelines for project IDs, names, and labels [here](https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects). To create a project, add the following import at the top of your file: + +```java +import com.google.gcloud.resourcemanager.ProjectInfo; +``` + +Then add the following code to create a project (be sure to change `myProjectId` to your own unique project ID). + +```java +String myProjectId = "my-globally-unique-project-id"; // Change to a unique project ID. +ProjectInfo myProject = resourceManager.create(ProjectInfo.builder(myProjectId).build()); +``` + +Note that the return value from `create` is a `ProjectInfo` that includes additional read-only information, like creation time, project number, and lifecycle state. Read more about these fields on the [Projects page](https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects). + +#### Getting a specific project +You can load a project if you know it's project ID and have read permissions to the project. For example, to get the project we just created we can do the following: + +```java +ProjectInfo projectFromServer = resourceManager.get(myProjectId); +``` + +#### Editing a project +To edit a project, create a new `ProjectInfo` object and pass it in to the `ResourceManager.replace` method. + +For example, to add a label for the newly created project to denote that it's launch status is "in development", add the following code: + +```java +ProjectInfo newProjectInfo = resourceManager.replace(projectFromServer.toBuilder() + .addLabel("launch-status", "in-development").build()); +``` + +Note that the values of the project you pass in to `replace` overwrite the server's values for non-read-only fields, namely `projectName` and `labels`. For example, if you create a project with `projectName` "some-project-name" and subsequently call replace using a `ProjectInfo` object that didn't set the `projectName`, then the server will unset the project's name. The server ignores any attempted changes to the read-only fields `projectNumber`, `lifecycleState`, and `createTime`. The `projectId` cannot change. + +#### Listing all projects +Suppose that we want a list of all projects for which we have read permissions. Add the following import: + +```java +import java.util.Iterator; +``` + +Then add the following code to print a list of projects you can view: + +```java +Iterator projectIterator = resourceManager.list().iterateAll(); +System.out.println("Projects I can view:"); +while (projectIterator.hasNext()) { + System.out.println(projectIterator.next().projectId()); +} +``` + +#### Complete source code + +Here we put together all the code shown above into one program. This program assumes that you are running from your own desktop and used the Google Cloud SDK to authenticate yourself. + +```java +import com.google.gcloud.resourcemanager.ProjectInfo; +import com.google.gcloud.resourcemanager.ResourceManager; +import com.google.gcloud.resourcemanager.ResourceManagerOptions; + +import java.util.Iterator; + +public class GcloudJavaResourceManagerExample { + + public static void main(String[] args) { + // Create Resource Manager service object. + // By default, credentials are inferred from the runtime environment. + ResourceManager resourceManager = ResourceManagerOptions.defaultInstance().service(); + + // Create a project. + String myProjectId = "my-globally-unique-project-id"; // Change to a unique project ID. + ProjectInfo myProject = resourceManager.create(ProjectInfo.builder(myProjectId).build()); + + // Get a project from the server. + ProjectInfo projectFromServer = resourceManager.get(myProjectId); + System.out.println("Got project " + projectFromServer.projectId() + " from the server."); + + // Update a project + ProjectInfo newProjectInfo = resourceManager.replace(myProject.toBuilder() + .addLabel("launch-status", "in-development").build()); + System.out.println("Updated the labels of project " + newProjectInfo.projectId() + + " to be " + newProjectInfo.labels()); + + // List all the projects you have permission to view. + Iterator projectIterator = resourceManager.list().iterateAll(); + System.out.println("Projects I can view:"); + while (projectIterator.hasNext()) { + System.out.println(projectIterator.next().projectId()); + } + } +} +``` Java Versions ------------- Java 7 or above is required for using this client. - - Versioning ---------- @@ -57,6 +189,13 @@ It is currently in major version zero (``0.y.z``), which means that anything may change at any time and the public API should not be considered stable. +Testing +------- + +This library has tools to help write tests for code that uses Resource Manager. + +See [TESTING] to read more about testing. + Contributing ------------ diff --git a/gcloud-java-resourcemanager/pom.xml b/gcloud-java-resourcemanager/pom.xml index 515a5c50e04f..70a1b2148c46 100644 --- a/gcloud-java-resourcemanager/pom.xml +++ b/gcloud-java-resourcemanager/pom.xml @@ -27,6 +27,12 @@ google-api-services-cloudresourcemanager v1beta1-rev6-1.19.0 compile + + + com.google.guava + guava-jdk5 + + junit diff --git a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ProjectInfo.java b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ProjectInfo.java index 5d490e662df0..2cb8a2d93ad2 100644 --- a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ProjectInfo.java +++ b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ProjectInfo.java @@ -31,7 +31,6 @@ /** * A Google Cloud Resource Manager project metadata object. - * * A Project is a high-level Google Cloud Platform entity. It is a container for ACLs, APIs, * AppEngine Apps, VMs, and other Google Cloud Platform resources. */ @@ -51,12 +50,12 @@ public class ProjectInfo implements Serializable { */ public enum State { /** - * Only used/useful for distinguishing unset values + * Only used/useful for distinguishing unset values. */ LIFECYCLE_STATE_UNSPECIFIED, /** - * The normal and active state + * The normal and active state. */ ACTIVE, @@ -67,7 +66,7 @@ public enum State { DELETE_REQUESTED, /** - * the process of deleting the project has begun. Reversing the deletion is no longer possible. + * The process of deleting the project has begun. Reversing the deletion is no longer possible. */ DELETE_IN_PROGRESS } @@ -106,7 +105,7 @@ com.google.api.services.cloudresourcemanager.model.ResourceId toPb() { com.google.api.services.cloudresourcemanager.model.ResourceId resourceIdPb = new com.google.api.services.cloudresourcemanager.model.ResourceId(); resourceIdPb.setId(id); - resourceIdPb.setType(type.toString().toLowerCase()); + resourceIdPb.setType(type.toLowerCase()); return resourceIdPb; } @@ -142,9 +141,9 @@ private Builder() { /** * Set the user-assigned name of the project. * - * This field is optional and can remain unset. Allowed characters are: lowercase and uppercase - * letters, numbers, hyphen, single-quote, double-quote, space, and exclamation point. This - * field can be changed after project creation. + *

This field is optional and can remain unset. Allowed characters are: lowercase and + * uppercase letters, numbers, hyphen, single-quote, double-quote, space, and exclamation point. + * This field can be changed after project creation. */ public Builder name(String name) { this.name = firstNonNull(name, Data.nullOf(String.class)); @@ -154,7 +153,7 @@ public Builder name(String name) { /** * Set the unique, user-assigned ID of the project. * - * The ID must be 6 to 30 lowercase letters, digits, or hyphens. It must start with a letter. + *

The ID must be 6 to 30 lowercase letters, digits, or hyphens. It must start with a letter. * Trailing hyphens are prohibited. This field cannot be changed after the server creates the * project. */ @@ -166,7 +165,7 @@ public Builder projectId(String projectId) { /** * Add a label associated with this project. * - * See {@link #labels} for label restrictions. + *

See {@link #labels} for label restrictions. */ public Builder addLabel(String key, String value) { this.labels.put(key, value); @@ -192,11 +191,11 @@ public Builder clearLabels() { /** * Set the labels associated with this project. * - * Label keys must be between 1 and 63 characters long and must conform to the following regular - * expression: [a-z]([-a-z0-9]*[a-z0-9])?. Label values must be between 0 and 63 characters long - * and must conform to the regular expression ([a-z]([-a-z0-9]*[a-z0-9])?)?. No more than 256 - * labels can be associated with a given resource. This field can be changed after project - * creation. + *

Label keys must be between 1 and 63 characters long and must conform to the following + * regular expression: [a-z]([-a-z0-9]*[a-z0-9])?. Label values must be between 0 and 63 + * characters long and must conform to the regular expression ([a-z]([-a-z0-9]*[a-z0-9])?)?. No + * more than 256 labels can be associated with a given resource. This field can be changed after + * project creation. */ public Builder labels(Map labels) { this.labels = Maps.newHashMap(checkNotNull(labels)); @@ -241,7 +240,7 @@ public ProjectInfo build() { /** * Get the unique, user-assigned ID of the project. * - * This field cannot be changed after the server creates the project. + *

This field cannot be changed after the server creates the project. */ public String projectId() { return projectId; @@ -250,7 +249,7 @@ public String projectId() { /** * Get the user-assigned name of the project. * - * This field is optional, can remain unset, and can be changed after project creation. + *

This field is optional, can remain unset, and can be changed after project creation. */ public String name() { return Data.isNull(name) ? null : name; @@ -259,7 +258,7 @@ public String name() { /** * Get number uniquely identifying the project. * - * This field is set by the server and is read-only. + *

This field is set by the server and is read-only. */ public Long projectNumber() { return projectNumber; @@ -275,7 +274,7 @@ public Map labels() { /** * Get the project's lifecycle state. * - * This is a read-only field. To change the lifecycle state of your project, use the + *

This is a read-only field. To change the lifecycle state of your project, use the * {@code delete} or {@code undelete} method. */ public State state() { @@ -289,7 +288,7 @@ ResourceId parent() { /** * Get the project's creation time (in milliseconds). * - * This field is set by the server and is read-only. + *

This field is set by the server and is read-only. */ public Long createTimeMillis() { return createTimeMillis; @@ -324,7 +323,7 @@ com.google.api.services.cloudresourcemanager.model.Project toPb() { projectPb.setLifecycleState(state.toString()); } if (createTimeMillis != null) { - projectPb.setCreateTime(ISODateTimeFormat.dateTime().print(createTimeMillis)); + projectPb.setCreateTime(ISODateTimeFormat.dateTime().withZoneUTC().print(createTimeMillis)); } if (parent != null) { projectPb.setParent(parent.toPb()); @@ -333,9 +332,8 @@ com.google.api.services.cloudresourcemanager.model.Project toPb() { } static ProjectInfo fromPb(com.google.api.services.cloudresourcemanager.model.Project projectPb) { - ProjectInfo.Builder builder = - ProjectInfo.builder(projectPb.getProjectId()).projectNumber(projectPb.getProjectNumber()); - if (projectPb.getName() != null) { + Builder builder = builder(projectPb.getProjectId()).projectNumber(projectPb.getProjectNumber()); + if (projectPb.getName() != null && !projectPb.getName().equals("Unnamed")) { builder.name(projectPb.getName()); } if (projectPb.getLabels() != null) { diff --git a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java index 1562fe51dad1..9ae524e28017 100644 --- a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java +++ b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/ResourceManager.java @@ -36,7 +36,7 @@ public interface ResourceManager extends Service { /** * The fields of a project. * - * These values can be used to specify the fields to include in a partial response when calling + *

These values can be used to specify the fields to include in a partial response when calling * {@link ResourceManager#get} or {@link ResourceManager#list}. Project ID is always returned, * even if not specified. */ @@ -82,7 +82,7 @@ private ProjectGetOption(ResourceManagerRpc.Option option, Object value) { /** * Returns an option to specify the project's fields to be returned by the RPC call. * - * If this option is not provided all project fields are returned. + *

If this option is not provided all project fields are returned. * {@code ProjectGetOption.fields} can be used to specify only the fields of interest. Project * ID is always returned, even if not specified. {@link ProjectField} provides a list of fields * that can be used. @@ -106,17 +106,17 @@ private ProjectListOption(ResourceManagerRpc.Option option, Object value) { /** * Returns an option to specify a filter. * - * Filter rules are case insensitive. The fields eligible for filtering are: + *

Filter rules are case insensitive. The fields eligible for filtering are: *

    *
  • name *
  • project ID *
  • labels.key, where key is the name of a label *
* - * You can specify multiple filters by adding a space between each filter. Multiple filters + *

You can specify multiple filters by adding a space between each filter. Multiple filters * are composed using "and". * - * Some examples of filters: + *

Some examples of filters: *