├── ebs-encrypt ├── go.mod ├── README.md ├── main.go └── go.sum └── README.md /ebs-encrypt/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/hatemosphere/ebs-encrypt 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.33.16 7 | github.com/buger/jsonparser v1.0.0 8 | github.com/mkideal/cli v0.2.2 // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /ebs-encrypt/README.md: -------------------------------------------------------------------------------- 1 | ### Preamble 2 | 3 | As you might have guessed or noticed, AWS does not support on-the-fly encryption of EBS volumes (as of 01.08.2020), so this can only be performed through snapshotting and restoring with modified volume spec. 4 | 5 | ***Key features of this stupidly simple tool:*** 6 | 7 | - makes a snapshot of EBS volume 8 | - creates a new encrypted EBS volume with the same tags in the same AZ with the same spec (volume type and size are not passed explicitly since it happens under the hood through volume metadata stored in the snapshot) 9 | - eventually performs a cleanup of the snapshot 10 | 11 | - does not remove or untag the old volume 12 | - please do not expect any other automagic from it 13 | 14 | ### Usage 15 | 16 | It will use default AWS SDK credentials chain, so make sure to pass AWS credentials in one way or another. The KMS key ID is optional, hardcoded default is `alias/aws/ebs` (the same one that is implicitly used if you create encrypted snapshot without passing KMS key at all). 17 | 18 | Usage example: 19 | 20 | ```bash 21 | $ AWS_REGION=us-west-2 go run main.go --volume_id=vol-00000000000001337 22 | vol-0d93008cbb8175778 23 | 24 | Creating AWS client session... 25 | Creating EC2 service... 26 | Going to work with volume vol-00000000000001337 in us-west-2 region 27 | Getting vol-00000000000001337 volume metadata... 28 | Checking if volume vol-00000000000001337 is in available state... 29 | Volume vol-00000000000001337 is available, so we can proceed with a snapshot 30 | Creating EBS volume vol-00000000000001337 snapshot... 31 | Waiting for snapshot snap-00000000000001337 creation completion... 32 | Creating encrypted volume (KMS ID: alias/aws/ebs) from snapshot snap-00000000000001337 in us-west-2a and restoring the tags 33 | Waiting for volume vol-00000000133701337 creation completion... 34 | Cleaning up snapshot snap-00000000000001337 35 | New encrypted volume vol-00000000133701337 is ready 36 | ``` 37 | 38 | If you'd like to get more bells and whistles, your Pull Requests are always welcomed! 39 | 40 | ### Current limitations 41 | 42 | - Code quality is "i scraped it in few hours while drinking beer" 43 | - Error handling is a joke 44 | - Logging and overal verbocity is just enough if you want to perform "cut a trees with an axe" type of activity 45 | - AWS API throttling might screw you over, no retries are provided 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Preamble 2 | 3 | So if you stumbled across this repo to read this README file with one single purpose - to overcome kops [limitation](https://github.com/kubernetes/kops/blob/master/docs/operations/etcd_backup_restore_encryption.md#etcd-volume-encryption) to not being able to encrypt etcd cluster volumes on running cluster, even while having shiny new `etcd-manager` managing your 3+ node etcd cluster, then you are in the right place. This was tested a few times on **AWS** and will probably work in GCP with minor adjustments. Your security department will be proud of you! 4 | 5 | There are multiple ways to hack your way through, so the guide below is just my opinionated best (read as "easiest/fastest/reliable") sequence of actions to achieve this. 6 | 7 | ## Encrypt etcd volumes on running Kubernetes cluster managed by kops in AWS, wonky how-to 8 | 9 | ### Preparation 10 | 11 | Make sure you have multi-node etcd cluster, otherwise you would need to perform another painful maintenance to convert it to multi-node. Consult this [guide](https://github.com/kubernetes/kops/blob/master/docs/single-to-multi-master.md) for more details on how to make it happen. As an alternative you can still perform this on a single node cluster by bringing it down for maintenance (***NOT RECOMMENDED BY ANY MEANS***). 12 | 13 | ### Working around kops validation 14 | 15 | Now we need to bypass kops cluster spec validation, which won't allow us to simply change `encryptedVolume` fields for each etcd member to `true`. There are two options for this: we can simply download current kops cluster spec from S3 bucket, modify these fields and re-upload modified spec back. 16 | 17 | A less hacky option would be to use kops binary itself to make this happen (just to have all other bundled state validations serving us to reduce the chances to destroy our cluster completely). Depending on how you manage your cluster state in a declarative way you need to execute `kops edit cluster` or `kops replace -f` in two steps, by first changing the names of all etcd members: 18 | 19 | This part of cluster spec: 20 | 21 | ```yaml 22 | spec: 23 | ... 24 | etcdClusters: 25 | - name: main 26 | etcdMembers: 27 | - instanceGroup: master-us-west-2a 28 | name: a 29 | - instanceGroup: master-us-west-2b 30 | name: b 31 | - instanceGroup: master-us-west-2c 32 | name: c 33 | ``` 34 | 35 | Will be changed to: 36 | 37 | ```yaml 38 | spec: 39 | ... 40 | etcdClusters: 41 | - name: main 42 | etcdMembers: 43 | - instanceGroup: master-us-west-2a 44 | name: a1 45 | - instanceGroup: master-us-west-2b 46 | name: b1 47 | - instanceGroup: master-us-west-2c 48 | name: c1 49 | ``` 50 | 51 | And only after this we can fool kops validations and enable (not really, we will enable it later) etcd volumes encryption (don't forget to revert changes to etcd cluster member names): 52 | 53 | ```yaml 54 | spec: 55 | ... 56 | etcdClusters: 57 | - name: main 58 | etcdMembers: 59 | - instanceGroup: master-us-west-2a 60 | name: a 61 | encryptedVolume: true 62 | - instanceGroup: master-us-west-2b 63 | name: b 64 | encryptedVolume: true 65 | - instanceGroup: master-us-west-2c 66 | name: c 67 | encryptedVolume: true 68 | ``` 69 | 70 | ### Getting the actual shit done 71 | 72 | So now we have a discreptancy between cluster spec stored in S3 bucket and the actual state of our volumes. Knowing that kops won't store etcd EBS volume IDs and the actual volume discovery during master node startup relies **ONLY** on EBS volume tags, we are going to encrypt and replace these volumes one by one. 73 | 74 | Assuming that you have vanilla 3+ (don't ask me why would someone have more than 3 master nodes) master setup configured by kops which should look like 3+ AWS autoscaling groups, ideally one per each availability zone, we are going to perform **etcd volume encryption rolling upgrade** for each ASG. 75 | 76 | For this we need to modify first ASG with Kubernetes master by reducing **desired/minimum/maximum** capacities from ***1*** to **0** and after it's done, to terminate the EC2 instance with Kubernetes master in the same AZ and wait for first etcd member volumes to change their state from `in-use` to `available` (by default you should have **two** etcd clusters per Kubernetes cluster, the main one and the second one to store only Kubernetes events). 77 | 78 | Now we need to create snapshots of these etcd volumes and then to create new encrypted volumes from snapshots by copying volume tags from current non-encrypted etcd volumes to new ones. I hacked together a tool to automate this process, you can find it in `ebs-encrypt` directory if this repository. After it's done, we need to remove all the tags from old etcd volume (again, etcd-manager has volume discovery based on volume tags and we don't want to have two volumes with the same tags). We are now ready to change ASG capacity back to ***1/1/1*** and to wait until our previously terminated master starts and becomes ready. After master is back online, we can perform the same sequence of actions for the rest of Kubernetes masters. 79 | 80 | ### Making sure it works 81 | 82 | When all the etcd members are successfully migrated to encrypted volumes, you can verify that kops is happy with them by executing `kops cluster update` and seeing zero planned changes to the cluster state. 83 | -------------------------------------------------------------------------------- /ebs-encrypt/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/aws/aws-sdk-go/aws" 9 | "github.com/aws/aws-sdk-go/aws/awserr" 10 | "github.com/aws/aws-sdk-go/aws/session" 11 | "github.com/aws/aws-sdk-go/service/ec2" 12 | ) 13 | 14 | const ( 15 | requiredVolumeState = "available" 16 | defaultKmsKeyID = "alias/aws/ebs" 17 | ) 18 | 19 | func createService() (*session.Session, *ec2.EC2) { 20 | fmt.Println("Creating AWS client session...") 21 | session, sessionErr := session.NewSession() 22 | if sessionErr != nil { 23 | fmt.Println("Could not create session", sessionErr) 24 | os.Exit(1) 25 | } 26 | 27 | fmt.Println("Creating EC2 service...") 28 | service := ec2.New(session) 29 | return session, service 30 | } 31 | 32 | func getVolumeMetadata(volumeID string, service *ec2.EC2) *ec2.DescribeVolumesOutput { 33 | fmt.Println("Getting " + volumeID + " volume metadata...") 34 | describeVolumeInput := &ec2.DescribeVolumesInput{ 35 | Filters: []*ec2.Filter{ 36 | { 37 | Name: aws.String("volume-id"), 38 | Values: []*string{ 39 | aws.String(volumeID), 40 | }, 41 | }, 42 | }, 43 | } 44 | describeVolumeResult, describeVolumeErr := service.DescribeVolumes(describeVolumeInput) 45 | if describeVolumeErr != nil { 46 | if aerr, ok := describeVolumeErr.(awserr.Error); ok { 47 | switch aerr.Code() { 48 | default: 49 | fmt.Println(aerr.Error()) 50 | } 51 | } else { 52 | fmt.Println(describeVolumeErr.Error()) 53 | } 54 | os.Exit(1) 55 | } 56 | return describeVolumeResult 57 | } 58 | 59 | func isVolumeInValidState(volumeMetadata *ec2.DescribeVolumesOutput, requiredVolumeState string) bool { 60 | volumeID := *volumeMetadata.Volumes[0].VolumeId 61 | volumeState := *volumeMetadata.Volumes[0].State 62 | fmt.Println("Checking if volume " + volumeID + " is in " + requiredVolumeState + " state...") 63 | if volumeState == requiredVolumeState { 64 | fmt.Println("Volume " + volumeID + " is " + requiredVolumeState + ", so we can proceed with a snapshot") 65 | return true 66 | } 67 | fmt.Println("Volume is " + volumeState + ", but should be " + requiredVolumeState) 68 | return false 69 | } 70 | 71 | func createVolumeSnapshot(volumeID string, volumeMetadata *ec2.DescribeVolumesOutput, service *ec2.EC2) (snapshotID string) { 72 | snapshotTagList := &ec2.TagSpecification{ 73 | Tags: volumeMetadata.Volumes[0].Tags[:], 74 | ResourceType: aws.String(ec2.ResourceTypeSnapshot), 75 | } 76 | 77 | fmt.Println("Creating EBS volume " + volumeID + " snapshot...") 78 | createSnasphotInput := &ec2.CreateSnapshotInput{ 79 | VolumeId: aws.String(volumeID), 80 | TagSpecifications: []*ec2.TagSpecification{snapshotTagList}, 81 | } 82 | 83 | createSnapshotResult, createSnapshotErr := service.CreateSnapshot(createSnasphotInput) 84 | if createSnapshotErr != nil { 85 | if aerr, ok := createSnapshotErr.(awserr.Error); ok { 86 | switch aerr.Code() { 87 | default: 88 | fmt.Println(aerr.Error()) 89 | } 90 | } else { 91 | fmt.Println(createSnapshotErr.Error()) 92 | } 93 | os.Exit(1) 94 | } 95 | snapshotID = *createSnapshotResult.SnapshotId 96 | 97 | describeSnapshotInput := &ec2.DescribeSnapshotsInput{ 98 | SnapshotIds: []*string{ 99 | aws.String(snapshotID), 100 | }, 101 | } 102 | 103 | fmt.Println("Waiting for snapshot " + snapshotID + " creation completion...") 104 | if waitForSnapshotCompletionErr := service.WaitUntilSnapshotCompleted(describeSnapshotInput); waitForSnapshotCompletionErr != nil { 105 | // TODO: Improve error handling :troll: 106 | panic(waitForSnapshotCompletionErr) 107 | } 108 | return snapshotID 109 | } 110 | 111 | func createEncryptedVolumeFromSnapshot(snapshotID string, kmsID string, volumeMetadata *ec2.DescribeVolumesOutput, service *ec2.EC2) (volumeID string) { 112 | volumeAZ := *volumeMetadata.Volumes[0].AvailabilityZone 113 | volumeTagList := &ec2.TagSpecification{ 114 | Tags: volumeMetadata.Volumes[0].Tags[:], 115 | ResourceType: aws.String(ec2.ResourceTypeVolume), 116 | } 117 | 118 | fmt.Println("Creating encrypted volume (KMS ID: " + kmsID + ") from snapshot " + snapshotID + " in " + volumeAZ + " and restoring the tags") 119 | input := &ec2.CreateVolumeInput{ 120 | // Size and volume type should be propagated automatically from snapshot, TODO: check it 121 | AvailabilityZone: aws.String(volumeAZ), 122 | SnapshotId: aws.String(snapshotID), 123 | Encrypted: aws.Bool(true), 124 | // You can specify the CMK using any of the following: 125 | // * Key ID. For example, key/1234abcd-12ab-34cd-56ef-1234567890ab. 126 | // * Key alias. For example, alias/ExampleAlias. 127 | // * Key ARN. For example, arn:aws:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef. 128 | // * Alias ARN. For example, arn:aws:kms:us-east-1:012345678910:alias/ExampleAlias. 129 | // If KMS Key speficied incorrectly, volume creation can freeze withour eror 130 | KmsKeyId: aws.String(kmsID), 131 | TagSpecifications: []*ec2.TagSpecification{volumeTagList}, 132 | } 133 | 134 | createVolumeResult, createVolumeErr := service.CreateVolume(input) 135 | if createVolumeErr != nil { 136 | if aerr, ok := createVolumeErr.(awserr.Error); ok { 137 | switch aerr.Code() { 138 | default: 139 | fmt.Println(aerr.Error()) 140 | } 141 | } else { 142 | fmt.Println(createVolumeErr.Error()) 143 | } 144 | os.Exit(1) 145 | } 146 | 147 | createdVolumeID := *createVolumeResult.VolumeId 148 | 149 | fmt.Println("Waiting for volume " + createdVolumeID + " creation completion...") 150 | describeNewVolumeInput := &ec2.DescribeVolumesInput{ 151 | Filters: []*ec2.Filter{ 152 | { 153 | Name: aws.String("volume-id"), 154 | Values: []*string{ 155 | aws.String(createdVolumeID), 156 | }, 157 | }, 158 | }, 159 | } 160 | if waitForVolumeReadinessErr := service.WaitUntilVolumeAvailable(describeNewVolumeInput); waitForVolumeReadinessErr != nil { 161 | panic(waitForVolumeReadinessErr) 162 | } 163 | 164 | // TODO: mekes sense to be moved to a separate function probably 165 | fmt.Print("Cleaning up snapshot " + snapshotID + "\n") 166 | 167 | deleteSnapshotInput := &ec2.DeleteSnapshotInput{ 168 | SnapshotId: aws.String(snapshotID), 169 | } 170 | 171 | _, deleteSnapshotErr := service.DeleteSnapshot(deleteSnapshotInput) 172 | if deleteSnapshotErr != nil { 173 | if aerr, ok := deleteSnapshotErr.(awserr.Error); ok { 174 | switch aerr.Code() { 175 | default: 176 | fmt.Println(aerr.Error()) 177 | } 178 | } else { 179 | fmt.Println(deleteSnapshotErr.Error()) 180 | } 181 | os.Exit(1) 182 | } 183 | 184 | fmt.Println("New encrypted volume " + createdVolumeID + " is ready") 185 | return createdVolumeID 186 | } 187 | 188 | func main() { 189 | sourceVolumeIDPtr := flag.String("volume_id", "", "AWS EBS target volume ID.") 190 | kmsKeyIDPtr := flag.String("kms_key", defaultKmsKeyID, fmt.Sprintf("AWS KMS key ID (CMK) used to encrypt volume.")) 191 | flag.Parse() 192 | if len(*sourceVolumeIDPtr) == 0 { 193 | fmt.Println("Source volume ID is not specified, getting outta here!") 194 | os.Exit(1) 195 | } 196 | 197 | session, service := createService() 198 | fmt.Println("Going to work with volume " + *sourceVolumeIDPtr + " in " + *session.Config.Region + " region") 199 | sourceVolumeMetadata := getVolumeMetadata(*sourceVolumeIDPtr, service) 200 | 201 | // This is super ugly, volumeStateIsValid should return error instead of printing and this error should be surfaced here 202 | if volumeStateIsValid := isVolumeInValidState(sourceVolumeMetadata, requiredVolumeState); volumeStateIsValid != true { 203 | os.Exit(1) 204 | } 205 | 206 | sourceVolumeSnapshotID := createVolumeSnapshot(*sourceVolumeIDPtr, sourceVolumeMetadata, service) 207 | createEncryptedVolumeFromSnapshot(sourceVolumeSnapshotID, *kmsKeyIDPtr, sourceVolumeMetadata, service) 208 | 209 | } 210 | -------------------------------------------------------------------------------- /ebs-encrypt/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.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= 6 | github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= 7 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 8 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 9 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 10 | github.com/aws/aws-sdk-go v1.33.16 h1:h/3BL2BQMEbS67BPoEo/5jD8IPGVrKBmoa4S9mBBntw= 11 | github.com/aws/aws-sdk-go v1.33.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= 12 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 13 | github.com/buger/jsonparser v1.0.0 h1:etJTGF5ESxjI0Ic2UaLQs2LQQpa8G9ykQScukbh4L8A= 14 | github.com/buger/jsonparser v1.0.0/go.mod h1:tgcrVJ81GPSF0mz+0nu1Xaz0fazGPrmmJfJtxjbHhUQ= 15 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 16 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 17 | github.com/comail/colog v0.0.0-20160416085026-fba8e7b1f46c/go.mod h1:1WwgAwMKQLYG5I2FBhpVx94YTOAuB2W59IZ7REjSE6Y= 18 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 19 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= 21 | github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= 22 | github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 23 | github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= 24 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 25 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 26 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 27 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 28 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 29 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 30 | github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= 31 | github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ= 32 | github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 33 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 34 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 35 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 36 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 37 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 38 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 39 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 40 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 41 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 42 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 43 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 44 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 45 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= 46 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 47 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 48 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 49 | github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= 50 | github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= 51 | github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= 52 | github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= 53 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 54 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 55 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 56 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 57 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 58 | github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= 59 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 60 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 61 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 62 | github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= 63 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 64 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 65 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 66 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 67 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 68 | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 69 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 70 | github.com/mkideal/cli v0.2.2 h1:ppqXv4Ced8Hf1KLEfzwcfeAHXuGRwEnFB7xE/iWWPQo= 71 | github.com/mkideal/cli v0.2.2/go.mod h1:1duqF+rGhMKIF8ezbX/lpkY+Zhn1ECQzzTtcsEh6ZA8= 72 | github.com/mkideal/log v1.0.0/go.mod h1:UHY5EOk5+/f2z2bQ6BGspFw5gl4F1SKjZI7Bqetm724= 73 | github.com/mkideal/pkg v0.1.2 h1:w4CGlOIp9exb1Ypo+XrbIR75ZRruzScNNcX840DSCQ8= 74 | github.com/mkideal/pkg v0.1.2/go.mod h1:4iVkIRF6ThYaNZtD6J/p9gHdy5nXv7EJ+cKuzmmFPAY= 75 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 76 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 77 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 78 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 79 | github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= 80 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 81 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 82 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 83 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 84 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 85 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 86 | github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= 87 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 88 | github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 89 | github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 90 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 91 | github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 92 | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 93 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 94 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 95 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 96 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 97 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 98 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 99 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 100 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 101 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 102 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 103 | github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= 104 | go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= 105 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 106 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 107 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 108 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 109 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 110 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 111 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 112 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 113 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 114 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 115 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 116 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 117 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 118 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 119 | golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 120 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 121 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 122 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 123 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 124 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 125 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 126 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 127 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 128 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 129 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 130 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 131 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 132 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 133 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 134 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 135 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 136 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 137 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 138 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 139 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 140 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 141 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 142 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 143 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 144 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 145 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 146 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 147 | golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 148 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 149 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 150 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 151 | google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= 152 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 153 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 154 | google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 155 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 156 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 157 | google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 158 | google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 159 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 160 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 161 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 162 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 163 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 164 | gopkg.in/redis.v5 v5.2.9/go.mod h1:6gtv0/+A4iM08kdRfocWYB3bLX2tebpNtfKlFT6H4mY= 165 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 166 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 167 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 168 | honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 169 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 170 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 171 | xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= 172 | xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= 173 | --------------------------------------------------------------------------------