lib/gcloud/resource_manager/project.rb in gcloud-0.11.0 vs lib/gcloud/resource_manager/project.rb in gcloud-0.12.0

- old
+ new

@@ -12,13 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. require "time" -require "gcloud/resource_manager/errors" require "gcloud/resource_manager/project/list" require "gcloud/resource_manager/project/updater" +require "gcloud/resource_manager/policy" module Gcloud module ResourceManager ## # # Project @@ -38,45 +38,45 @@ # p.labels["env"] = "production" # end # class Project ## - # @private The Connection object. - attr_accessor :connection + # @private The Service object. + attr_accessor :service ## # @private The Google API Client object. attr_accessor :gapi ## # @private Create an empty Project object. def initialize - @connection = nil - @gapi = {} + @service = nil + @gapi = Gcloud::ResourceManager::Service::API::Project.new end ## # The unique, user-assigned ID of the project. It must be 6 to 30 # lowercase letters, digits, or hyphens. It must start with a letter. # Trailing hyphens are prohibited. e.g. tokyo-rain-123 # def project_id - @gapi["projectId"] + @gapi.project_id end ## # The number uniquely identifying the project. e.g. 415104041262 # def project_number - @gapi["projectNumber"] + @gapi.project_number end ## # The user-assigned name of the project. # def name - @gapi["name"] + @gapi.name end ## # Updates the user-assigned name of the project. This field is optional # and can remain unset. @@ -91,18 +91,13 @@ # resource_manager = gcloud.resource_manager # project = resource_manager.project "tokyo-rain-123" # project.name = "My Project" # def name= new_name - ensure_connection! - @gapi["name"] = new_name - resp = connection.update_project @gapi - if resp.success? - @gapi = resp.data - else - fail ApiError.from_response(resp) - end + ensure_service! + @gapi.name = new_name + @gapi = service.update_project @gapi end ## # The labels associated with this project. # @@ -136,12 +131,11 @@ # project.labels do |labels| # labels["env"] = "production" # end # def labels - labels = @gapi["labels"] - labels = labels.to_hash if labels.respond_to? :to_hash + labels = @gapi.labels.to_h if block_given? yielded_labels = labels.dup yield yielded_labels self.labels = yielded_labels if yielded_labels != labels # changed else @@ -168,44 +162,39 @@ # resource_manager = gcloud.resource_manager # project = resource_manager.project "tokyo-rain-123" # project.labels = { "env" => "production" } # def labels= new_labels - ensure_connection! - @gapi["labels"] = new_labels - resp = connection.update_project @gapi - if resp.success? - @gapi = resp.data - else - fail ApiError.from_response(resp) - end + ensure_service! + @gapi.labels = new_labels + @gapi = service.update_project @gapi end ## # The time that this project was created. # def created_at - Time.parse @gapi["createTime"] + Time.parse @gapi.create_time rescue nil end ## # The project lifecycle state. # # Possible values are: # * `ACTIVE` - The normal and active state. - # * `LIFECYCLE_STATE_UNSPECIFIED` - Unspecified state. This is only - # used/useful for distinguishing unset values. # * `DELETE_REQUESTED` - The project has been marked for deletion by the - # user (by invoking DeleteProject) or by the system (Google Cloud - # Platform). This can generally be reversed by invoking UndeleteProject. + # user (by invoking ##delete) or by the system (Google Cloud + # Platform). This can generally be reversed by invoking {#undelete}. # * `DELETE_IN_PROGRESS` - The process of deleting the project has begun. # Reversing the deletion is no longer possible. + # * `LIFECYCLE_STATE_UNSPECIFIED` - Unspecified state. This is only + # used/useful for distinguishing unset values. # def state - @gapi["lifecycleState"] + @gapi.lifecycle_state end ## # Checks if the state is `ACTIVE`. def active? @@ -253,16 +242,14 @@ # end # def update updater = Updater.from_project self yield updater - resp = connection.update_project updater.gapi - if resp.success? - @gapi = resp.data - else - fail ApiError.from_response(resp) + if updater.gapi.to_h != @gapi.to_h # changed + @gapi = service.update_project updater.gapi end + self end ## # Reloads the project (with updated state) from the Google Cloud Resource # Manager service. @@ -274,16 +261,11 @@ # resource_manager = gcloud.resource_manager # project = resource_manager.project "tokyo-rain-123" # project.reload! # def reload! - resp = connection.get_project project_id - if resp.success? - @gapi = resp.data - else - fail ApiError.from_response(resp) - end + @gapi = service.get_project project_id end alias_method :refresh!, :reload! ## # Marks the project for deletion. This method will only affect the project @@ -315,17 +297,13 @@ # project.delete # project.active? #=> false # project.delete_requested? #=> true # def delete - resp = connection.delete_project project_id - if resp.success? - reload! - true - else - fail ApiError.from_response(resp) - end + service.delete_project project_id + reload! + true end ## # Restores the project. You can only use this method for a project that # has a lifecycle state of `DELETE_REQUESTED`. After deletion starts, as @@ -344,114 +322,116 @@ # project.undelete # project.delete_requested? #=> false # project.active? #=> true # def undelete - resp = connection.undelete_project project_id - if resp.success? - reload! - true - else - fail ApiError.from_response(resp) - end + service.undelete_project project_id + reload! + true end ## - # Gets the [Cloud IAM](https://cloud.google.com/iam/) access control - # policy. Returns a hash that conforms to the following structure: + # Gets and updates the [Cloud IAM](https://cloud.google.com/iam/) access + # control policy for this project. # - # { - # "bindings" => [{ - # "role" => "roles/viewer", - # "members" => ["serviceAccount:your-service-account"] - # }], - # "version" => 0, - # "etag" => "CAE=" - # } - # # @see https://cloud.google.com/iam/docs/managing-policies Managing # Policies + # @see https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/setIamPolicy + # projects.setIamPolicy # # @param [Boolean] force Force load the latest policy when `true`. # Otherwise the policy will be memoized to reduce the number of API # calls made. The default is `false`. # - # @return [Hash] See description + # @yield [policy] A block for updating the policy. The latest policy will + # be read from the service and passed to the block. After the block + # completes, the modified policy will be written to the service. + # @yieldparam [Policy] policy the current Cloud IAM Policy for this + # project # - # @example Policy values are memoized by default: + # @return [Policy] the current Cloud IAM Policy for this project + # + # @example Policy values are memoized to reduce the number of API calls: # require "gcloud" # # gcloud = Gcloud.new # resource_manager = gcloud.resource_manager # project = resource_manager.project "tokyo-rain-123" - # policy = project.policy # - # puts policy["bindings"] - # puts policy["version"] - # puts policy["etag"] + # policy = project.policy # API call + # policy_2 = project.policy # No API call # - # @example Use the `force` option to retrieve the latest policy: + # @example Use `force` to retrieve the latest policy from the service: # require "gcloud" # # gcloud = Gcloud.new # resource_manager = gcloud.resource_manager # project = resource_manager.project "tokyo-rain-123" - # policy = project.policy force: true # + # policy = project.policy force: true # API call + # policy_2 = project.policy force: true # API call + # + # @example Update the policy by passing a block: + # require "gcloud" + # + # gcloud = Gcloud.new + # resource_manager = gcloud.resource_manager + # project = resource_manager.project "tokyo-rain-123" + # + # policy = project.policy do |p| + # p.add "roles/owner", "user:owner@example.com" + # end # 2 API calls + # def policy force: false - @policy = nil if force + @policy = nil if force || block_given? @policy ||= begin - ensure_connection! - resp = connection.get_policy project_id - fail ApiError.from_response(resp) unless resp.success? - policy = resp.data - policy = policy.to_hash if policy.respond_to? :to_hash - policy + ensure_service! + gapi = service.get_policy project_id + Policy.from_gapi gapi end + return @policy unless block_given? + p = @policy.deep_dup + yield p + self.policy = p end ## - # Sets the [Cloud IAM](https://cloud.google.com/iam/) access control - # policy. + # Updates the [Cloud IAM](https://cloud.google.com/iam/) access control + # policy for this project. The policy should be read from {#policy}. + # See {Gcloud::ResourceManager::Policy} for an explanation of the policy + # `etag` property and how to modify policies. # + # You can also update the policy by passing a block to {#policy}, which + # will call this method internally after the block completes. + # # @see https://cloud.google.com/iam/docs/managing-policies Managing # Policies + # @see https://cloud.google.com/resource-manager/reference/rest/v1beta1/projects/setIamPolicy + # projects.setIamPolicy # - # @param [String] new_policy A hash that conforms to the following - # structure: + # @param [Policy] new_policy a new or modified Cloud IAM Policy for this + # project # - # { - # "bindings" => [{ - # "role" => "roles/viewer", - # "members" => ["serviceAccount:your-service-account"] - # }] - # } - # # @example # require "gcloud" # # gcloud = Gcloud.new # resource_manager = gcloud.resource_manager # project = resource_manager.project "tokyo-rain-123" # - # viewer_policy = { - # "bindings" => [{ - # "role" => "roles/viewer", - # "members" => ["serviceAccount:your-service-account"] - # }] - # } - # project.policy = viewer_policy + # policy = project.policy # API call # + # policy.add "roles/owner", "user:owner@example.com" + # + # project.policy = policy # API call + # def policy= new_policy - ensure_connection! - resp = connection.set_policy project_id, new_policy - if resp.success? - @policy = resp.data - @policy = @policy.to_hash if @policy.respond_to? :to_hash - else - fail ApiError.from_response(resp) - end + ensure_service! + gapi = service.set_policy project_id, new_policy.to_gapi + # Convert symbols to strings for backwards compatibility. + # This will go away when we add a ResourceManager::Policy class. + @policy = Policy.from_gapi gapi end ## # Tests the specified permissions against the [Cloud # IAM](https://cloud.google.com/iam/) access control policy. @@ -476,33 +456,29 @@ # perms.include? "resourcemanager.projects.get" #=> true # perms.include? "resourcemanager.projects.delete" #=> false # def test_permissions *permissions permissions = Array(permissions).flatten - ensure_connection! - resp = connection.test_permissions project_id, permissions - if resp.success? - Array(resp.data["permissions"]) - else - fail ApiError.from_response(resp) - end + ensure_service! + gapi = service.test_permissions project_id, permissions + gapi.permissions end ## # @private New Change from a Google API Client object. - def self.from_gapi gapi, connection + def self.from_gapi gapi, service new.tap do |p| p.gapi = gapi - p.connection = connection + p.service = service end end protected ## - # Raise an error unless an active connection is available. - def ensure_connection! - fail "Must have active connection" unless connection + # Raise an error unless an active service is available. + def ensure_service! + fail "Must have active connection" unless service end end end end