Skip to content

Commit

Permalink
update ancestry manager to use cfg (GoogleCloudPlatform#283)
Browse files Browse the repository at this point in the history
* update ancestry manager to use cfg

* fix tests, fork function

* move credential test

* remove split functionality, change original interface

* abstract config out to retriever class

* align coments with names

* clean up
  • Loading branch information
ScottSuarez committed Aug 6, 2021
1 parent 638f7e2 commit c37093e
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 120 deletions.
16 changes: 8 additions & 8 deletions ancestrymanager/ancestrymanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
package ancestrymanager

import (
"context"
"fmt"
"log"
"strings"

"github.com/pkg/errors"
"google.golang.org/api/cloudresourcemanager/v1"
"google.golang.org/api/option"

converter "github.com/GoogleCloudPlatform/terraform-google-conversion/google"
)
Expand All @@ -22,6 +19,12 @@ type AncestryManager interface {
GetAncestryWithResource(project string, tfData converter.TerraformResourceData, cai converter.Asset) (string, error)
}

// ClientRetriever is the interface that returns an instance of various clients.
type ClientRetriever interface {
// NewResourceManagerClient returns an initialized *cloudresourcemanager.Service
NewResourceManagerClient(userAgent string) *cloudresourcemanager.Service
}

// resourceAncestryManager provides common methods for retrieving ancestry from resources
type resourceAncestryManager struct {
}
Expand Down Expand Up @@ -180,7 +183,7 @@ func (m *offlineAncestryManager) GetAncestryWithResource(project string, tfData
}

// New returns AncestryManager that can be used to fetch ancestry information for a project.
func New(ctx context.Context, project, ancestry string, offline bool, opts ...option.ClientOption) (AncestryManager, error) {
func New(retriever ClientRetriever, project, ancestry, userAgent string, offline bool) (AncestryManager, error) {
if ancestry != "" {
ancestry = fmt.Sprintf("%s/project/%s", ancestry, project)
}
Expand All @@ -189,10 +192,7 @@ func New(ctx context.Context, project, ancestry string, offline bool, opts ...op
}
am := &onlineAncestryManager{ancestryCache: map[string]string{}}
am.store(project, ancestry)
rm, err := cloudresourcemanager.NewService(ctx, opts...)
if err != nil {
return nil, errors.Wrap(err, "constructing resource manager client")
}
rm := retriever.NewResourceManagerClient(userAgent)
am.resourceManager = rm
return am, nil
}
Expand Down
27 changes: 24 additions & 3 deletions ancestrymanager/ancestrymanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ import (
"google.golang.org/api/option"
)

type testRetriever struct {
online bool
opts []option.ClientOption
}

func (tr *testRetriever) NewResourceManagerClient(userAgent string) *cloudresourcemanager.Service {
ctx := context.Background()

if tr.online {
rm, err := cloudresourcemanager.NewService(ctx, tr.opts...)
if err != nil {
panic(err)
}
return rm
}
return nil
}

func TestAncestryPath(t *testing.T) {
cases := []struct {
name string
Expand Down Expand Up @@ -53,7 +71,6 @@ func TestAncestryPath(t *testing.T) {
}

func TestGetAncestry(t *testing.T) {
ctx := context.Background()
ownerProject := "foo"
ownerAncestry := "organization/qux/folder/bar"
ownerAncestryPath := "organization/qux/folder/bar/project/foo"
Expand All @@ -75,11 +92,15 @@ func TestGetAncestry(t *testing.T) {
ts := newAncestryManagerMockServer(t, cache)
defer ts.Close()

amOnline, err := New(ctx, ownerProject, "", false, option.WithEndpoint(ts.URL), option.WithoutAuthentication())
// option.WithEndpoint(ts.URL), option.WithoutAuthentication()
trOnline := &testRetriever{online: true, opts: []option.ClientOption{option.WithEndpoint(ts.URL), option.WithoutAuthentication()}}
amOnline, err := New(trOnline, ownerProject, ownerAncestry, "", false)
if err != nil {
t.Fatalf("failed to create online ancestry manager: %s", err)
}
amOffline, err := New(ctx, ownerProject, ownerAncestry, true)

trOffline := &testRetriever{online: false}
amOffline, err := New(trOffline, ownerProject, ownerAncestry, "", true)
if err != nil {
t.Fatalf("failed to create offline ancestry manager: %s", err)
}
Expand Down
48 changes: 48 additions & 0 deletions cnvconfig/getconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2021 Google LLC
//
// Licensed 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 cnvconfig

import (
"context"

converter "github.com/GoogleCloudPlatform/terraform-google-conversion/google"
"github.com/pkg/errors"
)

func GetConfig(ctx context.Context, project string, offline bool) (*converter.Config, error) {
cfg := &converter.Config{
Project: project,
}

// Search for default credentials
cfg.Credentials = multiEnvSearch([]string{
"GOOGLE_CREDENTIALS",
"GOOGLE_CLOUD_KEYFILE_JSON",
"GCLOUD_KEYFILE_JSON",
})

cfg.AccessToken = multiEnvSearch([]string{
"GOOGLE_OAUTH_ACCESS_TOKEN",
})

if !offline {
converter.ConfigureBasePaths(cfg)
if err := cfg.LoadAndValidate(ctx); err != nil {
return nil, errors.Wrap(err, "load and validate config")
}
}

return cfg, nil
}
84 changes: 84 additions & 0 deletions cnvconfig/getconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package cnvconfig

import (
"context"
"os"
"testing"

converter "github.com/GoogleCloudPlatform/terraform-google-conversion/google"
"github.com/stretchr/testify/assert"
)

type configAttrGetter func(cfg *converter.Config) string

func getCredentials(cfg *converter.Config) string {
return cfg.Credentials
}
func getAccessToken(cfg *converter.Config) string {
return cfg.AccessToken
}

func TestNewConverterCredentials(t *testing.T) {
ctx := context.Background()
offline := true
cases := []struct {
name string
envKey string
envValue string
getConfigValue configAttrGetter
}{
{
name: "GOOGLE_CREDENTIALS",
envKey: "GOOGLE_CREDENTIALS",
envValue: "whatever",
getConfigValue: getCredentials,
},
{
name: "GOOGLE_CLOUD_KEYFILE_JSON",
envKey: "GOOGLE_CLOUD_KEYFILE_JSON",
envValue: "whatever",
getConfigValue: getCredentials,
},
{
name: "GCLOUD_KEYFILE_JSON",
envKey: "GCLOUD_KEYFILE_JSON",
envValue: "whatever",
getConfigValue: getCredentials,
},
{
name: "GOOGLE_OAUTH_ACCESS_TOKEN",
envKey: "GOOGLE_OAUTH_ACCESS_TOKEN",
envValue: "whatever",
getConfigValue: getAccessToken,
},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
originalValue, isSet := os.LookupEnv(c.envKey)
err := os.Setenv(c.envKey, c.envValue)
if err != nil {
t.Fatalf("error setting env var %s=%s: %s", c.envKey, c.envValue, err)
}

cfg, err := GetConfig(ctx, "project", offline)
if err != nil {
t.Fatalf("error building converter: %s", err)
}

assert.EqualValues(t, c.getConfigValue(cfg), c.envValue)

if isSet {
err = os.Setenv(c.envKey, originalValue)
if err != nil {
t.Fatalf("error setting env var %s=%s: %s", c.envKey, originalValue, err)
}
} else {
err = os.Unsetenv(c.envKey)
if err != nil {
t.Fatalf("error unsetting env var %s: %s", c.envKey, err)
}
}
})
}
}
2 changes: 1 addition & 1 deletion converters/google/utils.go → cnvconfig/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// 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 google
package cnvconfig

import (
"os"
Expand Down
25 changes: 2 additions & 23 deletions converters/google/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package google

import (
"context"
errorssyslib "errors"
"fmt"
"sort"
Expand Down Expand Up @@ -127,27 +126,7 @@ type RestoreDefault struct {
}

// NewConverter is a factory function for Converter.
func NewConverter(ctx context.Context, ancestryManager ancestrymanager.AncestryManager, project string, offline, convertUnchanged bool) (*Converter, error) {
cfg := &converter.Config{
Project: project,
}
// Search for default credentials
cfg.Credentials = multiEnvSearch([]string{
"GOOGLE_CREDENTIALS",
"GOOGLE_CLOUD_KEYFILE_JSON",
"GCLOUD_KEYFILE_JSON",
})

cfg.AccessToken = multiEnvSearch([]string{
"GOOGLE_OAUTH_ACCESS_TOKEN",
})
if !offline {
converter.ConfigureBasePaths(cfg)
if err := cfg.LoadAndValidate(ctx); err != nil {
return nil, errors.Wrap(err, "load and validate config")
}
}

func NewConverter(cfg *converter.Config, ancestryManager ancestrymanager.AncestryManager, offline bool, convertUnchanged bool) *Converter {
return &Converter{
schema: provider.Provider(),
mapperFuncs: converter.Mappers(),
Expand All @@ -156,7 +135,7 @@ func NewConverter(ctx context.Context, ancestryManager ancestrymanager.AncestryM
ancestryManager: ancestryManager,
assets: make(map[string]Asset),
convertUnchanged: convertUnchanged,
}, nil
}
}

// Converter knows how to convert terraform resources to their
Expand Down
Loading

0 comments on commit c37093e

Please sign in to comment.