Skip to content

Commit

Permalink
Add a kubernetes style resource async class
Browse files Browse the repository at this point in the history
Refactor the existing async Operation to allow for multiple classes to
implement the async feature set.
Change resource.erb to be aware of multiple async types
Add a handwritten operation for kubernetes style resources
Using CloudRun as the initial resource that will support this
  • Loading branch information
chrisst committed Nov 19, 2019
1 parent c543128 commit f3e9965
Show file tree
Hide file tree
Showing 22 changed files with 576 additions and 380 deletions.
47 changes: 46 additions & 1 deletion api/async.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
require 'api/timeout'

module Api
# Represents an asynchronous operation definition
# Base class from which other Async classes can inherit.
class Async < Api::Object
end

# Represents an asynchronous operation definition
class OpAsync < Async
attr_reader :operation
attr_reader :result
attr_reader :status
Expand Down Expand Up @@ -103,4 +107,45 @@ def validate
end
end
end

# Kubernetes shaped resources do not have a dedicated Operation that can be
# polled against for the resource's status. Instead the resource contains a
# status block which has conditions that represent the state of the resource.
# As of now there is a single product with only 2 resources that follow this
# convention, so following the 1,2,many rule this is a bare bones
# implementation until a larger pattern emerges.
class K8sAsync < Async
attr_reader :operation
# The list of methods where operations are used.
attr_reader :actions

def validate
super

check :operation, type: K8sAsync::Operation, required: true
check :actions, default: %w[create delete update], type: ::Array, item_type: ::String
end

def allow?(method)
@actions.include?(method.downcase)
end

# Since K8s like objects contain the status within the resource body this
# Operation class is just a light wrapper to call the resource itself
class Operation < Api::Object
attr_reader :base_url
attr_reader :full_url
attr_reader :timeouts

def validate
super

check :base_url, type: String
check :full_url, type: String
check :timeouts, type: Api::Timeouts

conflicts %i[base_url full_url]
end
end
end
end
3 changes: 2 additions & 1 deletion google/yaml_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ def check_type(name, object, type)
elsif type.is_a? ::Array
return if type.find_index(:boolean) && [TrueClass, FalseClass].find_index(object.class)
return unless type.find_index(object.class).nil?
elsif object.is_a?(type)
# check if class is or inherits from type
elsif object.class <= type
return
end
raise "Property '#{name}' is '#{object.class}' instead of '#{type}'"
Expand Down
10 changes: 5 additions & 5 deletions products/accesscontextmanager/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,21 @@ versions:
base_url: https://accesscontextmanager.googleapis.com/v1/
scopes:
- https://www.googleapis.com/auth/cloud-platform
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
result: !ruby/object:Api::OpAsync::Result
path: 'response'
resource_inside_response: true
status: !ruby/object:Api::Async::Status
status: !ruby/object:Api::OpAsync::Status
path: 'done'
complete: true
allowed:
- true
- false
error: !ruby/object:Api::Async::Error
error: !ruby/object:Api::OpAsync::Error
path: 'error'
message: 'message'
objects:
Expand Down
30 changes: 15 additions & 15 deletions products/appengine/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@ objects:
'Official Documentation':
'https://cloud.google.com/appengine/docs/standard/python/mapping-custom-domains'
api: 'https://cloud.google.com/appengine/docs/admin-api/reference/rest/v1/apps.domainMappings'
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
result: !ruby/object:Api::OpAsync::Result
path: 'response'
resource_inside_response: true
status: !ruby/object:Api::Async::Status
status: !ruby/object:Api::OpAsync::Status
path: 'done'
complete: True
allowed:
- True
- False
error: !ruby/object:Api::Async::Error
error: !ruby/object:Api::OpAsync::Error
path: 'error'
message: 'message'
parameters:
Expand Down Expand Up @@ -226,22 +226,22 @@ objects:
'Official Documentation':
'https://cloud.google.com/appengine/docs/admin-api/deploying-overview'
api: 'https://cloud.google.com/appengine/docs/admin-api/reference/rest/v1/apps.services.versions'
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
kind: 'appengine#operation'
path: 'name'
base_url: 'projects/{{project}}/global/operations/{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
result: !ruby/object:Api::OpAsync::Result
path: 'targetLink'
status: !ruby/object:Api::Async::Status
status: !ruby/object:Api::OpAsync::Status
path: 'status'
complete: 'DONE'
allowed:
- 'PENDING'
- 'RUNNING'
- 'DONE'
error: !ruby/object:Api::Async::Error
error: !ruby/object:Api::OpAsync::Error
path: 'error/errors'
message: 'message'
parameters:
Expand Down Expand Up @@ -472,21 +472,21 @@ objects:
update_verb: :PATCH
references: !ruby/object:Api::Resource::ReferenceLinks
api: 'https://cloud.google.com/appengine/docs/admin-api/reference/rest/v1/apps#UrlDispatchRule'
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
result: !ruby/object:Api::OpAsync::Result
path: 'response'
status: !ruby/object:Api::Async::Status
status: !ruby/object:Api::OpAsync::Status
path: 'status'
complete: 'DONE'
allowed:
- 'PENDING'
- 'RUNNING'
- 'DONE'
error: !ruby/object:Api::Async::Error
error: !ruby/object:Api::OpAsync::Error
path: 'error/errors'
message: 'message'
properties:
Expand Down
10 changes: 5 additions & 5 deletions products/cloudfunctions/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,21 @@ objects:
A Cloud Function that contains user computation executed in response to an event.
collection_url_key: 'functions'
update_mask: true
async: !ruby/object:Api::Async
operation: !ruby/object:Api::Async::Operation
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::Async::Result
result: !ruby/object:Api::OpAsync::Result
path: 'response'
resource_inside_response: true
status: !ruby/object:Api::Async::Status
status: !ruby/object:Api::OpAsync::Status
path: 'done'
complete: True
allowed:
- True
- False
error: !ruby/object:Api::Async::Error
error: !ruby/object:Api::OpAsync::Error
path: 'error'
message: 'message'
parameters:
Expand Down
4 changes: 4 additions & 0 deletions products/cloudrun/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ objects:
name: Service
kind: Service
base_url: projects/{{project}}/locations/{{location}}/services
async: !ruby/object:Api::K8sAsync
actions: ['create', 'update']
operation: !ruby/object:Api::K8sAsync::Operation
base_url: 'projects/{{project}}/zones/{{zone}}/operations/{{op_id}}'
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Official Documentation':
Expand Down
Loading

0 comments on commit f3e9965

Please sign in to comment.