├── aws ├── icons │ ├── db.png │ ├── s3.png │ ├── ec2.png │ └── internet.png └── aws.go ├── vpc-subnet-ec2.png ├── examples ├── tf_0_12 │ ├── two-tier │ │ ├── outputs.tf │ │ ├── terraform.template.tfvars │ │ ├── variables.tf │ │ └── main.tf │ ├── rds │ │ ├── terraform.template.tfvars │ │ ├── sg-variables.tf │ │ ├── outputs.tf │ │ ├── subnets.tf │ │ ├── sg.tf │ │ ├── subnet-variables.tf │ │ ├── variables.tf │ │ └── main.tf │ ├── ankyit │ │ ├── terraform.tfvars │ │ └── main.tf │ └── vpc-subnet-ec2 │ │ └── main.tf └── tf_0_11 │ ├── aws-ec2-instance │ ├── outputs.tf │ ├── variables.tf │ └── main.tf │ └── vpc-subnet-ec2 │ └── main.tf ├── .gitignore ├── go.mod ├── .talismanrc ├── LICENSE.md ├── README.md ├── main.go ├── utils └── utils.go └── go.sum /aws/icons/db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steeve85/tfviz/HEAD/aws/icons/db.png -------------------------------------------------------------------------------- /aws/icons/s3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steeve85/tfviz/HEAD/aws/icons/s3.png -------------------------------------------------------------------------------- /aws/icons/ec2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steeve85/tfviz/HEAD/aws/icons/ec2.png -------------------------------------------------------------------------------- /vpc-subnet-ec2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steeve85/tfviz/HEAD/vpc-subnet-ec2.png -------------------------------------------------------------------------------- /aws/icons/internet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steeve85/tfviz/HEAD/aws/icons/internet.png -------------------------------------------------------------------------------- /examples/tf_0_12/two-tier/outputs.tf: -------------------------------------------------------------------------------- 1 | output "address" { 2 | value = aws_elb.web.dns_name 3 | } 4 | -------------------------------------------------------------------------------- /examples/tf_0_11/aws-ec2-instance/outputs.tf: -------------------------------------------------------------------------------- 1 | output "public_dns" { 2 | value = "${aws_instance.ubuntu.public_dns}" 3 | } 4 | -------------------------------------------------------------------------------- /examples/tf_0_12/rds/terraform.template.tfvars: -------------------------------------------------------------------------------- 1 | password = "neverstorepasswordsinplaintext" 2 | vpc_id = "vpc-12345678" 3 | -------------------------------------------------------------------------------- /examples/tf_0_12/two-tier/terraform.template.tfvars: -------------------------------------------------------------------------------- 1 | key_name = "terraform-provider-aws-example" 2 | public_key_path = "~/.ssh/terraform-provider-aws-example.pub" 3 | -------------------------------------------------------------------------------- /examples/tf_0_12/rds/sg-variables.tf: -------------------------------------------------------------------------------- 1 | variable "cidr_blocks" { 2 | default = "0.0.0.0/0" 3 | description = "CIDR for sg" 4 | } 5 | 6 | variable "sg_name" { 7 | default = "rds_sg" 8 | description = "Tag Name for sg" 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out -------------------------------------------------------------------------------- /examples/tf_0_12/rds/outputs.tf: -------------------------------------------------------------------------------- 1 | output "subnet_group" { 2 | value = aws_db_subnet_group.default.name 3 | } 4 | 5 | output "db_instance_id" { 6 | value = aws_db_instance.default.id 7 | } 8 | 9 | output "db_instance_address" { 10 | value = aws_db_instance.default.address 11 | } 12 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/steeve85/tfviz 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/awalterschulze/gographviz v2.0.1+incompatible 7 | github.com/hashicorp/hcl/v2 v2.6.0 8 | github.com/hashicorp/terraform v0.12.29 9 | github.com/zclconf/go-cty v1.5.1 10 | golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /examples/tf_0_12/rds/subnets.tf: -------------------------------------------------------------------------------- 1 | resource "aws_subnet" "subnet_1" { 2 | vpc_id = var.vpc_id 3 | cidr_block = var.subnet_1_cidr 4 | availability_zone = var.az_1 5 | 6 | tags = { 7 | Name = "main_subnet1" 8 | } 9 | } 10 | 11 | resource "aws_subnet" "subnet_2" { 12 | vpc_id = var.vpc_id 13 | cidr_block = var.subnet_2_cidr 14 | availability_zone = var.az_2 15 | 16 | tags = { 17 | Name = "main_subnet2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/tf_0_12/rds/sg.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "default" { 2 | name = "main_rds_sg" 3 | description = "Allow all inbound traffic" 4 | vpc_id = var.vpc_id 5 | 6 | ingress { 7 | from_port = 0 8 | to_port = 65535 9 | protocol = "TCP" 10 | cidr_blocks = [var.cidr_blocks] 11 | } 12 | 13 | egress { 14 | from_port = 0 15 | to_port = 0 16 | protocol = "-1" 17 | cidr_blocks = ["0.0.0.0/0"] 18 | } 19 | 20 | tags = { 21 | Name = var.sg_name 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/tf_0_11/aws-ec2-instance/variables.tf: -------------------------------------------------------------------------------- 1 | variable "aws_region" { 2 | description = "AWS region" 3 | default = "us-east-1" 4 | } 5 | 6 | variable "ami_id" { 7 | description = "ID of the AMI to provision. Default is Ubuntu 14.04 Base Image" 8 | default = "ami-2e1ef954" 9 | } 10 | 11 | variable "instance_type" { 12 | description = "type of EC2 instance to provision." 13 | default = "t2.micro" 14 | } 15 | 16 | variable "name" { 17 | description = "name to pass to Name tag" 18 | default = "Provisioned by Terraform" 19 | } 20 | -------------------------------------------------------------------------------- /examples/tf_0_11/aws-ec2-instance/main.tf: -------------------------------------------------------------------------------- 1 | // Ref: https://github.com/rberlind/aws-ec2-instance 2 | terraform { 3 | required_version = ">= 0.11.1" 4 | } 5 | 6 | provider "aws" { 7 | region = "${var.aws_region}" 8 | } 9 | 10 | resource "aws_instance" "ubuntu" { 11 | ami = "${var.ami_id}" 12 | instance_type = "${var.instance_type}" 13 | availability_zone = "${var.aws_region}b" 14 | associate_public_ip_address = "true" 15 | tags = { 16 | Name = "${var.name}" 17 | owner = "roger@hashicorp.com" 18 | ttl = "48" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.talismanrc: -------------------------------------------------------------------------------- 1 | fileignoreconfig: 2 | - filename: go.sum 3 | ignore_detectors: [filecontent] 4 | - filename: tests/tf_0.12/ankyit/main.tf 5 | checksum: 59a5ff1393025923718332e5a6425e045492d2baf4dd2e312bfbd7186253f350 6 | ignore_detectors: [] 7 | - filename: tests/tf_0_12/rds/terraform.template.tfvars 8 | checksum: 21372d66f6b70df6123ec68cd73f7972881cacf1a3945d7c1fdb14b0ba764a5c 9 | ignore_detectors: [] 10 | - filename: tests/tf_0_12/rds/main.tf 11 | checksum: 7b08dce2278fced1282e8a000b7352611b58a888c4b19ab09bc778f78b2e2e6d 12 | ignore_detectors: [] 13 | scopeconfig: [] -------------------------------------------------------------------------------- /examples/tf_0_12/rds/subnet-variables.tf: -------------------------------------------------------------------------------- 1 | variable "subnet_1_cidr" { 2 | default = "10.0.1.0/24" 3 | description = "Your AZ" 4 | } 5 | 6 | variable "subnet_2_cidr" { 7 | default = "10.0.2.0/24" 8 | description = "Your AZ" 9 | } 10 | 11 | variable "az_1" { 12 | default = "us-east-1b" 13 | description = "Your Az1, use AWS CLI to find your account specific" 14 | } 15 | 16 | variable "az_2" { 17 | default = "us-east-1c" 18 | description = "Your Az2, use AWS CLI to find your account specific" 19 | } 20 | 21 | variable "vpc_id" { 22 | description = "Your VPC ID" 23 | } 24 | -------------------------------------------------------------------------------- /examples/tf_0_12/ankyit/terraform.tfvars: -------------------------------------------------------------------------------- 1 | //Replace with preferred AWS Region 2 | aws_region = "ap-southeast-1" 3 | 4 | // Replace with preferred CIDR/ Subnet and IP 5 | aws_vpc_cidr_block = "172.16.0.0/16" 6 | aws_subnet_cidr_block = "172.16.10.0/24" 7 | aws_private_ip_fe = "172.16.10.100" 8 | 9 | // Replace with preferred name 10 | aws_Name = "aws-ec2-test-ground-application" 11 | aws_Application = "aws-ec2-test-ground" 12 | 13 | //Replace with AMI id from your region 14 | aws_ami = "ami-07539a31f72d244e7" 15 | 16 | //Replace with instance type 17 | aws_instance_type = "t2.micro" -------------------------------------------------------------------------------- /examples/tf_0_12/two-tier/variables.tf: -------------------------------------------------------------------------------- 1 | variable "public_key_path" { 2 | description = < 1 { 33 | fmt.Println("[WARNING] Diagnostics:") 34 | for _, d := range diags { 35 | fmt.Println("\t", d.Error()) 36 | } 37 | } 38 | } 39 | } 40 | 41 | // ExportGraphToFile exports Graph to file 42 | func ExportGraphToFile(outputPath string, outputFormat string, graph *gographviz.Escape) error { 43 | fmt.Println("Exporting Graph to", outputPath) 44 | if outputFormat == "dot" { 45 | err := ioutil.WriteFile(outputPath, []byte(graph.String()), 0644) 46 | if err != nil { 47 | return err 48 | } 49 | } else { 50 | tFlag := fmt.Sprintf("-T%s", outputFormat) 51 | cmd := exec.Command("dot", tFlag, "-o", outputPath) 52 | cmd.Stdin = strings.NewReader(graph.String()) 53 | if Verbose == true { 54 | fmt.Printf("[VERBOSE] Running command: %s\n", cmd.String()) 55 | } 56 | err := cmd.Run() 57 | if err != nil { 58 | return err 59 | } 60 | } 61 | return nil 62 | } 63 | 64 | // ParseTFfile loads a file path and returns a TF module 65 | func ParseTFfile(configpath string) (*tfconfigs.Module, error) { 66 | f, err := os.Stat(configpath); 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | tfparser := tfconfigs.NewParser(nil) 72 | 73 | switch { 74 | case f.IsDir(): 75 | fmt.Println("Parsing", configpath, "Terraform module...") 76 | if tfparser.IsConfigDir(configpath) == false { 77 | err := fmt.Errorf("[ERROR] Directory %s does not contain valid Terraform configuration files", configpath) 78 | return nil, err 79 | } 80 | module, diags := tfparser.LoadConfigDir(configpath) 81 | PrintDiags(diags) 82 | return module, nil 83 | default: 84 | fmt.Println("Parsing", configpath, "Terraform file...") 85 | file, diags := tfparser.LoadConfigFile(configpath) 86 | // Return error if the TF file doesn't contain resources 87 | if len(file.ManagedResources) == 0 { 88 | err := fmt.Errorf("[ERROR] File %s does not contain valid Terraform configuration", configpath) 89 | return nil, err 90 | } 91 | module, moreDiags := tfconfigs.NewModule([]*tfconfigs.File{file}, nil) 92 | diags = append(diags, moreDiags...) 93 | PrintDiags(diags) 94 | return module, nil 95 | } 96 | } 97 | 98 | // InitiateGraph initializes the graph 99 | func InitiateGraph() (*gographviz.Escape, error) { 100 | // Graph initialization 101 | g := gographviz.NewEscape() 102 | g.SetName("G") 103 | g.SetDir(true) 104 | 105 | if Verbose == true { 106 | fmt.Println("[VERBOSE] AddNode: Internet to G") 107 | } 108 | // Adding node for Internet representation 109 | err := g.AddNode("G", "Internet", map[string]string{ 110 | "shape": "none", 111 | "label": "Internet", 112 | "labelloc": "b", 113 | "image": "./aws/icons/internet.png", 114 | }) 115 | return g, err 116 | } 117 | 118 | // RemoveDuplicateValues removes duplicate strings in []string slices 119 | // Ref: https://www.geeksforgeeks.org/how-to-remove-duplicate-values-from-slice-in-golang/ 120 | func RemoveDuplicateValues(strSlice []string) []string { 121 | keys := make(map[string]bool) 122 | list := []string{} 123 | 124 | // If the key(values of the slice) is not equal 125 | // to the already present value in new slice (list) 126 | // then we append it. else we jump on another element. 127 | for _, entry := range strSlice { 128 | if _, value := keys[entry]; !value { 129 | keys[entry] = true 130 | list = append(list, entry) 131 | } 132 | } 133 | return list 134 | } 135 | 136 | // Find takes a slice and looks for an element in it. If found it will 137 | // return it's key, otherwise it will return -1 and a bool of false. 138 | // https://golangcode.com/check-if-element-exists-in-slice/ 139 | func Find(slice []string, val string) (int, bool) { 140 | for i, item := range slice { 141 | if item == val { 142 | return i, true 143 | } 144 | } 145 | return -1, false 146 | } 147 | 148 | // ChunkString splits a string into chunks of X characters 149 | // https://stackoverflow.com/a/48479355 150 | func ChunkString(s string, chunkSize int) []string { 151 | var chunks []string 152 | runes := []rune(s) 153 | 154 | if len(runes) == 0 { 155 | return []string{s} 156 | } 157 | 158 | for i := 0; i < len(runes); i += chunkSize { 159 | nn := i + chunkSize 160 | if nn > len(runes) { 161 | nn = len(runes) 162 | } 163 | chunks = append(chunks, string(runes[i:nn])) 164 | } 165 | return chunks 166 | } 167 | -------------------------------------------------------------------------------- /aws/aws.go: -------------------------------------------------------------------------------- 1 | package aws 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net" 7 | "os" 8 | "path" 9 | "strings" 10 | 11 | tfconfigs "github.com/hashicorp/terraform/configs" 12 | hcl2 "github.com/hashicorp/hcl/v2" 13 | "github.com/hashicorp/hcl/v2/gohcl" 14 | "github.com/zclconf/go-cty/cty" 15 | "github.com/awalterschulze/gographviz" 16 | 17 | "github.com/steeve85/tfviz/utils" 18 | ) 19 | 20 | 21 | // IgnoreIngress can be used to not create edges for Ingress rules 22 | var IgnoreIngress bool 23 | 24 | // IgnoreEgress can be used to not create edges for Egress rules 25 | var IgnoreEgress bool 26 | 27 | // Verbose enables verbose mode if set to true 28 | var Verbose bool 29 | 30 | // Defining values for ingress / egress rules 31 | const ingressRule = 1 32 | const egressRule = 2 33 | 34 | // Data is a structure that contain maps of TF parsed resources 35 | type Data struct { 36 | defaultVpc bool 37 | defaultSubnet bool 38 | defaultSecurityGroup bool 39 | Vpc map[string]Vpc 40 | Subnet map[string]Subnet 41 | Instance map[string]Instance 42 | DBInstance map[string]DBInstance 43 | DBSubnetGroup map[string]DBSubnetGroup 44 | SecurityGroup map[string]SecurityGroup 45 | S3 map[string]S3 46 | // list of security groups not defined in the TF module 47 | undefinedSecurityGroups []string 48 | // map of resources linked to a security group 49 | SecurityGroupNodeLinks map[string][]string 50 | // list of unsupported resources 51 | unsupportedResources []string 52 | } 53 | 54 | // Vpc is a structure for AWS VPC resources 55 | type Vpc struct { 56 | // The CIDR block for the VPC 57 | CidrBlock string `hcl:"cidr_block"` 58 | // Other arguments 59 | Remain hcl2.Body `hcl:",remain"` 60 | } 61 | 62 | // Subnet is a structure for AWS Subnet resources 63 | type Subnet struct { 64 | // The CIDR block for the subnet 65 | CidrBlock string `hcl:"cidr_block"` 66 | // The VPC ID 67 | VpcID string `hcl:"vpc_id"` 68 | // Other arguments 69 | Remain hcl2.Body `hcl:",remain"` 70 | } 71 | 72 | // Instance is a structure for AWS EC2 instance resources 73 | type Instance struct { 74 | // The type of instance to start 75 | InstanceType string `hcl:"instance_type"` 76 | // The AMI to use for the instance 77 | AMI string `hcl:"ami"` 78 | // A list of security group names (EC2-Classic) or IDs (default VPC) to associate with 79 | SecurityGroups *[]string `hcl:"security_groups"` 80 | // A list of security group IDs to associate with (VPC only) 81 | VpcSecurityGroupIDs *[]string `hcl:"vpc_security_group_ids"` 82 | // The VPC Subnet ID to launch in 83 | SubnetID *string `hcl:"subnet_id"` 84 | // Other arguments 85 | Remain hcl2.Body `hcl:",remain"` 86 | } 87 | 88 | // DBInstance is a structure for AWS RDS instance resources 89 | type DBInstance struct { 90 | // The allocated storage in Gb 91 | AllocatedStorage *int `hcl:"allocated_storage"` 92 | // Name of DB subnet group 93 | DBSubnetGroupName *string `hcl:"db_subnet_group_name"` 94 | // The database engine to use 95 | Engine *string `hcl:"engine"` 96 | // The instance type of the RDS instance 97 | InstanceClass *string `hcl:"instance_class"` 98 | // Password for the master DB user 99 | Password *string `hcl:"password"` 100 | // Bool to control if instance is publicly accessible 101 | PubliclyAccessible *bool `hcl:"publicly_accessible"` 102 | // Username for the master DB user 103 | Username *string `hcl:"username"` 104 | // List of VPC security groups to associate 105 | VpcSecurityGroupIDs *[]string `hcl:"vpc_security_group_ids"` 106 | // Other arguments 107 | Remain hcl2.Body `hcl:",remain"` 108 | } 109 | 110 | // DBSubnetGroup is a structure for RDS DB subnet group resources 111 | type DBSubnetGroup struct { 112 | // A list of VPC subnet IDs 113 | SubnetIDs []string `hcl:"subnet_ids"` 114 | // Other arguments 115 | Remain hcl2.Body `hcl:",remain"` 116 | } 117 | 118 | // SecurityGroup is a structure for AWS Security Group resources 119 | type SecurityGroup struct { 120 | // The VPC ID 121 | VpcID *string `hcl:"vpc_id"` 122 | // A list of ingress rules 123 | Ingress []SGRule `hcl:"ingress,block"` // FIXME make it optional? 124 | // A list of egress rules 125 | Egress []SGRule `hcl:"egress,block"` // FIXME make it optional? 126 | // Other arguments 127 | Remain hcl2.Body `hcl:",remain"` 128 | } 129 | 130 | // SGRule is a structure for AWS Security Group ingress/egress blocks 131 | type SGRule struct { 132 | // The start port (or ICMP type number if protocol is "icmp" or "icmpv6") 133 | FromPort int `hcl:"from_port"` 134 | // The end range port (or ICMP code if protocol is "icmp") 135 | ToPort int `hcl:"to_port"` 136 | // If true, the security group itself will be added as a source to this ingress/egress rule 137 | Self *bool `hcl:"self"` 138 | // The protocol. icmp, icmpv6, tcp, udp, "-1" (all) 139 | Protocol string `hcl:"protocol"` 140 | // List of CIDR blocks 141 | CidrBlocks *[]string `hcl:"cidr_blocks"` 142 | // List of IPv6 CIDR blocks 143 | IPv6CidrBlocks *[]string `hcl:"ipv6_cidr_blocks"` 144 | // List of security group Group Names if using EC2-Classic, or Group IDs if using a VPC 145 | SecurityGroups *[]string `hcl:"security_groups"` 146 | // Other arguments 147 | Remain hcl2.Body `hcl:",remain"` 148 | } 149 | 150 | // S3 is a structure for AWS S3 bucket resources 151 | type S3 struct { 152 | // The name of the bucket 153 | Bucket *string `hcl:"bucket"` 154 | // Other arguments 155 | Remain hcl2.Body `hcl:",remain"` 156 | } 157 | 158 | func createDefaultVpc(graph *gographviz.Escape) (error) { 159 | // Create default VPC cluster 160 | if Verbose == true { 161 | fmt.Println("[VERBOSE] AddSubGraph: cluster_aws_vpc_default // Create Default VPC") 162 | } 163 | err := graph.AddSubGraph("G", "cluster_aws_vpc_default", map[string]string{ 164 | "label": "VPC: default", 165 | }) 166 | if err != nil { 167 | return err 168 | } 169 | // Adding invisible node to VPC for links 170 | if Verbose == true { 171 | fmt.Println("[VERBOSE] AddNode: aws_vpc_default to cluster_aws_vpc_default") 172 | } 173 | err = graph.AddNode("cluster_aws_vpc_default", "aws_vpc_default", map[string]string{ 174 | "shape": "point", 175 | "style": "invis", 176 | }) 177 | if err != nil { 178 | return err 179 | } 180 | return nil 181 | } 182 | 183 | func createDefaultSubnet(graph *gographviz.Escape, clusterName string) (error) { 184 | // Create default Subnet cluster 185 | if Verbose == true { 186 | fmt.Printf("[VERBOSE] AddNode: cluster_aws_subnet_default to %s // Create Default Subnet\n", clusterName) 187 | } 188 | err := graph.AddSubGraph(clusterName, "cluster_aws_subnet_default", map[string]string{ 189 | "label": "Subnet: default", 190 | }) 191 | if err != nil { 192 | return err 193 | } 194 | 195 | // Adding invisible node to VPC for links 196 | if Verbose == true { 197 | fmt.Println("[VERBOSE] AddNode: aws_subnet_default to cluster_aws_subnet_default") 198 | } 199 | err = graph.AddNode("cluster_aws_subnet_default", "aws_subnet_default", map[string]string{ 200 | "shape": "point", 201 | "style": "invis", 202 | }) 203 | if err != nil { 204 | return err 205 | } 206 | return nil 207 | } 208 | 209 | func createDefaultSecurityGroup(graph *gographviz.Escape) (error) { 210 | // Create default security group 211 | if Verbose == true { 212 | fmt.Println("[VERBOSE] AddNode: sg-default to G // Create default Security Group") 213 | } 214 | err := graph.AddNode("G", "sg-default", map[string]string{ 215 | "style": "dotted", 216 | "label": "sg-default", 217 | }) 218 | if err != nil { 219 | return err 220 | } 221 | return nil 222 | } 223 | 224 | func createVpc(graph *gographviz.Escape, vpcName string) (error) { 225 | // Create VPC cluster 226 | if Verbose == true { 227 | fmt.Printf("[VERBOSE] AddSubGraph: cluster_aws_vpc_%s to G // Create VPC\n", vpcName) 228 | } 229 | err := graph.AddSubGraph("G", "cluster_aws_vpc_"+vpcName, map[string]string{ 230 | "label": "VPC: "+vpcName, 231 | "style": "rounded", 232 | "bgcolor": "#EDF1F2", 233 | "labeljust": "l", 234 | }) 235 | if err != nil { 236 | return err 237 | } 238 | 239 | // Adding invisible node to VPC for links 240 | if Verbose == true { 241 | fmt.Printf("[VERBOSE] AddNode: aws_vpc_%s to cluster_aws_vpc_%s\n", vpcName, vpcName) 242 | } 243 | err = graph.AddNode("cluster_aws_vpc_"+vpcName, "aws_vpc_"+vpcName, map[string]string{ 244 | "shape": "point", 245 | "style": "invis", 246 | }) 247 | if err != nil { 248 | return err 249 | } 250 | return nil 251 | } 252 | 253 | func createSubnet(graph *gographviz.Escape, subnetName string, awsSubnet Subnet) (error) { 254 | // Create subnet cluster 255 | vpcID := strings.Replace(awsSubnet.VpcID, ".", "_", -1) 256 | if Verbose == true { 257 | fmt.Printf("[VERBOSE] AddSubGraph: cluster_aws_subnet_%s to cluster_%s // Create Subnet\n", subnetName, vpcID) 258 | } 259 | err := graph.AddSubGraph("cluster_"+vpcID, "cluster_aws_subnet_"+subnetName, map[string]string{ 260 | "label": "Subnet: "+subnetName, 261 | "style": "rounded", 262 | "bgcolor": "white", 263 | "labeljust": "l", 264 | }) 265 | if err != nil { 266 | return err 267 | } 268 | 269 | // Adding invisible node to Subnet for links 270 | if Verbose == true { 271 | fmt.Printf("[VERBOSE] AddNode: aws_subnet_%s to cluster_aws_subnet_%s\n", subnetName, subnetName) 272 | } 273 | err = graph.AddNode("cluster_aws_subnet_"+subnetName, "aws_subnet_"+subnetName, map[string]string{ 274 | "shape": "point", 275 | "style": "invis", 276 | }) 277 | if err != nil { 278 | return err 279 | } 280 | return nil 281 | } 282 | 283 | func createS3(graph *gographviz.Escape, s3Name string, s3 S3) (error) { 284 | // Create S3 bucket node 285 | if Verbose == true { 286 | fmt.Printf("[VERBOSE] AddNode: aws_s3_bucket_%s to G // Create S3 bucket\n", s3Name) 287 | } 288 | 289 | // Splitting label if more than 8 chars 290 | tmpLabel := s3Name 291 | if s3.Bucket != nil && *s3.Bucket != "" { 292 | tmpLabel = *s3.Bucket 293 | } 294 | labelName := strings.Join(utils.ChunkString(tmpLabel, 8), "\n") 295 | 296 | err := graph.AddNode("G", "aws_s3_bucket_"+s3Name, map[string]string{ 297 | "label": labelName, 298 | "image": "./aws/icons/s3.png", 299 | "width": "1", 300 | "height": "1", 301 | "fixedsize": "true", 302 | "shape": "none", 303 | }) 304 | if err != nil { 305 | return err 306 | } 307 | return nil 308 | } 309 | 310 | func createInstance(graph *gographviz.Escape, instanceName string, awsInstance Instance) (error) { 311 | // Create instance node 312 | var clusterID string 313 | if awsInstance.SubnetID == nil { 314 | clusterID = "aws_subnet_default" 315 | } else { 316 | clusterID = strings.Replace(*awsInstance.SubnetID, ".", "_", -1) 317 | } 318 | if Verbose == true { 319 | fmt.Printf("[VERBOSE] AddNode: aws_instance_%s to cluster_%s // Create Instance\n", instanceName, clusterID) 320 | } 321 | 322 | // Splitting label if more than 8 chars 323 | labelName := strings.Join(utils.ChunkString(instanceName, 8), "\n") 324 | 325 | err := graph.AddNode("cluster_"+clusterID, "aws_instance_"+instanceName, map[string]string{ 326 | "label": labelName, 327 | "image": "./aws/icons/ec2.png", 328 | "width": "1", 329 | "height": "1", 330 | "fixedsize": "true", 331 | "shape": "none", 332 | }) 333 | if err != nil { 334 | return err 335 | } 336 | return nil 337 | } 338 | 339 | 340 | func (a *Data) createDBInstance(graph *gographviz.Escape, instanceName string, awsInstance DBInstance) (error) { 341 | // Create DB instance node 342 | var clusterID string 343 | // if there is no DB Subnet Group, the DB instance is created in the default VPC 344 | // same if there is no VPC defined in the TF module 345 | if awsInstance.DBSubnetGroupName == nil || len(a.Vpc) == 0{ 346 | clusterID = "aws_vpc_default" 347 | } else { 348 | // TODO: support multiple subnets from the DB Subnet group 349 | // - how to show a DB in multiple subnets? 350 | // - can a node be part of 2 subgraph (in graphviz)? 351 | // For now, only the first one is used 352 | tmpDBname := strings.Split(*awsInstance.DBSubnetGroupName, ".")[1] 353 | tmpSubnetName := strings.Split(a.DBSubnetGroup[tmpDBname].SubnetIDs[0], ".")[1] 354 | clusterID = "aws_vpc_" + a.Subnet[tmpSubnetName].VpcID 355 | } 356 | if Verbose == true { 357 | fmt.Printf("[VERBOSE] AddNode: aws_db_instance_%s to cluster_%s // Create DB Instance\n", instanceName, clusterID) 358 | } 359 | 360 | // Splitting label if more than 8 chars 361 | labelName := strings.Join(utils.ChunkString(instanceName, 8), "\n") 362 | 363 | fontColor := "black" 364 | // DB is publicly available, so setting label color as red 365 | if awsInstance.PubliclyAccessible != nil && *awsInstance.PubliclyAccessible == true { 366 | fontColor = "red" 367 | } 368 | 369 | err := graph.AddNode("cluster_"+clusterID, "aws_db_instance_"+instanceName, map[string]string{ 370 | "label": labelName, 371 | "fontcolor": fontColor, 372 | "image": "./aws/icons/db.png", 373 | "width": "1", 374 | "height": "1", 375 | "fixedsize": "true", 376 | "shape": "none", 377 | }) 378 | if err != nil { 379 | return err 380 | } 381 | return nil 382 | } 383 | 384 | // InitiateVariablesAndResources parses TF file to create Variables / Obj references for interpolation 385 | func InitiateVariablesAndResources(tfModule *tfconfigs.Module) (*hcl2.EvalContext, error) { 386 | // Create map for EvalContext to replace variables names by their values inside HCL file using DecodeBody 387 | ctxVariables := make(map[string]cty.Value) 388 | ctxVpc := make(map[string]cty.Value) 389 | ctxAwsSubnet := make(map[string]cty.Value) 390 | ctxAwsInstance := make(map[string]cty.Value) 391 | ctxAwsSecurityGroup := make(map[string]cty.Value) 392 | ctxDBInstance := make(map[string]cty.Value) 393 | ctxDBSubnetGroup := make(map[string]cty.Value) 394 | 395 | // Prepare context with TF variables 396 | for _, v := range tfModule.Variables { 397 | // Handling the case there is no default value for the variable 398 | if v.Default.IsNull() { 399 | ctxVariables[v.Name] = cty.StringVal("var_" + v.Name) 400 | } else { 401 | ctxVariables[v.Name] = v.Default 402 | } 403 | } 404 | 405 | // Load variables from Variable Definitions (.tfvars) Files 406 | // Start with terraform.tfvars file: 407 | inputVariablesFile := path.Join(tfModule.SourceDir, "terraform.tfvars") 408 | _, err := os.Stat(inputVariablesFile) 409 | if err == nil { 410 | vars, diags := tfconfigs.NewParser(nil).LoadValuesFile(inputVariablesFile) 411 | utils.PrintDiags(diags) 412 | for varName, varValue := range vars { 413 | ctxVariables[varName] = varValue 414 | } 415 | } 416 | // Search for .auto.tfvars files 417 | files, err := ioutil.ReadDir(tfModule.SourceDir) 418 | if err != nil { 419 | return nil, err 420 | } 421 | for _, f := range files { 422 | if strings.HasSuffix(f.Name(), ".auto.tfvars") { 423 | inputVariablesFile := path.Join(tfModule.SourceDir, f.Name()) 424 | vars, diags := tfconfigs.NewParser(nil).LoadValuesFile(inputVariablesFile) 425 | utils.PrintDiags(diags) 426 | for varName, varValue := range vars { 427 | ctxVariables[varName] = varValue 428 | } 429 | } 430 | } 431 | 432 | // Prepare context with named values to resources 433 | for _, v := range tfModule.ManagedResources { 434 | if v.Type == "aws_vpc" { 435 | ctxVpc[v.Name] = cty.ObjectVal(map[string]cty.Value{ 436 | "id": cty.StringVal(v.Type + "." + v.Name), 437 | }) 438 | } else if v.Type == "aws_subnet" { 439 | ctxAwsSubnet[v.Name] = cty.ObjectVal(map[string]cty.Value{ 440 | "id": cty.StringVal(v.Type + "." + v.Name), 441 | }) 442 | } else if v.Type == "aws_instance" { 443 | ctxAwsInstance[v.Name] = cty.ObjectVal(map[string]cty.Value{ 444 | "id": cty.StringVal(v.Type + "." + v.Name), 445 | }) 446 | } else if v.Type == "aws_security_group" { 447 | ctxAwsSecurityGroup[v.Name] = cty.ObjectVal(map[string]cty.Value{ 448 | "id": cty.StringVal(v.Type + "." + v.Name), 449 | }) 450 | } else if v.Type == "aws_db_instance" { 451 | ctxDBInstance[v.Name] = cty.ObjectVal(map[string]cty.Value{ 452 | "id": cty.StringVal(v.Type + "." + v.Name), 453 | }) 454 | } else if v.Type == "aws_db_subnet_group" { 455 | ctxDBSubnetGroup[v.Name] = cty.ObjectVal(map[string]cty.Value{ 456 | "id": cty.StringVal(v.Type + "." + v.Name), 457 | }) 458 | } 459 | } 460 | 461 | ctx := &hcl2.EvalContext{ 462 | Variables: map[string]cty.Value{ 463 | "var": cty.ObjectVal(ctxVariables), 464 | "aws_vpc" : cty.ObjectVal(ctxVpc), 465 | "aws_subnet" : cty.ObjectVal(ctxAwsSubnet), 466 | "aws_instance" : cty.ObjectVal(ctxAwsInstance), 467 | "aws_security_group" : cty.ObjectVal(ctxAwsSecurityGroup), 468 | "aws_db_instance" : cty.ObjectVal(ctxDBInstance), 469 | "aws_db_subnet_group" : cty.ObjectVal(ctxDBSubnetGroup), 470 | }, 471 | } 472 | return ctx, nil 473 | } 474 | 475 | // CreateDefaultNodes creates default VPC/Subnet/Security Groups if they don't exist in the TF module 476 | func (a *Data) CreateDefaultNodes(tfModule *tfconfigs.Module, graph *gographviz.Escape) (error) { 477 | for _, v := range tfModule.ManagedResources { 478 | if v.Type == "aws_vpc" { 479 | a.defaultVpc = true 480 | } else if v.Type == "aws_subnet" { 481 | a.defaultSubnet = true 482 | } else if v.Type == "aws_security_group" { 483 | a.defaultSecurityGroup = true 484 | } 485 | } 486 | 487 | if !a.defaultVpc { 488 | // Create default VPC cluster 489 | err := createDefaultVpc(graph) 490 | if err != nil { 491 | return err 492 | } 493 | } 494 | 495 | if !a.defaultSubnet { 496 | // Create default subnet cluster 497 | var clusterName string 498 | if !a.defaultVpc { 499 | clusterName = "cluster_aws_vpc_default" 500 | } else { 501 | clusterName = "G" 502 | } 503 | err := createDefaultSubnet(graph, clusterName) 504 | if err != nil { 505 | return err 506 | } 507 | } 508 | 509 | if !a.defaultSecurityGroup { 510 | // Create default security group 511 | err := createDefaultSecurityGroup(graph) 512 | if err != nil { 513 | return err 514 | } 515 | a.undefinedSecurityGroups = append(a.undefinedSecurityGroups, "sg-default") 516 | } 517 | return nil 518 | } 519 | 520 | // ParseTfResources parse the TF file / module to identify resources that will be used later on to create the graph 521 | func (a *Data) ParseTfResources(tfModule *tfconfigs.Module, ctx *hcl2.EvalContext, graph *gographviz.Escape) (error) { 522 | for _, v := range tfModule.ManagedResources { 523 | switch v.Type { 524 | case "aws_vpc": 525 | if Verbose == true { 526 | fmt.Printf("[VERBOSE] Decoding %s.%s\n", v.Type, v.Name) 527 | } 528 | var Vpc Vpc 529 | diags := gohcl.DecodeBody(v.Config, ctx, &Vpc) 530 | utils.PrintDiags(diags) 531 | 532 | // Add Vpc to Data 533 | a.Vpc[v.Name] = Vpc 534 | 535 | case "aws_subnet": 536 | if Verbose == true { 537 | fmt.Printf("[VERBOSE] Decoding %s.%s\n", v.Type, v.Name) 538 | } 539 | var awsSubnet Subnet 540 | diags := gohcl.DecodeBody(v.Config, ctx, &awsSubnet) 541 | utils.PrintDiags(diags) 542 | 543 | // Add Subnet to Data 544 | a.Subnet[v.Name] = awsSubnet 545 | 546 | case "aws_instance": 547 | if Verbose == true { 548 | fmt.Printf("[VERBOSE] Decoding %s.%s\n", v.Type, v.Name) 549 | } 550 | var awsInstance Instance 551 | diags := gohcl.DecodeBody(v.Config, ctx, &awsInstance) 552 | utils.PrintDiags(diags) 553 | 554 | // Add Instance to Data 555 | a.Instance[v.Name] = awsInstance 556 | 557 | // Creating SG - Instance connections to facilitate the edges creation for the graph 558 | if awsInstance.SecurityGroups != nil { 559 | for _, sg := range *awsInstance.SecurityGroups { 560 | _, found := a.SecurityGroupNodeLinks[sg] 561 | if found { 562 | a.SecurityGroupNodeLinks[sg] = append(a.SecurityGroupNodeLinks[sg], v.Type+"."+v.Name) 563 | } else { 564 | a.SecurityGroupNodeLinks[sg] = []string{v.Type+"."+v.Name} 565 | } 566 | } 567 | } 568 | if awsInstance.VpcSecurityGroupIDs != nil { 569 | for _, sg := range *awsInstance.VpcSecurityGroupIDs { 570 | _, found := a.SecurityGroupNodeLinks[sg] 571 | if found { 572 | a.SecurityGroupNodeLinks[sg] = append(a.SecurityGroupNodeLinks[sg], v.Type+"."+v.Name) 573 | } else { 574 | a.SecurityGroupNodeLinks[sg] = []string{v.Type+"."+v.Name} 575 | } 576 | } 577 | } 578 | 579 | case "aws_security_group": 580 | if Verbose == true { 581 | fmt.Printf("[VERBOSE] Decoding %s.%s\n", v.Type, v.Name) 582 | } 583 | var awsSecurityGroup SecurityGroup 584 | diags := gohcl.DecodeBody(v.Config, ctx, &awsSecurityGroup) 585 | utils.PrintDiags(diags) 586 | 587 | // Add SecurityGroup to Data 588 | a.SecurityGroup["aws_security_group."+v.Name] = awsSecurityGroup 589 | 590 | case "aws_db_instance": 591 | if Verbose == true { 592 | fmt.Printf("[VERBOSE] Decoding %s.%s\n", v.Type, v.Name) 593 | } 594 | var awsDBInstance DBInstance 595 | diags := gohcl.DecodeBody(v.Config, ctx, &awsDBInstance) 596 | utils.PrintDiags(diags) 597 | 598 | // Add DBInstance to Data 599 | a.DBInstance[v.Name] = awsDBInstance 600 | 601 | if awsDBInstance.VpcSecurityGroupIDs != nil { 602 | fmt.Println("DEBUG (awsDBInstance.VpcSecurityGroupIDs):", *awsDBInstance.VpcSecurityGroupIDs) 603 | for _, sg := range *awsDBInstance.VpcSecurityGroupIDs { 604 | _, found := a.SecurityGroupNodeLinks[sg] 605 | if found { 606 | a.SecurityGroupNodeLinks[sg] = append(a.SecurityGroupNodeLinks[sg], v.Type+"."+v.Name) 607 | } else { 608 | a.SecurityGroupNodeLinks[sg] = []string{v.Type+"."+v.Name} 609 | } 610 | fmt.Println("DEBUG (a.SecurityGroupNodeLinks[sg]):", a.SecurityGroupNodeLinks[sg]) 611 | } 612 | } 613 | 614 | case "aws_db_subnet_group": 615 | if Verbose == true { 616 | fmt.Printf("[VERBOSE] Decoding %s.%s\n", v.Type, v.Name) 617 | } 618 | var awsDBSubnetGroup DBSubnetGroup 619 | diags := gohcl.DecodeBody(v.Config, ctx, &awsDBSubnetGroup) 620 | utils.PrintDiags(diags) 621 | 622 | // Add DBSubnetGroup to Data 623 | a.DBSubnetGroup[v.Name] = awsDBSubnetGroup 624 | 625 | case "aws_s3_bucket": 626 | if Verbose == true { 627 | fmt.Printf("[VERBOSE] Decoding %s.%s\n", v.Type, v.Name) 628 | } 629 | var awsS3 S3 630 | diags := gohcl.DecodeBody(v.Config, ctx, &awsS3) 631 | utils.PrintDiags(diags) 632 | 633 | // Add S3 to Data 634 | a.S3[v.Name] = awsS3 635 | 636 | default: 637 | if Verbose == true { 638 | fmt.Printf("[VERBOSE] Can't decode %s.%s (not yet supported)\n", v.Type, v.Name) 639 | } 640 | a.unsupportedResources = append(a.unsupportedResources, v.Type + "." + v.Name) 641 | } 642 | } 643 | 644 | return nil 645 | } 646 | 647 | // CreateGraphNodes creates the nodes for the graph 648 | func (a *Data) CreateGraphNodes(graph *gographviz.Escape) (error) { 649 | // Add VPC clusters to graph 650 | for vpcName := range a.Vpc { 651 | err := createVpc(graph, vpcName) 652 | if err != nil { 653 | return err 654 | } 655 | } 656 | 657 | // Add Subnet clusters to graph 658 | for subnetName, subnetObj := range a.Subnet { 659 | err := createSubnet(graph, subnetName, subnetObj) 660 | if err != nil { 661 | return err 662 | } 663 | } 664 | 665 | // Add Instance nodes to graph 666 | for instanceName, instanceObj := range a.Instance { 667 | err := createInstance(graph, instanceName, instanceObj) 668 | if err != nil { 669 | return err 670 | } 671 | } 672 | 673 | // Add DB Instance nodes to graph 674 | for instanceName, instanceObj := range a.DBInstance { 675 | err := a.createDBInstance(graph, instanceName, instanceObj) 676 | if err != nil { 677 | return err 678 | } 679 | } 680 | 681 | // Add S3 bucket nodes to graph 682 | for s3Name, s3Obj := range a.S3 { 683 | err := createS3(graph, s3Name, s3Obj) 684 | if err != nil { 685 | return err 686 | } 687 | } 688 | 689 | return nil 690 | } 691 | 692 | func createInternetSGRuleEdge(ruleType int, nodeName string, graph *gographviz.Escape) (error) { 693 | // Highlight Ingress from 0.0.0.0/0 and Egress to 0.0.0.0/0 in red 694 | 695 | // Based on the rule type Ingress or Egress define the source and destination items 696 | var src, dst string 697 | if ruleType == ingressRule { 698 | src, dst = "Internet", nodeName 699 | } else { 700 | src, dst = nodeName, "Internet" 701 | } 702 | 703 | if Verbose == true { 704 | fmt.Printf("[VERBOSE] AddEdge: %s -> %s\n", src, dst) 705 | } 706 | err := graph.AddEdge(src, dst, true, map[string]string{ 707 | "color": "red", 708 | }) 709 | if err != nil { 710 | return err 711 | } 712 | return nil 713 | } 714 | 715 | func (a *Data) parseSGRule(ruleType int, nodeName string, sgName string, graph *gographviz.Escape) (error) { 716 | // Based on the rule type Ingress or Egress define the source and destination items 717 | var src, dst string 718 | var sgRule []SGRule 719 | if ruleType == ingressRule { 720 | src, dst = sgName, nodeName 721 | sgRule = a.SecurityGroup[sgName].Ingress 722 | } else { 723 | src, dst = nodeName, sgName 724 | sgRule = a.SecurityGroup[sgName].Egress 725 | } 726 | 727 | if _, found1 := a.SecurityGroup[sgName]; !found1 { 728 | _, found2 := utils.Find(a.undefinedSecurityGroups, sgName) 729 | if !found2 { 730 | // If the SG is not defined in TF, we need to create the Node before the Edges 731 | if Verbose == true { 732 | fmt.Printf("[VERBOSE] AddNode: %s to G\n", sgName) 733 | } 734 | err := graph.AddNode("G", sgName, map[string]string{ 735 | "style": "dotted", 736 | "label": sgName, 737 | }) 738 | if err != nil { 739 | return err 740 | } 741 | a.undefinedSecurityGroups = append(a.undefinedSecurityGroups, sgName) 742 | } 743 | 744 | // The SG exists, we just need to link it with the appropriate nodes 745 | if Verbose == true { 746 | fmt.Printf("[VERBOSE] AddEdge: %s -> %s\n", src, dst) 747 | } 748 | err := graph.AddEdge(src, dst, true, nil) 749 | if err != nil { 750 | return err 751 | } 752 | } 753 | for _, rule := range sgRule { 754 | if rule.CidrBlocks != nil { 755 | for _, cidr := range *rule.CidrBlocks { 756 | // Special ingress/egress rule for 0.0.0.0/0 757 | if cidr == "0.0.0.0/0" { 758 | err := createInternetSGRuleEdge(ruleType, nodeName, graph) 759 | if err != nil { 760 | return err 761 | } 762 | } else { 763 | ipAddrSG, _, err := net.ParseCIDR(cidr) 764 | if err != nil { 765 | // Unrecognized SG name 766 | utils.PrintError(err) 767 | } else { 768 | // The source/destination is a valid CIDR 769 | edgeCreated := false 770 | for k, v := range(a.Subnet) { 771 | // Checking for Security Group source/destination IP / Subnet matching 772 | _, ipNetSubnet, err := net.ParseCIDR(v.CidrBlock) 773 | if err != nil { 774 | return err 775 | } 776 | if ipNetSubnet.Contains(ipAddrSG) { 777 | // the source/destination IP is part of this subnet CIDR 778 | if ruleType == ingressRule { 779 | src, dst = "aws_subnet_"+k, nodeName 780 | } else { 781 | src, dst = nodeName, "aws_subnet_"+k 782 | } 783 | if Verbose == true { 784 | fmt.Printf("[VERBOSE] AddEdge: %s -> %s\n", src, dst) 785 | } 786 | err = graph.AddEdge(src, dst, true, nil) 787 | if err != nil { 788 | return err 789 | } 790 | edgeCreated = true 791 | } 792 | } 793 | 794 | if !edgeCreated { 795 | // Security Group source/destination IP did not matched with Subnet CIDRs 796 | // Now checking with VPC CIDRs 797 | for k, v := range a.Vpc { 798 | _, ipNetVpc, err := net.ParseCIDR(v.CidrBlock) 799 | if err != nil { 800 | return err 801 | } 802 | if ipNetVpc.Contains(ipAddrSG) { 803 | // the source/destination IP is part of this VPC CIDR 804 | if ruleType == ingressRule { 805 | src, dst = "aws_vpc_"+k, nodeName 806 | } else { 807 | src, dst = nodeName, "aws_vpc_"+k 808 | } 809 | if Verbose == true { 810 | fmt.Printf("[VERBOSE] AddEdge: %s -> %s\n", src, dst) 811 | } 812 | err = graph.AddEdge(src, dst, true, nil) 813 | if err != nil { 814 | return err 815 | } 816 | edgeCreated = true 817 | } 818 | } 819 | } 820 | 821 | if !edgeCreated { 822 | // Security Group source/destination IP did not matched with Subnet and VPC CIDRs 823 | // Creating a node for the source/destination as it is likely to be an undefined IP/CIDR 824 | if Verbose == true { 825 | fmt.Printf("[VERBOSE] AddNode: %s to G\n", cidr) 826 | } 827 | err := graph.AddNode("G", cidr, nil) 828 | if err != nil { 829 | return err 830 | } 831 | if ruleType == ingressRule { 832 | src, dst = cidr, nodeName 833 | } else { 834 | src, dst = nodeName, cidr 835 | } 836 | if Verbose == true { 837 | fmt.Printf("[VERBOSE] AddEdge: %s -> %s\n", src, dst) 838 | } 839 | err = graph.AddEdge(src, dst, true, nil) 840 | if err != nil { 841 | return err 842 | } 843 | } 844 | } 845 | } 846 | } 847 | } 848 | 849 | // Create edges for all instances linked to SGRule.Self 850 | if rule.Self != nil && *rule.Self != false { 851 | for _, v1 := range a.SecurityGroupNodeLinks[sgName] { 852 | v2 := strings.Replace(v1, ".", "_", -1) 853 | if v2 != nodeName { 854 | if ruleType == ingressRule { 855 | src, dst = v2, nodeName 856 | } else { 857 | src, dst = nodeName, v2 858 | } 859 | if Verbose == true { 860 | fmt.Printf("[VERBOSE] AddEdge: %s -> %s\n", src, dst) 861 | } 862 | err := graph.AddEdge(src, dst, true, nil) 863 | if err != nil { 864 | return err 865 | } 866 | } 867 | } 868 | } 869 | 870 | // Create edges for all instances linked to SGRule.SecurityGroups 871 | if rule.SecurityGroups != nil { 872 | for _, v1 := range *rule.SecurityGroups { 873 | for _, v2 := range a.SecurityGroupNodeLinks[v1] { 874 | v3 := strings.Replace(v2, ".", "_", -1) 875 | if v3 != nodeName { 876 | if ruleType == ingressRule { 877 | src, dst = v3, nodeName 878 | } else { 879 | src, dst = nodeName, v3 880 | } 881 | if Verbose == true { 882 | fmt.Printf("[VERBOSE] AddEdge: %s -> %s\n", src, dst) 883 | } 884 | err := graph.AddEdge(src, dst, true, nil) 885 | if err != nil { 886 | return err 887 | } 888 | } 889 | } 890 | } 891 | 892 | } 893 | } 894 | 895 | return nil 896 | } 897 | 898 | // CreateGraphEdges creates edges for the graph 899 | func (a *Data) CreateGraphEdges(graph *gographviz.Escape) (error) { 900 | // Link Instances with their Security Groups 901 | for instanceName, instanceObj := range a.Instance { 902 | 903 | // Get the Security Groups of the AWS instance 904 | var SGs []string 905 | if instanceObj.SecurityGroups != nil { 906 | SGs = append(SGs, *instanceObj.SecurityGroups...) 907 | } 908 | if instanceObj.VpcSecurityGroupIDs != nil { 909 | SGs = append(SGs, *instanceObj.VpcSecurityGroupIDs...) 910 | } 911 | 912 | // This instance has no SG attached and so will inherit from the default SG 913 | if len(SGs) == 0 { 914 | _, found := utils.Find(a.undefinedSecurityGroups, "sg-default") 915 | if !found { 916 | // Create default security group 917 | err := createDefaultSecurityGroup(graph) 918 | if err != nil { 919 | return err 920 | } 921 | a.undefinedSecurityGroups = append(a.undefinedSecurityGroups, "sg-default") 922 | } 923 | if Verbose == true { 924 | fmt.Printf("[VERBOSE] AddEdge: sg-default -> aws_instance_%s\n", instanceName) 925 | } 926 | err := graph.AddEdge("sg-default", "aws_instance_"+instanceName, true, nil) 927 | if err != nil { 928 | return err 929 | } 930 | } 931 | // The instance has at least one SG attached to it 932 | for _, sg := range SGs { 933 | // Parse Ingress SG rules 934 | if !IgnoreIngress { 935 | a.parseSGRule(ingressRule, "aws_instance_"+instanceName, sg, graph) 936 | } 937 | 938 | // Parse Egress SG rules 939 | if !IgnoreEgress { 940 | a.parseSGRule(egressRule, "aws_instance_"+instanceName, sg, graph) 941 | } 942 | } 943 | } 944 | 945 | // Link DB Instances with their Security Groups 946 | for instanceName, instanceObj := range a.DBInstance { 947 | 948 | // Get the Security Groups of the DB instance 949 | var SGs []string 950 | if instanceObj.VpcSecurityGroupIDs != nil { 951 | SGs = append(SGs, *instanceObj.VpcSecurityGroupIDs...) 952 | } 953 | 954 | // The instance has at least one SG attached to it 955 | for _, sg := range SGs { 956 | // Parse Ingress SG rules 957 | if !IgnoreIngress { 958 | a.parseSGRule(ingressRule, "aws_db_instance_"+instanceName, sg, graph) 959 | } 960 | 961 | // Parse Egress SG rules 962 | if !IgnoreEgress { 963 | a.parseSGRule(egressRule, "aws_db_instance_"+instanceName, sg, graph) 964 | } 965 | } 966 | } 967 | 968 | return nil 969 | } 970 | 971 | // PrintUnsupportedResources displays all resources currently unsupported by tfviz 972 | func (a *Data) PrintUnsupportedResources() { 973 | if len(a.unsupportedResources) > 0 { 974 | fmt.Println("[WARNING] Unsupported resources:") 975 | for _, r := range a.unsupportedResources { 976 | fmt.Println(" -", r) 977 | } 978 | } 979 | } -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 9 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 10 | github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 11 | github.com/Azure/azure-sdk-for-go v36.2.0+incompatible h1:09cv2WoH0g6jl6m2iT+R9qcIPZKhXEL0sbmLhxP895s= 12 | github.com/Azure/azure-sdk-for-go v36.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= 13 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 14 | github.com/Azure/go-autorest/autorest v0.9.2 h1:6AWuh3uWrsZJcNoCHrCF/+g4aKPCU39kaMO6/qrnK/4= 15 | github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 16 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= 17 | github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503 h1:Hxqlh1uAA8aGpa1dFhDNhll7U/rkWtG8ZItFvRMr7l0= 18 | github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= 19 | github.com/Azure/go-autorest/autorest/azure/cli v0.2.0 h1:pSwNMF0qotgehbQNllUWwJ4V3vnrLKOzHrwDLEZK904= 20 | github.com/Azure/go-autorest/autorest/azure/cli v0.2.0/go.mod h1:WWTbGPvkAg3I4ms2j2s+Zr5xCGwGqTQh+6M2ZqOczkE= 21 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= 22 | github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= 23 | github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= 24 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 25 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 26 | github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= 27 | github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= 28 | github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= 29 | github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4= 30 | github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= 31 | github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= 32 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= 33 | github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= 34 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 35 | github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4 h1:pSm8mp0T2OH2CPmPDPtwHPr3VAQaOwVF/JbllOPP4xA= 36 | github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= 37 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 38 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 39 | github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022 h1:y8Gs8CzNfDF5AZvjr+5UyGQvQEBL7pwo+v+wX6q9JI8= 40 | github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= 41 | github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= 42 | github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI= 43 | github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no= 44 | github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= 45 | github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 46 | github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= 47 | github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 48 | github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= 49 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 50 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 51 | github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190329064014-6e358769c32a h1:APorzFpCcv6wtD5vmRWYqNm4N55kbepL7c7kTq9XI6A= 52 | github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190329064014-6e358769c32a/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= 53 | github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70 h1:FrF4uxA24DF3ARNXVbUin3wa5fDLaB1Cy8mKks/LRz4= 54 | github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190103054945-8205d1f41e70/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= 55 | github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible h1:ABQ7FF+IxSFHDMOTtjCfmMDMHiCq6EsAoCV/9sFinaM= 56 | github.com/aliyun/aliyun-tablestore-go-sdk v4.1.2+incompatible/go.mod h1:LDQHRZylxvcg8H7wBIDfvO5g/cy4/sz1iucBlc2l3Jw= 57 | github.com/antchfx/xpath v0.0.0-20190129040759-c8489ed3251e/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= 58 | github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0/go.mod h1:LzD22aAzDP8/dyiCKFp31He4m2GPjl0AFyzDtZzUu9M= 59 | github.com/apparentlymart/go-cidr v1.0.1 h1:NmIwLZ/KdsjIUlhf+/Np40atNXm/+lZ5txfTJ/SpF+U= 60 | github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= 61 | github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= 62 | github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= 63 | github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= 64 | github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= 65 | github.com/apparentlymart/go-textseg/v12 v12.0.0 h1:bNEQyAGak9tojivJNkoqWErVCQbjdL7GzRt3F8NvfJ0= 66 | github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= 67 | github.com/apparentlymart/go-versions v0.0.2-0.20180815153302-64b99f7cb171/go.mod h1:JXY95WvQrPJQtudvNARshgWajS7jNNlM90altXIPNyI= 68 | github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs= 69 | github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 70 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 71 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 72 | github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= 73 | github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 74 | github.com/awalterschulze/gographviz v2.0.1+incompatible h1:XIECBRq9VPEQqkQL5pw2OtjCAdrtIgFKoJU8eT98AS8= 75 | github.com/awalterschulze/gographviz v2.0.1+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= 76 | github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= 77 | github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 78 | github.com/aws/aws-sdk-go v1.30.12 h1:KrjyosZvkpJjcwMk0RNxMZewQ47v7+ZkbQDXjWsJMs8= 79 | github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= 80 | github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= 81 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 82 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= 83 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= 84 | github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= 85 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 86 | github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= 87 | github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 88 | github.com/bmatcuk/doublestar v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk= 89 | github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= 90 | github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= 91 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 92 | github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= 93 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 94 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= 95 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 96 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 97 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 98 | github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 99 | github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= 100 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 101 | github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= 102 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 103 | github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 104 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 105 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 106 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 107 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 108 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 109 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 110 | github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= 111 | github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= 112 | github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= 113 | github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI= 114 | github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= 115 | github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1/go.mod h1:lcy9/2gH1jn/VCLouHA6tOEwLoNVd4GW6zhuKLmHC2Y= 116 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 117 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 118 | github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= 119 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 120 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 121 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 122 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 123 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 124 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 125 | github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 126 | github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 127 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 128 | github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= 129 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 130 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 131 | github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 132 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 133 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 134 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 135 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 136 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 137 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 138 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 139 | github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= 140 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 141 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 142 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 143 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 144 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 145 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 146 | github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= 147 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 148 | github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= 149 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 150 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 151 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 152 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 153 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 154 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 155 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 156 | github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= 157 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 158 | github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968 h1:Pu+HW4kcQozw0QyrTTgLE+3RXNqFhQNNzhbnoLFL83c= 159 | github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= 160 | github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01 h1:OgCNGSnEalfkRpn//WGJHhpo7fkP+LhTpvEITZ7CkK4= 161 | github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw= 162 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 163 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 164 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 165 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 166 | github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 167 | github.com/hashicorp/aws-sdk-go-base v0.4.0 h1:zH9hNUdsS+2G0zJaU85ul8D59BGnZBaKM+KMNPAHGwk= 168 | github.com/hashicorp/aws-sdk-go-base v0.4.0/go.mod h1:eRhlz3c4nhqxFZJAahJEFL7gh6Jyj5rQmQc7F9eHFyQ= 169 | github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089 h1:1eDpXAxTh0iPv+1kc9/gfSI2pxRERDsTk/lNGolwHn8= 170 | github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= 171 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 172 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 173 | github.com/hashicorp/go-azure-helpers v0.10.0 h1:KhjDnQhCqEMKlt4yH00MCevJQPJ6LkHFdSveXINO6vE= 174 | github.com/hashicorp/go-azure-helpers v0.10.0/go.mod h1:YuAtHxm2v74s+IjQwUG88dHBJPd5jL+cXr5BGVzSKhE= 175 | github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= 176 | github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= 177 | github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 178 | github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= 179 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 180 | github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02 h1:l1KB3bHVdvegcIf5upQ5mjcHjs2qsWnKh4Yr9xgIuu8= 181 | github.com/hashicorp/go-getter v1.4.2-0.20200106182914-9813cbd4eb02/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= 182 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= 183 | github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f h1:Yv9YzBlAETjy6AOX9eLBZ3nshNVRREgerT/3nvxlGho= 184 | github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 185 | github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa/go.mod h1:6ij3Z20p+OhOkCSrA0gImAWoHYQRGbnlcuk6XYTiaRw= 186 | github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 187 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 188 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 189 | github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= 190 | github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= 191 | github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4= 192 | github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= 193 | github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= 194 | github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= 195 | github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= 196 | github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= 197 | github.com/hashicorp/go-slug v0.4.1 h1:/jAo8dNuLgSImoLXaX7Od7QB4TfYCVPam+OpAt5bZqc= 198 | github.com/hashicorp/go-slug v0.4.1/go.mod h1:I5tq5Lv0E2xcNXNkmx7BSfzi1PsJ2cNjs3cC3LwyhK8= 199 | github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 200 | github.com/hashicorp/go-tfe v0.8.1 h1:J6ulpLaKPHrcnwudRjxvlMYIGzqQFlnPhg3SVFh5N4E= 201 | github.com/hashicorp/go-tfe v0.8.1/go.mod h1:XAV72S4O1iP8BDaqiaPLmL2B4EE6almocnOn8E8stHc= 202 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 203 | github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= 204 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 205 | github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 206 | github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= 207 | github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 208 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 209 | github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= 210 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 211 | github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws= 212 | github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= 213 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 214 | github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= 215 | github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= 216 | github.com/hashicorp/hcl/v2 v2.6.0 h1:3krZOfGY6SziUXa6H9PJU6TyohHn7I+ARYnhbeNBz+o= 217 | github.com/hashicorp/hcl/v2 v2.6.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= 218 | github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590 h1:2yzhWGdgQUWZUCNK+AoO35V+HTsgEmcM4J9IkArh7PI= 219 | github.com/hashicorp/hil v0.0.0-20190212112733-ab17b08d6590/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= 220 | github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE= 221 | github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb h1:ZbgmOQt8DOg796figP87/EFCVx2v2h9yRvwHF/zceX4= 222 | github.com/hashicorp/serf v0.0.0-20160124182025-e4ec8cc423bb/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE= 223 | github.com/hashicorp/terraform v0.12.29 h1:UkuApT6qh6KONIT1Jz7HoV8f4B+x71db3bmGcBzjBB0= 224 | github.com/hashicorp/terraform v0.12.29/go.mod h1:CBxNAiTW0pLap44/3GU4j7cYE2bMhkKZNlHPcr4P55U= 225 | github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7 h1:Pc5TCv9mbxFN6UVX0LH6CpQrdTM5YjbVI2w15237Pjk= 226 | github.com/hashicorp/terraform-config-inspect v0.0.0-20191212124732-c6ae6269b9d7/go.mod h1:p+ivJws3dpqbp1iP84+npOyAmTTOLMgCzrXd3GSdn/A= 227 | github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596 h1:hjyO2JsNZUKT1ym+FAdlBEkGPevazYsmVgIMw7dVELg= 228 | github.com/hashicorp/terraform-svchost v0.0.0-20191011084731-65d371908596/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= 229 | github.com/hashicorp/vault v0.10.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= 230 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= 231 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 232 | github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= 233 | github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 234 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 235 | github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= 236 | github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= 237 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 238 | github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926 h1:kie3qOosvRKqwij2HGzXWffwpXvcqfPPXRUw8I4F/mg= 239 | github.com/joyent/triton-go v0.0.0-20180313100802-d8f9c0314926/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= 240 | github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= 241 | github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 242 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 243 | github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 244 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 245 | github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= 246 | github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= 247 | github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= 248 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 249 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 250 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 251 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 252 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 253 | github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= 254 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 255 | github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= 256 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 257 | github.com/likexian/gokit v0.0.0-20190309162924-0a377eecf7aa/go.mod h1:QdfYv6y6qPA9pbBA2qXtoT8BMKha6UyNbxWGWl/9Jfk= 258 | github.com/likexian/gokit v0.0.0-20190418170008-ace88ad0983b/go.mod h1:KKqSnk/VVSW8kEyO2vVCXoanzEutKdlBAPohmGXkxCk= 259 | github.com/likexian/gokit v0.0.0-20190501133040-e77ea8b19cdc/go.mod h1:3kvONayqCaj+UgrRZGpgfXzHdMYCAO0KAt4/8n0L57Y= 260 | github.com/likexian/gokit v0.20.15 h1:DgtIqqTRFqtbiLJFzuRESwVrxWxfs8OlY6hnPYBa3BM= 261 | github.com/likexian/gokit v0.20.15/go.mod h1:kn+nTv3tqh6yhor9BC4Lfiu58SmH8NmQ2PmEl+uM6nU= 262 | github.com/likexian/simplejson-go v0.0.0-20190409170913-40473a74d76d/go.mod h1:Typ1BfnATYtZ/+/shXfFYLrovhFyuKvzwrdOnIDHlmg= 263 | github.com/likexian/simplejson-go v0.0.0-20190419151922-c1f9f0b4f084/go.mod h1:U4O1vIJvIKwbMZKUJ62lppfdvkCdVd2nfMimHK81eec= 264 | github.com/likexian/simplejson-go v0.0.0-20190502021454-d8787b4bfa0b/go.mod h1:3BWwtmKP9cXWwYCr5bkoVDEfLywacOv0s06OBEDpyt8= 265 | github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82 h1:wnfcqULT+N2seWf6y4yHzmi7GD2kNx4Ute0qArktD48= 266 | github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82/go.mod h1:y54tfGmO3NKssKveTEFFzH8C/akrSOy/iW9qEAUDV84= 267 | github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9 h1:SmVbOZFWAlyQshuMfOkiAx1f5oUTsOGG5IXplAEYeeM= 268 | github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= 269 | github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b h1:/1RFh2SLCJ+tEnT73+Fh5R2AO89sQqs8ba7o+hx1G0Y= 270 | github.com/masterzen/winrm v0.0.0-20190223112901-5e5c9a7fe54b/go.mod h1:wr1VqkwW0AB5JS0QLy5GpVMS9E3VtRoSYXUYyVk46KY= 271 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 272 | github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= 273 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 274 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 275 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 276 | github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= 277 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 278 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 279 | github.com/mattn/go-shellwords v1.0.4 h1:xmZZyxuP+bYKAKkA9ABYXVNJ+G/Wf3R8d8vAP3LDJJk= 280 | github.com/mattn/go-shellwords v1.0.4/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= 281 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 282 | github.com/miekg/dns v1.0.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 283 | github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= 284 | github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 285 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= 286 | github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= 287 | github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= 288 | github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= 289 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 290 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 291 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 292 | github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb h1:GRiLv4rgyqjqzxbhJke65IYUf4NCOOvrPOJbV/sPxkM= 293 | github.com/mitchellh/go-linereader v0.0.0-20190213213312-1b945b3263eb/go.mod h1:OaY7UOoTkkrX3wRwjpYRKafIkkyeD0UtweSHAWWiqQM= 294 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 295 | github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= 296 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 297 | github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 298 | github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= 299 | github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 300 | github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= 301 | github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= 302 | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= 303 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 304 | github.com/mitchellh/panicwrap v1.0.0 h1:67zIyVakCIvcs69A0FGfZjBdPleaonSgGlXRSRlb6fE= 305 | github.com/mitchellh/panicwrap v1.0.0/go.mod h1:pKvZHwWrZowLUzftuFq7coarnxbBXU4aQh3N0BJOeeA= 306 | github.com/mitchellh/prefixedio v0.0.0-20190213213902-5733675afd51 h1:eD92Am0Qf3rqhsOeA1zwBHSfRkoHrt4o6uORamdmJP8= 307 | github.com/mitchellh/prefixedio v0.0.0-20190213213902-5733675afd51/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo= 308 | github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= 309 | github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 310 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 311 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 312 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 313 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 314 | github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= 315 | github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= 316 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 317 | github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= 318 | github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= 319 | github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= 320 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 321 | github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58 h1:m3CEgv3ah1Rhy82L+c0QG/U3VyY1UsvsIdkh0/rU97Y= 322 | github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk= 323 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 324 | github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= 325 | github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= 326 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 327 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 328 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 329 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 330 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 331 | github.com/posener/complete v1.2.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI= 332 | github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= 333 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 334 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= 335 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 336 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 337 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 338 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 339 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 340 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 341 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 342 | github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= 343 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 344 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 345 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 346 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 347 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 348 | github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= 349 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 350 | github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= 351 | github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 352 | github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 353 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 354 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 355 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 356 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 357 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 358 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 359 | github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d h1:Z4EH+5EffvBEhh37F0C0DnpklTMh00JOkjW5zK3ofBI= 360 | github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw= 361 | github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible h1:5Td2b0yfaOvw9M9nZ5Oav6Li9bxUNxt4DgxMfIPpsa0= 362 | github.com/tencentcloud/tencentcloud-sdk-go v3.0.82+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= 363 | github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c h1:iRD1CqtWUjgEVEmjwTMbP1DMzz1HRytOsgx/rlw/vNs= 364 | github.com/tencentyun/cos-go-sdk-v5 v0.0.0-20190808065407-f07404cefc8c/go.mod h1:wk2XFUg6egk4tSDNZtXeKfe2G6690UVyt163PuUxBZk= 365 | github.com/terraform-providers/terraform-provider-openstack v1.15.0 h1:adpjqej+F8BAX9dHmuPF47sUIkgifeqBu6p7iCsyj0Y= 366 | github.com/terraform-providers/terraform-provider-openstack v1.15.0/go.mod h1:2aQ6n/BtChAl1y2S60vebhyJyZXBsuAI5G4+lHrT1Ew= 367 | github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 368 | github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 h1:cMjKdf4PxEBN9K5HaD9UMW8gkTbM0kMzkTa9SJe0WNQ= 369 | github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= 370 | github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= 371 | github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 372 | github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 373 | github.com/vmihailenco/msgpack v4.0.1+incompatible h1:RMF1enSPeKTlXrXdOcqjFUElywVZjjC6pqse21bKbEU= 374 | github.com/vmihailenco/msgpack v4.0.1+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= 375 | github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= 376 | github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= 377 | github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 378 | github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 h1:Jpn2j6wHkC9wJv5iMfJhKqrZJx3TahFx+7sbZ7zQdxs= 379 | github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= 380 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 381 | github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= 382 | github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= 383 | github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 384 | github.com/zclconf/go-cty v1.2.1/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= 385 | github.com/zclconf/go-cty v1.5.1 h1:oALUZX+aJeEBUe2a1+uD2+UTaYfEjnKFDEMRydkGvWE= 386 | github.com/zclconf/go-cty v1.5.1/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= 387 | github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8= 388 | github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= 389 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 390 | go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= 391 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 392 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 393 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 394 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 395 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 396 | golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 397 | golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 398 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 399 | golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 400 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 401 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 402 | golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= 403 | golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 404 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 405 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 406 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 407 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 408 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 409 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 410 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 411 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 412 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 413 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 414 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 415 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 416 | golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 417 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 418 | golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 419 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 420 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 421 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 422 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 423 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 424 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 425 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 426 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 427 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 428 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 429 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 430 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 431 | golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 432 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= 433 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 434 | golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= 435 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 436 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 437 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 438 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= 439 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 440 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 441 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 442 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 443 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 444 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 445 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 446 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 447 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 448 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 449 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 450 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 451 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 452 | golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 453 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 454 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 455 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 456 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 457 | golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 458 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 459 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 460 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 461 | golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= 462 | golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 463 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 464 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 465 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 466 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 467 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 468 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 469 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 470 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= 471 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 472 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 473 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 474 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 475 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 476 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 477 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 478 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 479 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 480 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 481 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 482 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0 h1:Dh6fw+p6FyRl5x/FvNswO1ji0lIGzm3KP8Y9VkS9PTE= 483 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 484 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 485 | golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207 h1:8Kg+JssU1jBZs8GIrL5pl4nVyaqyyhdmHAR4D1zGErg= 486 | golang.org/x/tools v0.0.0-20200811215021-48a8ffc5b207/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 487 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 488 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 489 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 490 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 491 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 492 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 493 | google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= 494 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 495 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 496 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 497 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 498 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 499 | google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 500 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 501 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 502 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 503 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 504 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 505 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 506 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= 507 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 508 | google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 509 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 510 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 511 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 512 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 513 | google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= 514 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 515 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 516 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 517 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 518 | gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 519 | gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= 520 | gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 521 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 522 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 523 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 524 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 525 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 526 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 527 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 528 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 529 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 530 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 531 | --------------------------------------------------------------------------------