Skip to content

Commit

Permalink
Add support for cloud run service IAM. Use base paths via replaceVars (
Browse files Browse the repository at this point in the history
…#2770)

Merged PR #2770.
  • Loading branch information
slevenick authored and modular-magician committed Dec 5, 2019
1 parent a8521e3 commit 541765f
Show file tree
Hide file tree
Showing 13 changed files with 68 additions and 32 deletions.
10 changes: 10 additions & 0 deletions api/resource/iam_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ class IamPolicy < Api::Object
# How the API supports IAM conditions
attr_reader :iam_conditions_request_type

# Allows us to override the base_url of the resource. This is required for Cloud Run as the
# IAM resources use an entirely different base URL from the actual resource
attr_reader :base_url

# Allows us to override the import format of the resource. Useful for Cloud Run where we need
# variables that are outside of the base_url qualifiers.
attr_reader :import_format

def validate
super

Expand All @@ -75,6 +83,8 @@ def validate
check :parent_resource_attribute, type: String, default: 'id'
check :test_project_name, type: String
check :iam_conditions_request_type, type: Symbol, allowed: %i[REQUEST_BODY QUERY_PARAM]
check :base_url, type: String
check :import_format, type: Array, item_type: String
check(
:example_config_body,
type: String, default: 'templates/terraform/iam/iam_attributes.tf.erb'
Expand Down
2 changes: 1 addition & 1 deletion build/terraform
2 changes: 1 addition & 1 deletion build/terraform-beta
2 changes: 1 addition & 1 deletion build/terraform-mapper
11 changes: 8 additions & 3 deletions products/cloudrun/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ display_name: Cloud Run
versions:
- !ruby/object:Api::Product::Version
name: ga
base_url: https://{{location}}-run.googleapis.com/apis/
base_url: https://{{location}}-run.googleapis.com/
scopes:
- https://www.googleapis.com/auth/cloud-platform
objects:
# Cloud Run DomainMappings
- !ruby/object:Api::Resource
name: DomainMapping
kind: DomainMapping
base_url: domains.cloudrun.com/v1/namespaces/{{project}}/domainmappings
base_url: apis/domains.cloudrun.com/v1/namespaces/{{project}}/domainmappings
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Official Documentation':
Expand Down Expand Up @@ -219,7 +219,7 @@ objects:
- !ruby/object:Api::Resource
name: Service
kind: Service
base_url: serving.knative.dev/v1/namespaces/{{project}}/services
base_url: apis/serving.knative.dev/v1/namespaces/{{project}}/services
async: !ruby/object:Api::PollAsync
actions: ['create', 'update']
operation: !ruby/object:Api::PollAsync::Operation
Expand All @@ -246,6 +246,11 @@ objects:
See also:
https://github.com/knative/serving/blob/master/docs/spec/overview.md#service
iam_policy: !ruby/object:Api::Resource::IamPolicy
method_name_separator: ':'
parent_resource_attribute: 'service'
base_url: v1/projects/{{project}}/locations/{{location}}/services/{{service}}
import_format: ["projects/{{project}}/locations/{{location}}/services/{{service}}", "{{service}}"]
parameters:
- !ruby/object:Api::Type::String
name: location
Expand Down
1 change: 1 addition & 0 deletions products/cloudrun/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ overrides: !ruby/object:Overrides::ResourceOverrides
- !ruby/object:Provider::Terraform::Examples
name: "cloud_run_service_basic"
primary_resource_id: "default"
primary_resource_name: "fmt.Sprintf(\"tftest-cloudrun%s\", context[\"random_suffix\"])"
vars:
cloud_run_service_name: "tftest-cloudrun"
test_env_vars:
Expand Down
18 changes: 10 additions & 8 deletions provider/terraform/import.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ module Provider
class Terraform < Provider::AbstractCore
# Functions to support 'terraform import'.
module Import
def import_id_formats_from_resource(resource)
import_id_formats(resource.import_format, resource.identity, resource.base_url)
end

# Returns a list of import id formats for a given resource. If an id
# contains provider-default values, this fn will return formats both
# including and omitting the value.
Expand All @@ -32,22 +36,20 @@ module Import
# a) self_link: projects/{{project}}/global/networks/{{name}}
# b) short id: {{project}}/{{name}}
# c) short id w/o defaults: {{name}}
def import_id_formats(resource)
if resource.import_format.nil? || resource.import_format.empty?
underscored_base_url = resource.base_url.gsub(
def import_id_formats(import_format, identity, base_url)
if import_format.nil? || import_format.empty?
underscored_base_url = base_url.gsub(
/{{[[:word:]]+}}/, &:underscore
)

if resource.identity.nil? || resource.identity.empty?
if identity.nil? || identity.empty?
id_formats = [underscored_base_url + '/{{name}}']
else
identity_path = resource.identity
.map { |v| "{{#{v.name.underscore}}}" }
.join('/')
identity_path = identity.map { |v| "{{#{v.name.underscore}}}" }.join('/')
id_formats = [underscored_base_url + '/' + identity_path]
end
else
id_formats = resource.import_format
id_formats = import_format
end

# short id: {{project}}/{{zone}}/{{name}}
Expand Down
4 changes: 2 additions & 2 deletions spec/provider_terraform_import_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ class << self
config.validate
end

describe '#import_id_formats' do
describe '#import_id_formats_from_resource' do
subject do
provider.import_id_formats(
provider.import_id_formats_from_resource(
resource(
'base_url: "projects/{{project}}/regions/{{region}}/subnetworks"'
)
Expand Down
12 changes: 9 additions & 3 deletions templates/terraform/examples/base_configs/iam_test_file.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@ import (
<% resource_name = product_ns + object.name -%>
<%
individual_url = object.self_link_url
params = extract_identifiers(individual_url.gsub('{{name}}', "{{#{object.name.underscore}}}"))
-%>
<%
tf_product = (@config.legacy_name || product_ns).underscore
resource_ns = object.legacy_name || "google_#{tf_product}_#{object.name.underscore}"
resource_ns_iam = resource_ns + '_iam'
-%>
<% import_url = individual_url.gsub(/({{)(\w+)(}})/, '%s').gsub(object.__product.base_url, '') -%>
<% import_str = Array.new(params.length, '%s').join('/') -%>
<%
if object.iam_policy.import_format
import_format = object.iam_policy.import_format.first
else
import_format = individual_url
end
params = extract_identifiers(import_format.gsub('{{name}}', "{{#{object.name.underscore}}}"))
import_url = import_format.gsub(/({{)(\w+)(}})/, '%s').gsub(object.__product.base_url, '')
-%>
<% import_qualifiers = [] -%>
<% params.each_with_index do |param, i| -%>
<% if param == 'project' -%>
Expand Down
31 changes: 21 additions & 10 deletions templates/terraform/iam_policy.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
)
<% resource_name = product_ns + object.name -%>
<%
resource_uri = object.self_link_url
resource_uri = object.iam_policy.base_url || object.self_link_uri
parent_resource_name = object.iam_policy.parent_resource_attribute || object.name.underscore
resource_params = extract_identifiers(resource_uri.gsub('{{name}}', "{{#{parent_resource_name}}}"))
-%>
Expand Down Expand Up @@ -87,9 +87,10 @@ func <%= resource_name -%>IamUpdaterProducer(d *schema.ResourceData, config *Con

<% end # if provider_default_values.include? -%>
<% end # resource_params.each -%>
<% import_format = object.iam_policy.import_format || object.import_format -%>

// We may have gotten either a long or short name, so attempt to parse long name if possible
m, err := getImportIdQualifiers([]string{"<%= import_id_formats(object).map{|s| format2regex s}.map{|s| s.gsub('<name>', "<#{parent_resource_name}>")}.join('","') -%>"}, d, config, d.Get("<%= parent_resource_name -%>").(string))
m, err := getImportIdQualifiers([]string{"<%= import_id_formats(import_format, object.identity, object.base_url).map{|s| format2regex s}.map{|s| s.gsub('<name>', "<#{parent_resource_name}>")}.join('","') -%>"}, d, config, d.Get("<%= parent_resource_name -%>").(string))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -137,7 +138,7 @@ func <%= resource_name -%>IdParseFunc(d *schema.ResourceData, config *Config) er
<% end # if provider_default_values.include? -%>
<% end # resource_params.each -%>

m, err := getImportIdQualifiers([]string{"<%= import_id_formats(object).map{|s| format2regex s}.map{|s| s.gsub('<name>', "<#{parent_resource_name}>")}.join('","') -%>"}, d, config, d.Id())
m, err := getImportIdQualifiers([]string{"<%= import_id_formats(import_format, object.identity, object.base_url).map{|s| format2regex s}.map{|s| s.gsub('<name>', "<#{parent_resource_name}>")}.join('","') -%>"}, d, config, d.Id())
if err != nil {
return err
}
Expand Down Expand Up @@ -165,7 +166,10 @@ func <%= resource_name -%>IdParseFunc(d *schema.ResourceData, config *Config) er
}

func (u *<%= resource_name -%>IamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) {
url := u.qualify<%= object.name -%>Url("getIamPolicy")
url, err := u.qualify<%= object.name -%>Url("getIamPolicy")
if err != nil {
return nil, err
}

<% if resource_params.include?('project') -%>
project, err := getProject(u.d, u.Config)
Expand Down Expand Up @@ -212,7 +216,10 @@ func (u *<%= resource_name -%>IamUpdater) SetResourceIamPolicy(policy *cloudreso
obj := make(map[string]interface{})
obj["policy"] = json

url := u.qualify<%= object.name -%>Url("setIamPolicy")
url, err := u.qualify<%= object.name -%>Url("setIamPolicy")
if err != nil {
return err
}

<% if resource_params.include?('project') -%>
project, err := getProject(u.d, u.Config)
Expand All @@ -229,11 +236,15 @@ func (u *<%= resource_name -%>IamUpdater) SetResourceIamPolicy(policy *cloudreso
return nil
}

<% import_url = resource_uri.gsub(/({{)(\w+)(}})/, '%s').gsub(object.__product.base_url, '') -%>
<% string_qualifiers = resource_params.map{|param| "u.#{param.camelize(:lower)}"}.join(', ') -%>
<%# TODO(slevenick): this should use normal resource qualify methods to replace base_url -%>
func (u *<%= resource_name -%>IamUpdater) qualify<%= object.name -%>Url(methodIdentifier string) string {
return fmt.Sprintf("<%= object.__product.base_url -%>%s<%= object.iam_policy.method_name_separator -%>%s", fmt.Sprintf("<%= import_url -%>", <%= string_qualifiers -%>), methodIdentifier)
<% import_url = resource_uri.gsub(/({{)(\w+)(}})/, '%s') -%>
<% string_qualifiers = extract_identifiers(resource_uri.gsub('{{name}}', "{{#{parent_resource_name}}}")).map{|param| "u.#{param.camelize(:lower)}"}.join(', ') -%>
func (u *<%= resource_name -%>IamUpdater) qualify<%= object.name -%>Url(methodIdentifier string) (string, error) {
urlTemplate := fmt.Sprintf("{{<%= object.__product.name -%>BasePath}}%s<%= object.iam_policy.method_name_separator -%>%s", fmt.Sprintf("<%= import_url -%>", <%= string_qualifiers -%>), methodIdentifier)
url, err := replaceVars(u.d, u.Config, urlTemplate)
if err != nil {
return "", err
}
return url, nil
}

func (u *<%= resource_name -%>IamUpdater) GetResourceId() string {
Expand Down
2 changes: 1 addition & 1 deletion templates/terraform/resource.erb
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ func resource<%= resource_name -%>Import(d *schema.ResourceData, meta interface{
<% else -%>
config := meta.(*Config)
if err := parseImportId([]string{
<% for import_id in import_id_formats(object) -%>
<% for import_id in import_id_formats_from_resource(object) -%>
"<%= format2regex(import_id) %>",
<% end -%>
}, d, config); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion templates/terraform/resource.html.markdown.erb
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ This resource provides the following
<%= object.name -%> can be imported using any of these accepted formats:
```
<% import_id_formats(object).each do |id_format| -%>
<% import_id_formats_from_resource(object).each do |id_format| -%>
$ terraform import <% if object.min_version.name == 'beta' %>-provider=google-beta <% end -%><%= terraform_name -%>.default <%= id_format %>
<% end -%>
```
Expand Down
3 changes: 2 additions & 1 deletion templates/terraform/resource_iam.html.markdown.erb
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,9 @@ exported:
## Import

For all import syntaxes, the "resource in question" can take any of the following forms:
<% import_format = object.iam_policy.import_format || object.import_format -%>

<% import_id_formats(object).each do |id_format| -%>
<% import_id_formats(import_format, object.identity, object.base_url).each do |id_format| -%>
* <%= id_format %>
<% end -%>

Expand Down

0 comments on commit 541765f

Please sign in to comment.