From 9fa97ef8c24227dcb1d7c8e2d510f7f7117c8bed Mon Sep 17 00:00:00 2001 From: Bevan Arps Date: Thu, 12 Dec 2024 11:12:05 +1300 Subject: [PATCH] Idiomatic resource naming for asoctl (#4487) * Add conc library * Create importFactory and test * Consume factory * Move naming to the factory * Add createUniqueKubernetesName and consume * Format code * Avoid deadlock when panic occurs during import * Avoid closing the chan early * Remove use of github.com/pkg/errors * go mod tidy * Fix specifier --- v2/cmd/asoctl/cmd/import_azure_resource.go | 12 +- v2/cmd/asoctl/go.mod | 34 --- v2/cmd/asoctl/go.sum | 95 --------- .../pkg/importresources/import_factory.go | 193 ++++++++++++++++++ .../importresources/import_factory_test.go | 173 ++++++++++++++++ .../importable_arm_resource.go | 143 +++++-------- .../importable_arm_resource_test.go | 58 +----- .../importresources/importable_resource.go | 66 +----- .../pkg/importresources/resource_importer.go | 14 +- 9 files changed, 440 insertions(+), 348 deletions(-) create mode 100644 v2/cmd/asoctl/pkg/importresources/import_factory.go create mode 100644 v2/cmd/asoctl/pkg/importresources/import_factory_test.go diff --git a/v2/cmd/asoctl/cmd/import_azure_resource.go b/v2/cmd/asoctl/cmd/import_azure_resource.go index 47a9b0556eb..03b4189bf18 100644 --- a/v2/cmd/asoctl/cmd/import_azure_resource.go +++ b/v2/cmd/asoctl/cmd/import_azure_resource.go @@ -7,6 +7,7 @@ package cmd import ( "context" + "fmt" "io" "os" "sync" @@ -169,8 +170,15 @@ func importAzureResource( output = bar - // Ensure the progress bar is closed when we're done - defer bar.Wait() + // Ensure the progress bar is closed when we're done, but skip if a panic has happened + defer func() { + if p := recover(); p != nil { + os.Stderr.Write([]byte(fmt.Sprintf("panic: %s\n", p))) + } else { + // No panic + defer bar.Wait() + } + }() } importerOptions := importresources.ResourceImporterOptions{ diff --git a/v2/cmd/asoctl/go.mod b/v2/cmd/asoctl/go.mod index 4a2a78bd99a..0a681aa4698 100644 --- a/v2/cmd/asoctl/go.mod +++ b/v2/cmd/asoctl/go.mod @@ -51,25 +51,16 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription v1.2.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect - github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect @@ -85,9 +76,6 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hbollon/go-edlib v1.6.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -105,11 +93,9 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/microsoft/go-mssqldb v1.8.0 // indirect - github.com/moby/spdystream v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.20.5 // indirect @@ -121,20 +107,6 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/etcd/api/v3 v3.5.14 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect - go.etcd.io/etcd/client/v3 v3.5.14 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/sdk v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.30.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect @@ -146,20 +118,14 @@ require ( gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect - google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.35.1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiserver v0.31.3 // indirect - k8s.io/component-base v0.31.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kms v0.31.3 // indirect k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 // indirect k8s.io/utils v0.0.0-20240821151609-f90d01438635 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/v2/cmd/asoctl/go.sum b/v2/cmd/asoctl/go.sum index 651cb12ce86..860211afdca 100644 --- a/v2/cmd/asoctl/go.sum +++ b/v2/cmd/asoctl/go.sum @@ -60,29 +60,18 @@ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= -github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -99,17 +88,10 @@ github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lSh github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-logr/zerologr v1.2.3 h1:up5N9vcH9Xck3jJkXzgyOxozT14R47IyDODz8LM1KSs= @@ -137,8 +119,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= -github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -153,13 +133,6 @@ github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSF github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hbollon/go-edlib v1.6.0 h1:ga7AwwVIvP8mHm9GsPueC0d71cfRU/52hmPJ7Tprv4E= github.com/hbollon/go-edlib v1.6.0/go.mod h1:wnt6o6EIVEzUfgbUZY7BerzQ2uvzp354qmS2xaLkrhM= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= @@ -204,12 +177,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= -github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/microsoft/go-mssqldb v1.8.0 h1:7cyZ/AT7ycDsEoWPIXibd+aVKFtteUNhDGf3aobP+tw= github.com/microsoft/go-mssqldb v1.8.0/go.mod h1:6znkekS3T2vp0waiMhen4GPU1BiAsrP+iXHcE7a7rFo= -github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -217,12 +186,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo= github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/onsi/gomega v1.36.0 h1:Pb12RlruUtj4XUuPUqeEWc6j5DkVVVA49Uf6YLfC95Y= github.com/onsi/gomega v1.36.0/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -279,30 +244,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= -go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= -go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= -go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= -go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= -go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -312,8 +253,6 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= @@ -324,8 +263,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= @@ -333,8 +270,6 @@ golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -344,18 +279,12 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= @@ -376,8 +305,6 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1: google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -389,48 +316,26 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= -k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= -k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= -k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE= k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.3 h1:+1oHTtCB+OheqFEz375D0IlzHZ5VeQKX1KGXnx+TTuY= -k8s.io/apiserver v0.31.3/go.mod h1:PrxVbebxrxQPFhJk4powDISIROkNMKHibTg9lTRQ0Qg= -k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= -k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= -k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ= -k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.31.3 h1:XCFmiJn5CCKs8xoOLpCmu42Ubm/KW85wNHybGFcSAYc= -k8s.io/kms v0.31.3/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI= k8s.io/utils v0.0.0-20240821151609-f90d01438635/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= -sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/controller-runtime v0.19.2 h1:3sPrF58XQEPzbE8T81TN6selQIMGbtYwuaJ6eDssDF8= -sigs.k8s.io/controller-runtime v0.19.2/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/v2/cmd/asoctl/pkg/importresources/import_factory.go b/v2/cmd/asoctl/pkg/importresources/import_factory.go new file mode 100644 index 00000000000..d9d43d382e9 --- /dev/null +++ b/v2/cmd/asoctl/pkg/importresources/import_factory.go @@ -0,0 +1,193 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package importresources + +import ( + "crypto/rand" + "math/big" + "regexp" + "strings" + "sync" + "unicode" + + "github.com/rotisserie/eris" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/Azure/azure-service-operator/v2/internal/set" + "github.com/Azure/azure-service-operator/v2/pkg/genruntime" +) + +// importFactory is a helper struct that's used to create things. +type importFactory struct { + scheme *runtime.Scheme + usedNames map[schema.GroupKind]set.Set[string] + usedNamesLock sync.Mutex +} + +func newImportFactory( + scheme *runtime.Scheme, +) *importFactory { + return &importFactory{ + scheme: scheme, + usedNames: make(map[schema.GroupKind]set.Set[string]), + } +} + +// createBlankObjectFromGVK creates a blank object of from a given GVK. +func (f *importFactory) createBlankObjectFromGVK(gvk schema.GroupVersionKind) (runtime.Object, error) { + obj, err := f.scheme.New(gvk) + if err != nil { + return nil, eris.Wrap(err, "unable to create blank resource") + } + + obj.GetObjectKind().SetGroupVersionKind(gvk) + return obj, nil +} + +// selectVersionFromGK selects the latest version of a given GroupKind. +// The latest stable version will be selected if it exists, otherwise the latest preview version will be selected. +func (f *importFactory) selectVersionFromGK(gk schema.GroupKind) (schema.GroupVersionKind, error) { + knownVersions := f.scheme.VersionsForGroupKind(gk) + if len(knownVersions) == 0 { + return schema.GroupVersionKind{}, + eris.Errorf( + "no known versions for Group %s, Kind %s", + gk.Group, + gk.Kind) + } + + // Scan for the GVK that implements genruntime.ImportableResource + // We expect there to be exactly one + var result *schema.GroupVersionKind + for _, gv := range knownVersions { + gvk := gk.WithVersion(gv.Version) + obj, err := f.createBlankObjectFromGVK(gvk) + if err != nil { + return schema.GroupVersionKind{}, eris.Wrapf(err, "unable to create blank resource for GVK %s", gvk) + } + + if _, ok := obj.(genruntime.ImportableResource); ok { + if result != nil { + return schema.GroupVersionKind{}, + eris.Errorf( + "multiple known versions for Group %s, Kind %s implement genruntime.ImportableResource", + gk.Group, + gk.Kind) + } + + result = &gvk + } + } + + if result == nil { + return schema.GroupVersionKind{}, + eris.Errorf( + "no known versions for Group %s, Kind %s implement genruntime.ImportableResource", + gk.Group, + gk.Kind) + } + + return *result, nil +} + +// createUniqueKubernetesName creates a name that is unique within a given resource type. +func (f *importFactory) createUniqueKubernetesName( + name string, + gk schema.GroupKind, +) string { + // Only one object of a given kind can have a given name at a time. + // See https://kubernetes.io/docs/concepts/overview/working-with-objects/names/ + + // Protect against concurrent access to the usedNames map + f.usedNamesLock.Lock() + defer f.usedNamesLock.Unlock() + + used, knownGK := f.usedNames[gk] + if !knownGK { + used = set.Make[string]() + f.usedNames[gk] = used + } + + baseName := f.createKubernetesName(name) + suffix := "" + for { + uniqueName := baseName + if suffix != "" { + uniqueName = baseName + "-" + suffix + } + + if !used.Contains(uniqueName) { + used.Add(uniqueName) + return uniqueName + } + + suffix = f.createSuffix(6) + } +} + +var suffixRunes = []rune("abcdefghijklmnopqrstuvwxyz") + +func (f *importFactory) createSuffix(size int) string { + buffer := make([]rune, 0, size) + + for range size { + rnge := big.NewInt(int64(len(suffixRunes))) + index, err := rand.Int(rand.Reader, rnge) + if err != nil { + // This should never happen + panic(err) + } + + i := int(index.Int64()) + buffer = append(buffer, suffixRunes[i]) + } + + return string(buffer) +} + +var kubernetesNameRegex = regexp.MustCompile("-+") + +// createKubernetesName creates a name compliant with kubernetes naming conventions. +func (f *importFactory) createKubernetesName( + name string, +) string { + // Most resource types require a name that can be used as a DNS subdomain name as defined in RFC 1123. + // This means the name must: + // o contain no more than 253 characters + // o contain only lowercase alphanumeric characters, '-' or '.' + // o start with an alphanumeric character + // o end with an alphanumeric character + // See https://kubernetes.io/docs/concepts/overview/working-with-objects/names/ + + buffer := make([]rune, 0, len(name)) + + for _, r := range name { + switch { + case unicode.IsLetter(r): + // Transform letters to lowercase + buffer = append(buffer, unicode.ToLower(r)) + + case unicode.IsNumber(r): + // Keep numbers as they are + buffer = append(buffer, r) + + default: + // Any other characters are converted to hyphens + buffer = append(buffer, '-') + } + } + + result := string(buffer) + + // Collapse any sequences of hyphens into a single hyphen + result = kubernetesNameRegex.ReplaceAllString(result, "-") + + // Remove any leading or trailing hyphens + result = strings.Trim(result, "-") + + return result +} diff --git a/v2/cmd/asoctl/pkg/importresources/import_factory_test.go b/v2/cmd/asoctl/pkg/importresources/import_factory_test.go new file mode 100644 index 00000000000..5ae3fde8cca --- /dev/null +++ b/v2/cmd/asoctl/pkg/importresources/import_factory_test.go @@ -0,0 +1,173 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package importresources + +import ( + "testing" + + . "github.com/onsi/gomega" + + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/Azure/azure-service-operator/v2/api" +) + +func Test_selectVersionFromGK_givenGK_returnsExpectedVersion(t *testing.T) { + t.Parallel() + + cases := map[string]struct { + group string + kind string + expectedVersion string + expectedError string + }{ + "Batch Account": { + group: "batch.azure.com", + kind: "BatchAccount", + expectedVersion: "v1api20210101", + }, + "Managed Cluster": { + group: "containerservice.azure.com", + kind: "ManagedCluster", + expectedVersion: "v1api20240901", + }, + "Coffee isn't supported": { + group: "coffee.azure.com", + kind: "Latte", + expectedError: "no known versions for Group coffee.azure.com, Kind Latte", + }, + } + + factory := newImportFactory(api.CreateScheme()) + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + t.Parallel() + g := NewGomegaWithT(t) + + gk := schema.GroupKind{ + Group: c.group, + Kind: c.kind, + } + + gvk, err := factory.selectVersionFromGK(gk) + + // This check will start failing if/when a newer version of the resource being tested is added. + // This is expected, just update the test to reflect the new version. + if c.expectedVersion != "" { + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(gvk.Version).To(Equal(c.expectedVersion)) + } + + if c.expectedError != "" { + g.Expect(err).To(HaveOccurred()) + g.Expect(err.Error()).To(ContainSubstring(c.expectedError)) + } + }) + } +} + +func Test_createBlankObjectFromGVK_GivenGVK_returnsExpectedInstance(t *testing.T) { + t.Parallel() + + cases := map[string]struct { + group string + kind string + version string + }{ + "Batch Account": { + group: "batch.azure.com", + kind: "BatchAccount", + version: "v1api20210101", + }, + "Managed Cluster": { + group: "containerservice.azure.com", + kind: "ManagedCluster", + version: "v1api20240901", + }, + } + + factory := newImportFactory(api.CreateScheme()) + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + t.Parallel() + g := NewGomegaWithT(t) + + gvk := schema.GroupVersionKind{ + Group: c.group, + Kind: c.kind, + Version: c.version, + } + + obj, err := factory.createBlankObjectFromGVK(gvk) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(obj.GetObjectKind().GroupVersionKind()).To(Equal(gvk)) + }) + } +} + +func Test_createKubernetesName_givenResourceNames_returnsExpectedName(t *testing.T) { + t.Parallel() + + cases := map[string]struct { + name string + expected string + }{ + "Simple Name": { + name: "simple-name", + expected: "simple-name", + }, + "Guid": { + name: "760b841c-091e-43fa-92c3-03b38f5d680e", + expected: "760b841c-091e-43fa-92c3-03b38f5d680e", + }, + "Name with underscores": { + name: "testpgb01-authentication_timeout", + expected: "testpgb01-authentication-timeout", + }, + "simple": { + name: "simple", + expected: "simple", + }, + "with spaces": { + name: "with spaces", + expected: "with-spaces", + }, + "with special characters": { + name: "with!@#$%^&*()_+special characters", + expected: "with-special-characters", + }, + "with underscores": { + name: "with_underscores", + expected: "with-underscores", + }, + "with multiple spaces": { + name: "with multiple spaces", + expected: "with-multiple-spaces", + }, + "with linux style paths": { + name: "/path/to/resource", + expected: "path-to-resource", + }, + "with windows style paths": { + name: "\\path\\to\\resource", + expected: "path-to-resource", + }, + } + + factory := newImportFactory(api.CreateScheme()) + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + t.Parallel() + g := NewGomegaWithT(t) + + result := factory.createKubernetesName(c.name) + g.Expect(result).To(Equal(c.expected)) + }) + } +} diff --git a/v2/cmd/asoctl/pkg/importresources/importable_arm_resource.go b/v2/cmd/asoctl/pkg/importresources/importable_arm_resource.go index a90dcae9aec..d52257ca4e4 100644 --- a/v2/cmd/asoctl/pkg/importresources/importable_arm_resource.go +++ b/v2/cmd/asoctl/pkg/importresources/importable_arm_resource.go @@ -10,16 +10,13 @@ import ( "fmt" "net/http" "reflect" - "regexp" "strings" "sync" - "unicode" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/go-logr/logr" "github.com/rotisserie/eris" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" kerrors "k8s.io/apimachinery/pkg/util/errors" @@ -33,7 +30,6 @@ import ( ) type importableARMResource struct { - importableResource armID *arm.ResourceID // The ARM ID of the resource to import owner *genruntime.ResourceReference // The owner of the resource we're importing client *genericarmclient.GenericClient // client for talking to ARM @@ -50,12 +46,10 @@ var ( // id is the ARM ID of the resource to import. // owner is the resource that owns this resource (if any). // client is the client to use to talk to ARM. -// scheme is the scheme to use to create the resource. func NewImportableARMResource( id string, owner *genruntime.ResourceReference, client *genericarmclient.GenericClient, - scheme *runtime.Scheme, ) (ImportableResource, error) { // Parse id into a more useful form armID, err := arm.ParseResourceID(id) @@ -64,9 +58,6 @@ func NewImportableARMResource( } return &importableARMResource{ - importableResource: importableResource{ - scheme: scheme, - }, armID: armID, owner: owner, client: client, @@ -101,10 +92,11 @@ func (i *importableARMResource) Resource() genruntime.MetaObject { func (i *importableARMResource) Import( ctx context.Context, progress importreporter.Interface, + factory *importFactory, _ logr.Logger, ) (ImportResourceResult, error) { // Create an importable blank object into which we capture the current state of the resource - importable, err := i.createImportableObjectFromID(i.owner, i.armID) + importable, err := i.createImportableObjectFromID(i.owner, i.armID, factory) if err != nil { // Error doesn't need additional context return ImportResourceResult{}, err @@ -112,7 +104,7 @@ func (i *importableARMResource) Import( // Our resource might have an extension that can customize the import process, // so we have a factory to create the loader function we call. - loader := i.createImportFunction(importable) + loader := i.createImportFunction(importable, factory) loaderResult, err := loader(ctx, importable, i.owner) if err != nil { i.err = err @@ -130,7 +122,7 @@ func (i *importableARMResource) Import( resource: i, } - if children, err := i.findChildren(ctx, progress); err != nil { + if children, err := i.findChildren(ctx, progress, factory); err != nil { return result, err } else { result.pending = children @@ -146,6 +138,7 @@ func (i *importableARMResource) Import( func (i *importableARMResource) findChildren( ctx context.Context, progress importreporter.Interface, + factory *importFactory, ) ([]ImportableResource, error) { if i.resource == nil { // Nothing to do @@ -186,7 +179,7 @@ func (i *importableARMResource) findChildren( var result []ImportableResource var errs []error for _, subType := range childTypes { - childResources, err := i.importChildResources(ctx, ref, subType) + childResources, err := i.importChildResources(ctx, ref, subType, factory) if ctx.Err() != nil { // Aborting, don't do anything } else if err != nil { @@ -210,13 +203,14 @@ func (i *importableARMResource) findChildren( func (i *importableARMResource) createImportFunction( instance genruntime.ImportableARMResource, + factory *importFactory, ) extensions.ImporterFunc { // Loader is a function that does the actual loading, populating both the Spec and Status of the resource - loader := i.loader() + loader := i.loader(factory) // Check to see if we have an extension to customize loading, and if we do, wrap importFn to call the extension gvk := instance.GetObjectKind().GroupVersionKind() - if ex, ok := i.GetResourceExtension(gvk); ok { + if ex, ok := i.GetResourceExtension(gvk, factory); ok { next := loader loader = func( ctx context.Context, @@ -228,12 +222,14 @@ func (i *importableARMResource) createImportFunction( } // Lastly, we need to wrap importFn to remove Status so that it doesn't get included when we export the YAML - loader = i.clearStatus(loader) + loader = i.clearStatus(loader, factory) return loader } -func (i *importableARMResource) loader() extensions.ImporterFunc { +func (i *importableARMResource) loader( + factory *importFactory, +) extensions.ImporterFunc { return func( ctx context.Context, resource genruntime.ImportableResource, @@ -246,7 +242,7 @@ func (i *importableARMResource) loader() extensions.ImporterFunc { } // Get the current status of the object from ARM - status, err := i.getStatus(ctx, i.armID.String(), importable) + status, err := i.getStatus(ctx, i.armID.String(), importable, factory) if err != nil { // If the error is non-fatal, we can skip the resource but still process the rest if reason, nonfatal := i.classifyError(err); nonfatal { @@ -274,7 +270,10 @@ func (i *importableARMResource) loader() extensions.ImporterFunc { } } -func (i *importableARMResource) clearStatus(next extensions.ImporterFunc) extensions.ImporterFunc { +func (i *importableARMResource) clearStatus( + next extensions.ImporterFunc, + factory *importFactory, +) extensions.ImporterFunc { return func( ctx context.Context, resource genruntime.ImportableResource, @@ -292,7 +291,7 @@ func (i *importableARMResource) clearStatus(next extensions.ImporterFunc) extens } // Clear the status - status, err := genruntime.NewEmptyVersionedStatus(rsrc, i.scheme) + status, err := genruntime.NewEmptyVersionedStatus(rsrc, factory.scheme) if err != nil { return extensions.ImportResult{}, eris.Wrapf(err, "constructing status object for resource: %s", i.armID) @@ -311,6 +310,7 @@ func (i *importableARMResource) importChildResources( ctx context.Context, owner genruntime.ResourceReference, childResourceType string, + factory *importFactory, ) ([]ImportableResource, error) { // Look up the GK for the child resource type we're importing childResourceGK, ok := FindGroupKindForResourceType(childResourceType) @@ -319,13 +319,13 @@ func (i *importableARMResource) importChildResources( } // Expand from the GK to GVK - childResourceGVK, err := i.selectVersionFromGK(childResourceGK) + childResourceGVK, err := factory.selectVersionFromGK(childResourceGK) if err != nil { return nil, eris.Wrapf(err, "unable to find GVK for type %subType", childResourceType) } // Create an empty instance from the GVK, so we can find the ARM API version needed for the list call - obj, err := i.createBlankObjectFromGVK(childResourceGVK) + obj, err := factory.createBlankObjectFromGVK(childResourceGVK) if err != nil { return nil, eris.Wrap(err, "unable to create blank resource") } @@ -353,7 +353,7 @@ func (i *importableARMResource) importChildResources( subResources := make([]ImportableResource, 0, len(childResourceReferences)) for _, ref := range childResourceReferences { - importer, err := NewImportableARMResource(ref.ID, &owner, i.client, i.scheme) + importer, err := NewImportableARMResource(ref.ID, &owner, i.client) if err != nil { return nil, eris.Wrapf(err, "unable to create importable resource for %s", ref.ID) } @@ -404,6 +404,7 @@ func (*importableARMResource) classifyError(err error) (string, bool) { func (i *importableARMResource) createImportableObjectFromID( owner *genruntime.ResourceReference, armID *arm.ResourceID, + factory *importFactory, ) (resource genruntime.ImportableARMResource, err error) { defer func() { if r := recover(); r != nil { @@ -412,12 +413,12 @@ func (i *importableARMResource) createImportableObjectFromID( } }() - gvk, gvkErr := i.groupVersionKindFromID(armID) + gvk, gvkErr := i.groupVersionKindFromID(armID, factory) if gvkErr != nil { return nil, eris.Wrap(gvkErr, "unable to determine GVK of resource") } - obj, objErr := i.createBlankObjectFromGVK(gvk) + obj, objErr := factory.createBlankObjectFromGVK(gvk) if objErr != nil { return nil, eris.Wrap(objErr, "unable to create blank resource") } @@ -428,11 +429,13 @@ func (i *importableARMResource) createImportableObjectFromID( "unable to create blank resource, expected %s to identify an importable ARM object", armID) } + i.SetAzureName(armID.Name, importable) + + kubernetesName := factory.createUniqueKubernetesName(armID.Name, gvk.GroupKind()) + i.SetName(kubernetesName, importable) + if owner != nil { i.SetOwner(importable, *owner) - i.SetName(importable, armID.Name, *owner) - } else { - i.SetName(importable, armID.Name, genruntime.ResourceReference{}) } return importable, nil @@ -442,9 +445,10 @@ func (i *importableARMResource) getStatus( ctx context.Context, armID string, importable genruntime.ImportableARMResource, + factory *importFactory, ) (genruntime.ConvertibleStatus, error) { // Create an empty ARM status object into which we capture the current state of the resource - armStatus, err := genruntime.NewEmptyARMStatus(importable, i.scheme) + armStatus, err := genruntime.NewEmptyARMStatus(importable, factory.scheme) if err != nil { return nil, eris.Wrapf(err, "constructing ARM status for resource: %q", armID) } @@ -456,7 +460,7 @@ func (i *importableARMResource) getStatus( } // Convert the ARM shape to the Kube shape - status, err := genruntime.NewEmptyVersionedStatus(importable, i.scheme) + status, err := genruntime.NewEmptyVersionedStatus(importable, factory.scheme) if err != nil { return nil, eris.Wrapf(err, "constructing Kube status object for resource: %q", armID) } @@ -485,13 +489,16 @@ func (i *importableARMResource) getStatus( } // groupVersionKindFromID returns the GroupVersionKind for the resource we're importing -func (i *importableARMResource) groupVersionKindFromID(id *arm.ResourceID) (schema.GroupVersionKind, error) { +func (i *importableARMResource) groupVersionKindFromID( + id *arm.ResourceID, + factory *importFactory, +) (schema.GroupVersionKind, error) { gk, err := i.groupKindFromID(id) if err != nil { return schema.GroupVersionKind{}, err } - return i.selectVersionFromGK(gk) + return factory.selectVersionFromGK(gk) } // groupKindFromID parses a GroupKind from the resource URL, allowing us to look up the actual resource @@ -524,20 +531,16 @@ func (i *importableARMResource) createContainerURI(id *arm.ResourceID, subType s } func (i *importableARMResource) SetName( - importable genruntime.ImportableARMResource, name string, - owner genruntime.ResourceReference, + importable genruntime.ImportableARMResource, ) { - // Kubernetes' names are prefixed with the owner name to avoid collisions - n := name - if owner.Name != "" { - n = fmt.Sprintf("%s-%s", owner.Name, name) - } - - // Sanitise the name so it's a valid Kubernetes name - safeName := safeResourceName(n) - importable.SetName(safeName) + importable.SetName(name) +} +func (i *importableARMResource) SetAzureName( + name string, + importable genruntime.ImportableARMResource, +) { // AzureName needs to be exactly as specified in the ARM URL. // Use reflection to set it as we don't have convenient access. // Not all resources have the AzureName property - some resources @@ -587,53 +590,6 @@ func (i *importableARMResource) SetOwner( } } -var safeResourceNameMappings = map[rune]rune{ - '_': '-', // underscores are replaced with hyphens - '/': '-', // slashes are replaced with hyphens - '\\': '-', // backslashes are replaced with hyphens - '%': '-', // percent signs are replaced with hyphens -} - -var safeResourceNameRegex = regexp.MustCompile("-+") - -// safeResourceName ensures the name is a valid Kubernetes name -func safeResourceName(name string) string { - buffer := make([]rune, 0, len(name)) - - for _, r := range name { - - mapped, isMapped := safeResourceNameMappings[r] - - switch { - case unicode.IsLetter(r): - // Transform letters to lowercase - buffer = append(buffer, unicode.ToLower(r)) - - case unicode.IsNumber(r): - // Keep numbers as they are - buffer = append(buffer, r) - - case len(buffer) == 0: - // Discard leading special characters so that the result always starts with a letter or number - - case isMapped: - // Convert special characters - buffer = append(buffer, mapped) - - case unicode.IsSpace(r): - // Convert all kinds of spaces to hyphens - buffer = append(buffer, '-') - - default: - // Skip other characters - } - } - - result := string(buffer) - result = safeResourceNameRegex.ReplaceAllString(result, "-") - return result -} - type childReference struct { ID string `json:"id,omitempty"` } @@ -643,10 +599,13 @@ var ( resourceExtensionsOnce sync.Once ) -func (i *importableARMResource) GetResourceExtension(gvk schema.GroupVersionKind) (extensions.Importer, bool) { +func (i *importableARMResource) GetResourceExtension( + gvk schema.GroupVersionKind, + factory *importFactory, +) (extensions.Importer, bool) { resourceExtensionsOnce.Do(func() { var err error - resourceExtensions, err = controllers.GetResourceExtensions(i.scheme) + resourceExtensions, err = controllers.GetResourceExtensions(factory.scheme) if err != nil { panic(err) } diff --git a/v2/cmd/asoctl/pkg/importresources/importable_arm_resource_test.go b/v2/cmd/asoctl/pkg/importresources/importable_arm_resource_test.go index 7a1f62e7166..4d1f7f08e4f 100644 --- a/v2/cmd/asoctl/pkg/importresources/importable_arm_resource_test.go +++ b/v2/cmd/asoctl/pkg/importresources/importable_arm_resource_test.go @@ -142,12 +142,12 @@ func Test_ARMResourceImporter_GroupVersionKindFromARMID(t *testing.T) { }, } - factory := importableARMResource{ - importableResource: importableResource{ - scheme: api.CreateScheme(), - }, + factory := &importFactory{ + scheme: api.CreateScheme(), } + armRsrc := importableARMResource{} + for _, c := range cases { c := c t.Run(c.name, func(t *testing.T) { @@ -158,7 +158,7 @@ func Test_ARMResourceImporter_GroupVersionKindFromARMID(t *testing.T) { id, err := arm.ParseResourceID(c.armId) g.Expect(err).To(BeNil()) - gvk, err := factory.groupVersionKindFromID(id) + gvk, err := armRsrc.groupVersionKindFromID(id, factory) g.Expect(err).To(BeNil()) // If the asserts fail, check to see whether we've introduced a new version of the resource @@ -169,51 +169,3 @@ func Test_ARMResourceImporter_GroupVersionKindFromARMID(t *testing.T) { }) } } - -func Test_safeResourceName_GivenName_ReturnsExpectedResult(t *testing.T) { - t.Parallel() - - cases := map[string]struct { - name string - expected string - }{ - "simple": { - name: "simple", - expected: "simple", - }, - "with spaces": { - name: "with spaces", - expected: "with-spaces", - }, - "with special characters": { - name: "with!@#$%^&*()_+special characters", - expected: "with-special-characters", - }, - "with underscores": { - name: "with_underscores", - expected: "with-underscores", - }, - "with multiple spaces": { - name: "with multiple spaces", - expected: "with-multiple-spaces", - }, - "with linux style paths": { - name: "/path/to/resource", - expected: "path-to-resource", - }, - "with windows style paths": { - name: "\\path\\to\\resource", - expected: "path-to-resource", - }, - } - - for name, c := range cases { - c := c - t.Run(name, func(t *testing.T) { - t.Parallel() - - g := NewGomegaWithT(t) - g.Expect(safeResourceName(c.name)).To(Equal(c.expected)) - }) - } -} diff --git a/v2/cmd/asoctl/pkg/importresources/importable_resource.go b/v2/cmd/asoctl/pkg/importresources/importable_resource.go index b9c5fb89a4f..af8770ee73c 100644 --- a/v2/cmd/asoctl/pkg/importresources/importable_resource.go +++ b/v2/cmd/asoctl/pkg/importresources/importable_resource.go @@ -9,12 +9,9 @@ import ( "context" "github.com/go-logr/logr" - "github.com/rotisserie/eris" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "github.com/Azure/azure-service-operator/v2/cmd/asoctl/pkg/importreporter" - "github.com/Azure/azure-service-operator/v2/pkg/genruntime" ) // ImportableResource is an interface that wraps a Kubernetes resource that can be imported. @@ -38,68 +35,7 @@ type ImportableResource interface { Import( ctx context.Context, reporter importreporter.Interface, + factory *importFactory, log logr.Logger, ) (ImportResourceResult, error) } - -// importableResource is a core of common data and support methods for implementing ImportableResource -type importableResource struct { - scheme *runtime.Scheme -} - -// createBlankObjectFromGVK is a helper function to create a blank object of from a given GVK. -func (i *importableResource) createBlankObjectFromGVK(gvk schema.GroupVersionKind) (runtime.Object, error) { - obj, err := i.scheme.New(gvk) - if err != nil { - return nil, eris.Wrap(err, "unable to create blank resource") - } - - obj.GetObjectKind().SetGroupVersionKind(gvk) - return obj, nil -} - -// selectVersionFromGK is a helper function to select the latest version of a given GroupKind. -// The latest stable version will be selected if it exists, otherwise the latest preview version will be selected. -func (i *importableResource) selectVersionFromGK(gk schema.GroupKind) (schema.GroupVersionKind, error) { - knownVersions := i.scheme.VersionsForGroupKind(gk) - if len(knownVersions) == 0 { - return schema.GroupVersionKind{}, - eris.Errorf( - "no known versions for Group %s, Kind %s", - gk.Group, - gk.Kind) - } - - // Scan for the GVK that implements genruntime.ImportableResource - // We expect there to be exactly one - var result *schema.GroupVersionKind - for _, gv := range knownVersions { - gvk := gk.WithVersion(gv.Version) - obj, err := i.createBlankObjectFromGVK(gvk) - if err != nil { - return schema.GroupVersionKind{}, eris.Wrapf(err, "unable to create blank resource for GVK %s", gvk) - } - - if _, ok := obj.(genruntime.ImportableResource); ok { - if result != nil { - return schema.GroupVersionKind{}, - eris.Errorf( - "multiple known versions for Group %s, Kind %s implement genruntime.ImportableResource", - gk.Group, - gk.Kind) - } - - result = &gvk - } - } - - if result == nil { - return schema.GroupVersionKind{}, - eris.Errorf( - "no known versions for Group %s, Kind %s implement genruntime.ImportableResource", - gk.Group, - gk.Kind) - } - - return *result, nil -} diff --git a/v2/cmd/asoctl/pkg/importresources/resource_importer.go b/v2/cmd/asoctl/pkg/importresources/resource_importer.go index ed47a46771a..7f17bac3f1e 100644 --- a/v2/cmd/asoctl/pkg/importresources/resource_importer.go +++ b/v2/cmd/asoctl/pkg/importresources/resource_importer.go @@ -23,7 +23,7 @@ import ( // ResourceImporter is the entry point for importing resources. // Factory methods here provide ways to instantiate importers for different kinds of resources. type ResourceImporter struct { - scheme *runtime.Scheme // a reference to the scheme used by asoctl + factory *importFactory // Shared factory used to create resources and other things client *genericarmclient.GenericClient // Client to use when talking to ARM resources []ImportableResource // A slice of resources to be imported imported map[string]ImportedResource // A set of importers that have been successfully imported @@ -52,7 +52,7 @@ func New( options ResourceImporterOptions, ) *ResourceImporter { return &ResourceImporter{ - scheme: scheme, + factory: newImportFactory(scheme), client: client, imported: make(map[string]ImportedResource), log: log, @@ -68,7 +68,7 @@ func (ri *ResourceImporter) Add(importer ImportableResource) { // AddARMID adds an ARM ID to the list of resources to import. func (ri *ResourceImporter) AddARMID(armID string) error { - importer, err := NewImportableARMResource(armID, nil /* no owner */, ri.client, ri.scheme) + importer, err := NewImportableARMResource(armID, nil /* no owner */, ri.client) if err != nil { return eris.Wrapf(err, "failed to create importer for %q", armID) } @@ -151,10 +151,10 @@ func (ri *ResourceImporter) startDeduplicator( uniqueResources := make(chan ImportableResource) - // Close the channel when we're done, so that workers shut down too - defer close(uniqueResources) - waitgroup.Go(func() { + // Close the channel when we're done, so that workers shut down too + defer close(uniqueResources) + run: for { // Dequeue from our internal buffer if needed @@ -355,7 +355,7 @@ func (ri *ResourceImporter) importResource( defer progress.Completed(1) // Import the resource itself - if imported, err := rsrc.Import(ctx, progress, ri.log); err != nil { + if imported, err := rsrc.Import(ctx, progress, ri.factory, ri.log); err != nil { return ImportResourceResult{}, eris.Wrapf(err, "importing %s", name) } else { return imported, nil