func Run(rn runner.Runner, importRn runner.Runner, runArgs *RunArgs) error {
	inputDir, err := fileutil.Expand(runArgs.InputDir)
	if err != nil {
		return fmt.Errorf("expand path %q: %v", inputDir, err)
	}
	var successesTotal, failuresTotal []string
	skipped := make(map[string]string)
	var ie *importError
	for {
		failuresTotal = nil
		successes, err := planAndImport(rn, importRn, runArgs, skipped)
		successesTotal = append(successesTotal, successes...)
		if err == nil {
			break
		}
		if !errors.As(err, &ie) {
			return err
		}
		failuresTotal = ie.errMsgs
		if len(successes) <= 0 {
			break
		}
		log.Println("Some imports succeeded but others did not. Retrying the import, in case dependent values have now been populated.")
	}
	buf, err := template.WriteBuffer(summaryTmpl, map[string]interface{}{
		"total":     len(successesTotal) + len(skipped) + len(failuresTotal),
		"successes": successesTotal,
		"skipped":   skipped,
		"failures":  failuresTotal,
	})
	if err != nil {
		return fmt.Errorf("building summary template: %v", err)
	}
	log.Printf("%s\n", buf)
	if ie != nil {
		return ie
	}
	return nil
}
Run executes the main tfimport logic.
package tfimport
import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"regexp"
	"strings"
	"github.com/GoogleCloudPlatform/healthcare-data-protection-suite/internal/fileutil"
	"github.com/GoogleCloudPlatform/healthcare-data-protection-suite/internal/runner"
	"github.com/GoogleCloudPlatform/healthcare-data-protection-suite/internal/template"
	"github.com/GoogleCloudPlatform/healthcare-data-protection-suite/internal/terraform"
	"github.com/GoogleCloudPlatform/healthcare-data-protection-suite/internal/tfimport/importer"
)
var kubernetesImporter = &importer.SimpleImporter{
	Fields: []string{"metadata"},
	Tmpl:   "{{or (index .metadata \"namespace\") \"default\"}}/{{.metadata.name}}",
}
var kubernetesAlphaImporter = &importer.SimpleImporter{
	Fields: []string{"manifest"},
	Tmpl:   "{{or (index .manifest.metadata \"namespace\") \"default\"}}/{{.manifest.metadata.name}}",
}
var Importers = map[string]resourceImporter{
	"google_app_engine_application": &importer.SimpleImporter{
		Fields: []string{"project"},
		Tmpl:   "{{.project}}",
	},
	"google_bigquery_dataset": &importer.SimpleImporter{
		Fields: []string{"project", "dataset_id"},
		Tmpl:   "projects/{{.project}}/datasets/{{.dataset_id}}",
	},
	"google_bigquery_table": &importer.SimpleImporter{
		Fields: []string{"project", "dataset_id", "table_id"},
		Tmpl:   "{{.project}}/{{.dataset_id}}/{{.table_id}}",
	},
	"google_billing_account_iam_binding": &importer.SimpleImporter{
		Fields: []string{"billing_account_id", "role"},
		Tmpl:   "{{.billing_account_id}} {{.role}}",
	},
	"google_billing_account_iam_member": &importer.SimpleImporter{
		Fields: []string{"billing_account_id", "role", "member"},
		Tmpl:   "{{.billing_account_id}} {{.role}} {{.member}}",
	},
	"google_billing_account_iam_policy": &importer.SimpleImporter{
		Fields: []string{"billing_account_id"},
		Tmpl:   "{{.billing_account_id}}",
	},
	"google_billing_budget": &importer.BillingBudget{},
	"google_binary_authorization_policy": &importer.SimpleImporter{
		Fields: []string{"project"},
		Tmpl:   "projects/{{.project}}",
	},
	"google_cloudbuild_trigger": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/triggers/{{.name}}",
	},
	"google_compute_address": &importer.SimpleImporter{
		Fields: []string{"project", "region", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/addresses/{{.name}}",
	},
	"google_compute_firewall": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/global/firewalls/{{.name}}",
	},
	"google_compute_forwarding_rule": &importer.SimpleImporter{
		Fields: []string{"project", "region", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/forwardingRules/{{.name}}",
	},
	"google_compute_global_address": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/global/addresses/{{.name}}",
	},
	"google_compute_health_check": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/global/healthChecks/{{.name}}",
	},
	"google_compute_image": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/global/images/{{.name}}",
	},
	"google_compute_instance": &importer.SimpleImporter{
		Fields: []string{"project", "zone", "name"},
		Tmpl:   "projects/{{.project}}/zones/{{.zone}}/instances/{{.name}}",
	},
	"google_compute_instance_template": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/global/instanceTemplates/{{.name}}",
	},
	"google_compute_instance_from_template": &importer.SimpleImporter{
		Fields: []string{"project", "zone", "name"},
		Tmpl:   "projects/{{.project}}/zones/{{.zone}}/instances/{{.name}}",
	},
	"google_compute_interconnect_attachment": &importer.SimpleImporter{
		Fields: []string{"project", "region", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/interconnectAttachments/{{.name}}",
	},
	"google_compute_network": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/global/networks/{{.name}}",
	},
	"google_compute_network_peering": &importer.ComputeNetworkPeering{},
	"google_compute_project_metadata_item": &importer.SimpleImporter{
		Fields: []string{"key"},
		Tmpl:   "{{.key}}",
	},
	"google_compute_region_backend_service": &importer.SimpleImporter{
		Fields: []string{"project", "region", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/backendServices/{{.name}}",
	},
	"google_compute_route": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/global/routes/{{.name}}",
	},
	"google_compute_router": &importer.SimpleImporter{
		Fields: []string{"project", "region", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/routers/{{.name}}",
	},
	"google_compute_router_interface": &importer.SimpleImporter{
		Fields: []string{"region", "router", "name"},
		Tmpl:   "{{.region}}/{{.router}}/{{.name}}",
	},
	"google_compute_router_nat": &importer.SimpleImporter{
		Fields: []string{"project", "region", "router", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/routers/{{.router}}/{{.name}}",
	},
	"google_compute_router_peer": &importer.SimpleImporter{
		Fields: []string{"project", "region", "router", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/routers/{{.router}}/{{.name}}",
	},
	"google_compute_shared_vpc_host_project": &importer.SimpleImporter{
		Fields: []string{"project"},
		Tmpl:   "{{.project}}",
	},
	"google_compute_shared_vpc_service_project": &importer.SimpleImporter{
		Fields: []string{"host_project", "service_project"},
		Tmpl:   "{{.host_project}}/{{.service_project}}",
	},
	"google_compute_subnetwork": &importer.SimpleImporter{
		Fields: []string{"project", "region", "name"},
		Tmpl:   "projects/{{.project}}/regions/{{.region}}/subnetworks/{{.name}}",
	},
	"google_compute_subnetwork_iam_binding": &importer.SimpleImporter{
		Fields: []string{"subnetwork", "role"},
		Tmpl:   "{{.subnetwork}} {{.role}}",
	},
	"google_compute_subnetwork_iam_member": &importer.SimpleImporter{
		Fields: []string{"subnetwork", "role", "member"},
		Tmpl:   "{{.subnetwork}} {{.role}} {{.member}}",
	},
	"google_compute_subnetwork_iam_policy": &importer.SimpleImporter{
		Fields: []string{"subnetwork"},
		Tmpl:   "{{.subnetwork}}",
	},
	"google_container_cluster": &importer.SimpleImporter{
		Fields: []string{"project", "location", "name"},
		Tmpl:   "projects/{{.project}}/locations/{{.location}}/clusters/{{.name}}",
	},
	"google_container_node_pool": &importer.SimpleImporter{
		Fields: []string{"project", "location", "cluster", "name"},
		Tmpl:   "{{.project}}/{{.location}}/{{.cluster}}/{{.name}}",
	},
	"google_dns_managed_zone": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/managedZones/{{.name}}",
	},
	"google_dns_record_set": &importer.SimpleImporter{
		Fields: []string{"project", "managed_zone", "name", "type"},
		Tmpl:   "{{.project}}/{{.managed_zone}}/{{.name}}/{{.type}}",
	},
	"google_firebase_project": &importer.SimpleImporter{
		Fields: []string{"project"},
		Tmpl:   "projects/{{.project}}",
	},
	"google_folder": &importer.SimpleImporter{
		Fields: []string{"folder_id"},
		Tmpl:   "folders/{{.folder_id}}",
	},
	"google_folder_iam_binding": &importer.SimpleImporter{
		Fields: []string{"folder", "role"},
		Tmpl:   "{{.folder}} {{.role}}",
	},
	"google_folder_iam_member": &importer.SimpleImporter{
		Fields: []string{"folder", "role", "member"},
		Tmpl:   "{{.folder}} {{.role}} {{.member}}",
	},
	"google_folder_iam_policy": &importer.SimpleImporter{
		Fields: []string{"folder"},
		Tmpl:   "{{.folder}}",
	},
	"google_folder_organization_policy": &importer.SimpleImporter{
		Fields: []string{"folder", "constraint"},
		Tmpl:   "folders/{{.folder}}/constraints/{{.constraint}}",
	},
	"google_iap_tunnel_instance_iam_binding": &importer.SimpleImporter{
		Fields: []string{"project", "zone", "instance", "role"},
		Tmpl:   "projects/{{.project}}/iap_tunnel/zones/{{.zone}}/instances/{{.instance}} {{.role}}",
	},
	"google_iap_tunnel_instance_iam_member": &importer.SimpleImporter{
		Fields: []string{"project", "zone", "instance", "role", "member"},
		Tmpl:   "projects/{{.project}}/iap_tunnel/zones/{{.zone}}/instances/{{.instance}} {{.role}} {{.member}}",
	},
	"google_iap_tunnel_instance_iam_policy": &importer.SimpleImporter{
		Fields: []string{"project", "zone", "instance"},
		Tmpl:   "projects/{{.project}}/iap_tunnel/zones/{{.zone}}/instances/{{.instance}}",
	},
	"google_kms_key_ring": &importer.SimpleImporter{
		Fields: []string{"project", "location", "name"},
		Tmpl:   "projects/{{.project}}/locations/{{.location}}/keyRings/{{.name}}",
	},
	"google_logging_billing_account_sink": &importer.SimpleImporter{
		Fields: []string{"billing_account", "name"},
		Tmpl:   "billingAccounts/{{.billing_account}}/sinks/{{.name}}",
	},
	"google_logging_folder_sink": &importer.SimpleImporter{
		Fields: []string{"folder", "name"},
		Tmpl:   "folders/{{.folder}}/sinks/{{.name}}",
	},
	"google_logging_metric": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "{{.project}} {{.name}}",
	},
	"google_logging_organization_sink": &importer.SimpleImporter{
		Fields: []string{"org_id", "name"},
		Tmpl:   "organizations/{{.org_id}}/sinks/{{.name}}",
	},
	"google_logging_project_sink": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/sinks/{{.name}}",
	},
	"google_organization_iam_audit_config": &importer.SimpleImporter{
		Fields: []string{"org_id", "service"},
		Tmpl:   "{{.org_id}} {{.service}}",
	},
	"google_organization_iam_custom_role": &importer.SimpleImporter{
		Fields: []string{"org_id", "role_id"},
		Tmpl:   "organizations/{{.org_id}}/roles/{{.role_id}}",
	},
	"google_organization_iam_member": &importer.SimpleImporter{
		Fields: []string{"org_id", "role", "member"},
		Tmpl:   "{{.org_id}} {{.role}} {{.member}}",
	},
	"google_organization_policy": &importer.SimpleImporter{
		Fields: []string{"org_id", "constraint"},
		Tmpl:   "{{.org_id}}/constraints/{{.constraint}}",
	},
	"google_project": &importer.SimpleImporter{
		Fields: []string{"project_id"},
		Tmpl:   "{{.project_id}}",
	},
	"google_project_iam_audit_config": &importer.SimpleImporter{
		Fields: []string{"project", "service"},
		Tmpl:   "{{.project}} {{.service}}",
	},
	"google_project_iam_binding": &importer.SimpleImporter{
		Fields: []string{"project", "role"},
		Tmpl:   "{{.project}} {{.role}}",
	},
	"google_project_iam_custom_role": &importer.SimpleImporter{
		Fields: []string{"project", "role_id"},
		Tmpl:   "projects/{{.project}}/roles/{{.role_id}}",
	},
	"google_project_iam_member": &importer.SimpleImporter{
		Fields: []string{"project", "role", "member"},
		Tmpl:   "{{.project}} {{.role}} {{.member}}",
	},
	"google_project_organization_policy": &importer.SimpleImporter{
		Fields: []string{"project", "constraint"},
		Tmpl:   "projects/{{.project}}:constraints/{{.constraint}}",
	},
	"google_project_service": &importer.SimpleImporter{
		Fields: []string{"project", "service"},
		Tmpl:   "{{.project}}/{{.service}}",
	},
	"google_project_usage_export_bucket": &importer.SimpleImporter{
		Fields: []string{"project"},
		Tmpl:   "{{.project}}",
	},
	"google_pubsub_subscription": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/subscriptions/{{.name}}",
	},
	"google_pubsub_subscription_iam_binding": &importer.SimpleImporter{
		Fields: []string{"project", "subscription", "role"},
		Tmpl:   "projects/{{.project}}/subscriptions/{{.subscription}} {{.role}}",
	},
	"google_pubsub_subscription_iam_member": &importer.SimpleImporter{
		Fields: []string{"project", "subscription", "role", "member"},
		Tmpl:   "projects/{{.project}}/subscriptions/{{.subscription}} {{.role}} {{.member}}",
	},
	"google_pubsub_subscription_iam_policy": &importer.SimpleImporter{
		Fields: []string{"project", "subscription"},
		Tmpl:   "projects/{{.project}}/subscriptions/{{.subscription}}",
	},
	"google_pubsub_topic": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/topics/{{.name}}",
	},
	"google_pubsub_topic_iam_binding": &importer.SimpleImporter{
		Fields: []string{"project", "topic", "role"},
		Tmpl:   "projects/{{.project}}/topics/{{.topic}} {{.role}}",
	},
	"google_pubsub_topic_iam_member": &importer.SimpleImporter{
		Fields: []string{"project", "topic", "role", "member"},
		Tmpl:   "projects/{{.project}}/topics/{{.topic}} {{.role}} {{.member}}",
	},
	"google_pubsub_topic_iam_policy": &importer.SimpleImporter{
		Fields: []string{"project", "topic"},
		Tmpl:   "projects/{{.project}}/topics/{{.topic}}",
	},
	"google_resource_manager_lien": &importer.ResourceManagerLien{},
	"google_secret_manager_secret": &importer.SimpleImporter{
		Fields: []string{"project", "secret_id"},
		Tmpl:   "projects/{{.project}}/secrets/{{.secret_id}}",
	},
	"google_secret_manager_secret_version": &importer.SimpleImporter{
		Fields: []string{"secret"},
		Tmpl:   "{{.secret}}/versions/latest",
	},
	"google_service_account": &importer.SimpleImporter{
		Fields: []string{"project", "account_id"},
		Tmpl:   "projects/{{.project}}/serviceAccounts/{{.account_id}}@{{.project}}.iam.gserviceaccount.com",
	},
	"google_service_account_iam_binding": &importer.SimpleImporter{
		Fields: []string{"service_account_id", "role"},
		Tmpl:   "{{.service_account_id}} {{.role}}",
	},
	"google_service_account_iam_member": &importer.SimpleImporter{
		Fields: []string{"service_account_id", "role", "member"},
		Tmpl:   "{{.service_account_id}} {{.role}} {{.member}}",
	},
	"google_service_account_iam_policy": &importer.SimpleImporter{
		Fields: []string{"service_account_id"},
		Tmpl:   "{{.service_account_id}}",
	},
	"google_service_networking_connection": &importer.ServiceNetworkingConnection{},
	"google_service_usage_consumer_quota_override": &importer.SimpleImporter{
		Fields: []string{"project", "service", "metric", "limit", "name"},
		Tmpl:   "projects/{{.project}}/services/{{.service}}/consumerQuotaMetrics/{{.metric}}/limits/{{.limit}}/consumerOverrides/{{.name}}",
	},
	"google_sql_database": &importer.SimpleImporter{
		Fields: []string{"project", "instance", "name"},
		Tmpl:   "projects/{{.project}}/instances/{{.instance}}/databases/{{.name}}",
	},
	"google_sql_database_instance": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "projects/{{.project}}/instances/{{.name}}",
	},
	"google_sql_user": &importer.SQLUser{},
	"google_storage_bucket": &importer.SimpleImporter{
		Fields: []string{"project", "name"},
		Tmpl:   "{{.project}}/{{.name}}",
	},
	"google_storage_bucket_iam_binding": &importer.SimpleImporter{
		Fields: []string{"bucket", "role"},
		Tmpl:   "{{.bucket}} {{.role}}",
	},
	"google_storage_bucket_iam_member": &importer.SimpleImporter{
		Fields: []string{"bucket", "role", "member"},
		Tmpl:   "{{.bucket}} {{.role}} {{.member}}",
	},
	"google_storage_bucket_iam_policy": &importer.SimpleImporter{
		Fields: []string{"bucket"},
		Tmpl:   "{{.bucket}}",
	},
	"gsuite_group": &importer.SimpleImporter{
		Fields: []string{"email"},
		Tmpl:   "{{.email}}",
	},
	"gsuite_group_member": &importer.SimpleImporter{
		Fields: []string{"group", "email"},
		Tmpl:   "{{.group}}:{{.email}}",
	},
	"helm_release": &importer.SimpleImporter{
		Fields: []string{"namespace", "name"},
		Tmpl:   "{{.namespace}}/{{.name}}",
		Defaults: map[string]interface{}{
			"namespace": "default",
		},
	},
	"kubernetes_config_map": kubernetesImporter,
	"kubernetes_namespace": &importer.SimpleImporter{
		Fields: []string{"metadata"},
		Tmpl:   "{{.metadata.name}}",
	},
	"kubernetes_pod":             kubernetesImporter,
	"kubernetes_role":            kubernetesImporter,
	"kubernetes_role_binding":    kubernetesImporter,
	"kubernetes_service":         kubernetesImporter,
	"kubernetes_service_account": kubernetesImporter,
	"kubernetes_manifest": kubernetesAlphaImporter,
	"random_id":      &importer.RandomID{},
	"random_integer": &importer.RandomInteger{},
}
var Unimportable = map[string]bool{
	"google_bigquery_dataset_access": true,
	"google_service_account_key":     true,
	"google_storage_bucket_object":   true,
	"local_file":                     true,
	"null_resource":                  true,
	"random_password":                true,
	"random_pet":                     true,
	"random_shuffle":                 true,
	"random_string":                  true,
	"tls_private_key":                true,
}
var RequiresInteractive = map[string]bool{
	"google_billing_budget":        true,
	"google_resource_manager_lien": true,
}
type Resource struct {
	Change         terraform.ResourceChange
	ProviderConfig importer.ConfigMap
	Importer       resourceImporter
}
type resourceImporter interface {
	ImportID(rc terraform.ResourceChange, pcv importer.ConfigMap, interactive bool) (string, error)
}
func (ir Resource) ImportID(interactive bool) (string, error) {
	return ir.Importer.ImportID(ir.Change, ir.ProviderConfig, interactive)
}
func Importable(rc terraform.ResourceChange, pcv importer.ConfigMap, interactive bool) (*Resource, bool) {
	ri, ok := Importers[rc.Kind]
	if !ok {
		return nil, false
	}
	if _, reqInteractive := RequiresInteractive[rc.Kind]; reqInteractive && !interactive {
		return nil, false
	}
	return &Resource{
		Change:         rc,
		ProviderConfig: pcv,
		Importer:       ri,
	}, true
}
func Import(rn runner.Runner, ir *Resource, inputDir string, terraformPath string, interactive bool) (output string, err error) {
	importID, err := ir.ImportID(interactive)
	if err != nil {
		return "", err
	}
	cmd := exec.Command(terraformPath, "import", ir.Change.Address, importID)
	cmd.Dir = inputDir
	outputBytes, err := rn.CmdCombinedOutput(cmd)
	return string(outputBytes), err
}
var (
	reNotImportable = regexp.MustCompile(`(?i)Error:.*resource (.*) doesn't support import`)
	reDoesNotExist  = regexp.MustCompile(`(?i)Error:.*Cannot import non-existent.*object`)
)
// NotImportable parses the output of a `terraform import` command to determine if it indicated that a resource is not importable.
func NotImportable(output string) bool {
	return reNotImportable.FindStringIndex(output) != nil
}
// DoesNotExist parses the output of a `terraform import` command to determine if it indicated that a resource does not exist.
func DoesNotExist(output string) bool {
	return reDoesNotExist.FindStringIndex(output) != nil
}
// importError is an error indicating a resource failed to be imported.
// This doesn't indicate an error in running the steps around trying an import,
type importError struct {
	errMsgs []string
}
func (e *importError) Error() string {
	return fmt.Sprintf("failed to find or import %v resources. Use --verbose flag to see detailed error messages.", len(e.errMsgs))
}
var summaryTmpl string = `
Summary:
Found {{.total}} importable resources
Successfully imported {{len .successes}}{{if gt (len .successes) 0}}:{{end}}
{{- range $resource := .successes}}
- {{$resource}}
{{- end}}
Skipped {{len .skipped}}{{if gt (len .skipped) 0}}:{{end}}
{{- range $resource, $reason := .skipped}}
- {{$resource}} ({{$reason}})
{{- end}}
Failed to import {{len .failures}}{{if gt (len .failures) 0}}:{{end}}
{{- range $resource := .failures}}
- {{$resource}}
{{- end}}
`
type RunArgs struct {
	InputDir      string
	TerraformPath string
	DryRun        bool
	Interactive   bool
	Verbose       bool
	SpecificResourceTypes map[string]bool
}