commit
a3cb1daa07
@ -1,68 +1,131 @@
|
||||
defaults: &golang
|
||||
docker:
|
||||
- image: circleci/golang:1.12
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- checkout
|
||||
- run: go build -ldflags="-s -w" -o ./pkg/packer_$(go env GOOS)_$(go env GOARCH) .
|
||||
- run: zip ./pkg/packer_$(go env GOOS)_$(go env GOARCH).zip ./pkg/packer_$(go env GOOS)_$(go env GOARCH)
|
||||
- run: rm ./pkg/packer_$(go env GOOS)_$(go env GOARCH)
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- ./pkg/
|
||||
orbs:
|
||||
win: circleci/windows@1.0.0
|
||||
version: 2.1
|
||||
|
||||
executors:
|
||||
golang:
|
||||
docker:
|
||||
- image: circleci/golang:1.13
|
||||
darwin:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
|
||||
commands:
|
||||
install-go-run-tests-unix:
|
||||
parameters:
|
||||
GOOS:
|
||||
type: string
|
||||
GOVERSION:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- run: curl https://dl.google.com/go/go<< parameters.GOVERSION >>.<< parameters.GOOS >>-amd64.tar.gz | tar -C ~/ -xz
|
||||
- run: ~/go/bin/go test ./...
|
||||
install-go-run-tests-windows:
|
||||
parameters:
|
||||
GOVERSION:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- run: curl https://dl.google.com/go/go<< parameters.GOVERSION >>.windows-amd64.zip --output ~/go<< parameters.GOVERSION >>.windows-amd64.zip
|
||||
- run: unzip ~/go<< parameters.GOVERSION >>.windows-amd64.zip -d ~/
|
||||
- run: ~/go/bin/go test ./...
|
||||
build-and-persist-packer-binary:
|
||||
parameters:
|
||||
GOOS:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- run: GOOS=<< parameters.GOOS >> go build -ldflags="-s -w" -o ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH) .
|
||||
- run: zip ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH).zip ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH)
|
||||
- run: rm ./pkg/packer_<< parameters.GOOS >>_$(go env GOARCH)
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- ./pkg/
|
||||
# Golang CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-go/ for more details
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
<<: *golang
|
||||
test-linux:
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- checkout
|
||||
- run: make ci
|
||||
test-darwin:
|
||||
executor: darwin
|
||||
working_directory: ~/go/src/github.com/hashicorp/packer
|
||||
environment:
|
||||
GO111MODULE: "off"
|
||||
steps:
|
||||
- install-go-run-tests-unix:
|
||||
GOOS: darwin
|
||||
GOVERSION: "1.13"
|
||||
test-windows:
|
||||
executor:
|
||||
name: win/vs2019
|
||||
shell: bash.exe
|
||||
steps:
|
||||
- install-go-run-tests-windows:
|
||||
GOVERSION: "1.13"
|
||||
check-vendor-vs-mod:
|
||||
<<: *golang
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
environment:
|
||||
GO111MODULE: "off"
|
||||
steps:
|
||||
- checkout
|
||||
- run: GO111MODULE=on go run . --help
|
||||
- run: make check-vendor-vs-mod
|
||||
check-fmt:
|
||||
<<: *golang
|
||||
executor: golang
|
||||
steps:
|
||||
- checkout
|
||||
- run: make fmt-check
|
||||
check-generate:
|
||||
<<: *golang
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- checkout
|
||||
- run: make generate-check
|
||||
build_linux:
|
||||
<<: *golang
|
||||
environment:
|
||||
GOOS: linux
|
||||
executor: golang
|
||||
steps:
|
||||
- build-and-persist-packer-binary:
|
||||
GOOS: linux
|
||||
build_windows:
|
||||
<<: *golang
|
||||
environment:
|
||||
GOOS: windows
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- build-and-persist-packer-binary:
|
||||
GOOS: windows
|
||||
build_darwin:
|
||||
<<: *golang
|
||||
environment:
|
||||
GOOS: darwin
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- build-and-persist-packer-binary:
|
||||
GOOS: darwin
|
||||
build_freebsd:
|
||||
<<: *golang
|
||||
environment:
|
||||
GOOS: freebsd
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- build-and-persist-packer-binary:
|
||||
GOOS: freebsd
|
||||
build_solaris:
|
||||
<<: *golang
|
||||
environment:
|
||||
GOOS: solaris
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- build-and-persist-packer-binary:
|
||||
GOOS: solaris
|
||||
build_openbsd:
|
||||
<<: *golang
|
||||
environment:
|
||||
GOOS: openbsd
|
||||
executor: golang
|
||||
working_directory: /go/src/github.com/hashicorp/packer
|
||||
steps:
|
||||
- build-and-persist-packer-binary:
|
||||
GOOS: openbsd
|
||||
store_artifacts:
|
||||
<<: *golang
|
||||
executor: golang
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
@ -80,12 +143,18 @@ jobs:
|
||||
ghr -prerelease -t ${GITHUB_TOKEN_AZR} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${CIRCLE_TAG} ./pkg/
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_check_vendor_vs_module:
|
||||
test:
|
||||
jobs:
|
||||
- test-linux
|
||||
- test-darwin
|
||||
- test-windows
|
||||
check-code:
|
||||
jobs:
|
||||
- build
|
||||
- check-vendor-vs-mod
|
||||
- check-fmt
|
||||
- check-generate
|
||||
build_packer_binaries:
|
||||
jobs:
|
||||
- build_linux:
|
||||
filters:
|
||||
tags:
|
||||
|
9
.github/CONTRIBUTING.md
vendored
9
.github/CONTRIBUTING.md
vendored
@ -292,3 +292,12 @@ make testacc TEST=./builder/amazon/ebs TESTARGS="-run TestBuilderAcc_forceDelete
|
||||
Acceptance tests typically require other environment variables to be set for
|
||||
things such as API tokens and keys. Each test should error and tell you which
|
||||
credentials are missing, so those are not documented here.
|
||||
|
||||
#### Debugging Plugins
|
||||
|
||||
Each packer plugin runs in a separate process and communicates with RCP over a
|
||||
socket therefore using a debugger will not work (be complicated at least).
|
||||
|
||||
But most of the Packer code is really simple and easy to follow with PACKER_LOG
|
||||
turned on. If that doesn't work adding some extra debug print outs when you have
|
||||
homed in on the problem is usually enough.
|
||||
|
23
.travis.yml
23
.travis.yml
@ -1,23 +0,0 @@
|
||||
env:
|
||||
- USER=travis GO111MODULE=off
|
||||
|
||||
os:
|
||||
- osx
|
||||
|
||||
sudo: false
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
|
||||
script:
|
||||
- df -h
|
||||
- travis_wait make ci
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
40
CHANGELOG.md
40
CHANGELOG.md
@ -1,11 +1,51 @@
|
||||
## 1.4.4 (Upcoming)
|
||||
|
||||
### IMPROVEMENTS:
|
||||
* builder/amazon: Add ability to set `run_volume_tags` [GH-8051]
|
||||
* builder/amazon: Add AWS API call reties on AMI prevalidation [GH-8034]
|
||||
* builder/hcloud: Allow selecting image based on filters [GH-7945]
|
||||
* builder/hyper-v: Decrease the delay between Hyper-V VM startup and hyper-v
|
||||
builder's ability to send keystrokes to the target VM. [GH-7970]
|
||||
* builder/openstack: Store WinRM password for provisioners to use [GH-7940]
|
||||
* builder/proxmox: Shorten default boot_key_interval to 5ms from 100ms
|
||||
[GH-8088]
|
||||
* builder/ucloud: Make ucloud builder's base url configurable [GH-8095]
|
||||
* builder/virtualbox-vm: Make target snapshot optional [GH-8011] [GH-8004]
|
||||
* builder/yandex: Support GPU instances and set source image by name [GH-8091]
|
||||
* core: Add a new `floppy_label` option [GH-8099]
|
||||
* core: Added version compatibility to console command [GH-8080]
|
||||
* post-processor/vagrant-cloud: Allow use of the Artifice post-processor with
|
||||
the Vagrant Cloud post-processor [GH-8018] [GH-8027]
|
||||
* post-processor/vsphere: Removed redundant whitelist check for builders,
|
||||
allowing users to use post-processor withough the VMWare builder [GH-8064]
|
||||
|
||||
|
||||
### BUG FIXES:
|
||||
* builder/amazon: Fix FleetID crash [GH-8013]
|
||||
* builder/azure: Avoid a panic in getObjectIdFromToken [GH-8047]
|
||||
* builder/hyper-v: Fix when management interface is not part of virtual switch
|
||||
[GH-8017]
|
||||
* builder/openstack: Fix race condition created when adding metadata [GH-8016]
|
||||
* builder/outscale: Get SSH Host from VM.Nics instead of VM Root [GH-8077]
|
||||
* builder/proxmox: Bump proxmox api dep, fixing bug with checking http status
|
||||
during boot command [GH-8083]
|
||||
* builder/proxmox: Check that disk format is set when pool type requires it
|
||||
[GH-8084]
|
||||
* builder/proxmox: Fix panic caused by cancelling build [GH-8067] [GH-8072]
|
||||
* builder/qemu: Fix dropped error when retrieving version [GH-8050]
|
||||
* builder/vagrant: Fix provisioning boxes, define source and output boxes
|
||||
[GH-7957]
|
||||
* builder/vagrant: Use GlobalID when provided [GH-8092]
|
||||
* builder/virtualbox: Fix windows pathing problem for guest additions checksum
|
||||
download. [GH-7996]
|
||||
* builder/virtualbox: LoadSnapshots succeeds even if machine has no snapshots
|
||||
[GH-8096]
|
||||
* core: Fix bug where sensitive variables contianing commas were not being
|
||||
properly sanitized in UI calls. [GH-7997]
|
||||
* core: Fix handling of booleans where "unset" is a value distinct from
|
||||
"false". [GH-8021]
|
||||
* core: Fix tests that swallowed errors in goroutines [GH-8094]
|
||||
* provisioner/ansible: Fix provisioner dropped errors [GH-8045]
|
||||
|
||||
## 1.4.3 (August 14, 2019)
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
/builder/profitbricks/ @jasmingacic
|
||||
/builder/triton/ @sean-
|
||||
/builder/ncloud/ @YuSungDuk
|
||||
/builder/proxmox/ @carlpett
|
||||
/builder/scaleway/ @sieben @mvaude @jqueuniet @fflorens @brmzkw
|
||||
/builder/hcloud/ @LKaemmerling
|
||||
/builder/hyperone @m110 @gregorybrzeski @ad-m
|
||||
|
16
Makefile
16
Makefile
@ -45,14 +45,13 @@ install-build-deps: ## Install dependencies for bin build
|
||||
@go get github.com/mitchellh/gox
|
||||
|
||||
install-gen-deps: ## Install dependencies for code generation
|
||||
@go get golang.org/x/tools/cmd/goimports
|
||||
@./scripts/off_gopath.sh; if [ $$? -eq 0 ]; then \
|
||||
go get github.com/mna/pigeon@master; \
|
||||
else \
|
||||
go get -u github.com/mna/pigeon; \
|
||||
fi
|
||||
|
||||
@go get github.com/alvaroloes/enumer
|
||||
# to avoid having to tidy our go deps, we `go get` our binaries from a temp
|
||||
# dir. `go get` will change our deps and the following deps are not part of
|
||||
# out code dependencies; so a go mod tidy will remove them again. `go
|
||||
# install` seems to install the last tagged version and we want to install
|
||||
# master.
|
||||
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/mna/pigeon@master)
|
||||
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/alvaroloes/enumer@master)
|
||||
|
||||
dev: ## Build and install a development build
|
||||
@grep 'const VersionPrerelease = ""' version/version.go > /dev/null ; if [ $$? -eq 0 ]; then \
|
||||
@ -97,7 +96,6 @@ fmt-examples:
|
||||
generate: install-gen-deps ## Generate dynamically generated code
|
||||
go generate ./...
|
||||
go fmt common/bootcommand/boot_command.go
|
||||
goimports -w common/bootcommand/boot_command.go
|
||||
go fmt command/plugin.go
|
||||
|
||||
generate-check: generate ## Check go code generation is on par
|
||||
|
37
appveyor.yml
37
appveyor.yml
@ -1,37 +0,0 @@
|
||||
# appveyor.yml reference : http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
version: "{build}"
|
||||
|
||||
skip_tags: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
os: Windows Server 2012 R2
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\hashicorp\packer
|
||||
|
||||
install:
|
||||
- set GO111MODULE=off
|
||||
- echo %Path%
|
||||
- go version
|
||||
- go env
|
||||
- go get github.com/mitchellh/gox
|
||||
- go get golang.org/x/tools/cmd/stringer
|
||||
|
||||
build_script:
|
||||
- git rev-parse HEAD
|
||||
# go test $(go list ./... | grep -v vendor)
|
||||
- ps: |
|
||||
go.exe test -timeout=2m (go.exe list ./... `
|
||||
|? { -not $_.Contains('/vendor/') } `
|
||||
|? { $_ -ne 'github.com/hashicorp/packer/builder/parallels/common' } `
|
||||
|? { $_ -ne 'github.com/hashicorp/packer/provisioner/ansible' })
|
||||
|
||||
test: off
|
||||
|
||||
deploy: off
|
@ -4,6 +4,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
helperconfig "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
@ -126,13 +127,15 @@ func TestBuilderPrepare_Devices(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(b.config.ECSSystemDiskMapping, AlicloudDiskDevice{
|
||||
expected := AlicloudDiskDevice{
|
||||
DiskCategory: "cloud",
|
||||
Description: "system disk",
|
||||
DiskName: "system_disk",
|
||||
DiskSize: 60,
|
||||
}) {
|
||||
t.Fatalf("system disk is not set properly, actual: %#v", b.config.ECSSystemDiskMapping)
|
||||
Encrypted: helperconfig.TriUnset,
|
||||
}
|
||||
if !reflect.DeepEqual(b.config.ECSSystemDiskMapping, expected) {
|
||||
t.Fatalf("system disk is not set properly, actual: %v; expected: %v", b.config.ECSSystemDiskMapping, expected)
|
||||
}
|
||||
if !reflect.DeepEqual(b.config.ECSImagesDiskMappings, []AlicloudDiskDevice{
|
||||
{
|
||||
|
@ -5,18 +5,19 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type AlicloudDiskDevice struct {
|
||||
DiskName string `mapstructure:"disk_name"`
|
||||
DiskCategory string `mapstructure:"disk_category"`
|
||||
DiskSize int `mapstructure:"disk_size"`
|
||||
SnapshotId string `mapstructure:"disk_snapshot_id"`
|
||||
Description string `mapstructure:"disk_description"`
|
||||
DeleteWithInstance bool `mapstructure:"disk_delete_with_instance"`
|
||||
Device string `mapstructure:"disk_device"`
|
||||
Encrypted *bool `mapstructure:"disk_encrypted"`
|
||||
DiskName string `mapstructure:"disk_name"`
|
||||
DiskCategory string `mapstructure:"disk_category"`
|
||||
DiskSize int `mapstructure:"disk_size"`
|
||||
SnapshotId string `mapstructure:"disk_snapshot_id"`
|
||||
Description string `mapstructure:"disk_description"`
|
||||
DeleteWithInstance bool `mapstructure:"disk_delete_with_instance"`
|
||||
Device string `mapstructure:"disk_device"`
|
||||
Encrypted config.Trilean `mapstructure:"disk_encrypted"`
|
||||
}
|
||||
|
||||
type AlicloudDiskDevices struct {
|
||||
@ -32,7 +33,7 @@ type AlicloudImageConfig struct {
|
||||
AlicloudImageUNShareAccounts []string `mapstructure:"image_unshare_account"`
|
||||
AlicloudImageDestinationRegions []string `mapstructure:"image_copy_regions"`
|
||||
AlicloudImageDestinationNames []string `mapstructure:"image_copy_names"`
|
||||
ImageEncrypted *bool `mapstructure:"image_encrypted"`
|
||||
ImageEncrypted config.Trilean `mapstructure:"image_encrypted"`
|
||||
AlicloudImageForceDelete bool `mapstructure:"image_force_delete"`
|
||||
AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots"`
|
||||
AlicloudImageForceDeleteInstances bool `mapstructure:"image_force_delete_instances"`
|
||||
|
@ -8,31 +8,32 @@ import (
|
||||
|
||||
"github.com/hashicorp/packer/common/uuid"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type RunConfig struct {
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
|
||||
ZoneId string `mapstructure:"zone_id"`
|
||||
IOOptimized *bool `mapstructure:"io_optimized"`
|
||||
InstanceType string `mapstructure:"instance_type"`
|
||||
Description string `mapstructure:"description"`
|
||||
AlicloudSourceImage string `mapstructure:"source_image"`
|
||||
ForceStopInstance bool `mapstructure:"force_stop_instance"`
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
|
||||
SecurityGroupId string `mapstructure:"security_group_id"`
|
||||
SecurityGroupName string `mapstructure:"security_group_name"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
VpcName string `mapstructure:"vpc_name"`
|
||||
CidrBlock string `mapstructure:"vpc_cidr_block"`
|
||||
VSwitchId string `mapstructure:"vswitch_id"`
|
||||
VSwitchName string `mapstructure:"vswitch_id"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
InternetChargeType string `mapstructure:"internet_charge_type"`
|
||||
InternetMaxBandwidthOut int `mapstructure:"internet_max_bandwidth_out"`
|
||||
WaitSnapshotReadyTimeout int `mapstructure:"wait_snapshot_ready_timeout"`
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
|
||||
ZoneId string `mapstructure:"zone_id"`
|
||||
IOOptimized config.Trilean `mapstructure:"io_optimized"`
|
||||
InstanceType string `mapstructure:"instance_type"`
|
||||
Description string `mapstructure:"description"`
|
||||
AlicloudSourceImage string `mapstructure:"source_image"`
|
||||
ForceStopInstance bool `mapstructure:"force_stop_instance"`
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
|
||||
SecurityGroupId string `mapstructure:"security_group_id"`
|
||||
SecurityGroupName string `mapstructure:"security_group_name"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
VpcName string `mapstructure:"vpc_name"`
|
||||
CidrBlock string `mapstructure:"vpc_cidr_block"`
|
||||
VSwitchId string `mapstructure:"vswitch_id"`
|
||||
VSwitchName string `mapstructure:"vswitch_id"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
InternetChargeType string `mapstructure:"internet_charge_type"`
|
||||
InternetMaxBandwidthOut int `mapstructure:"internet_max_bandwidth_out"`
|
||||
WaitSnapshotReadyTimeout int `mapstructure:"wait_snapshot_ready_timeout"`
|
||||
|
||||
// Communicator settings
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
|
@ -30,7 +30,7 @@ func (s *stepCreateAlicloudImage) Run(ctx context.Context, state multistep.State
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
tempImageName := config.AlicloudImageName
|
||||
if config.ImageEncrypted != nil && *config.ImageEncrypted {
|
||||
if config.ImageEncrypted.True() {
|
||||
tempImageName = fmt.Sprintf("packer_%s", random.AlphaNum(7))
|
||||
ui.Say(fmt.Sprintf("Creating temporary image for encryption: %s", tempImageName))
|
||||
} else {
|
||||
@ -85,7 +85,7 @@ func (s *stepCreateAlicloudImage) Cleanup(state multistep.StateBag) {
|
||||
}
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
encryptedSet := config.ImageEncrypted != nil && *config.ImageEncrypted
|
||||
encryptedSet := config.ImageEncrypted.True()
|
||||
|
||||
_, cancelled := state.GetOk(multistep.StateCancelled)
|
||||
_, halted := state.GetOk(multistep.StateHalted)
|
||||
|
@ -12,12 +12,13 @@ import (
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type stepCreateAlicloudInstance struct {
|
||||
IOOptimized *bool
|
||||
IOOptimized confighelper.Trilean
|
||||
InstanceType string
|
||||
UserData string
|
||||
UserDataFile string
|
||||
@ -142,12 +143,10 @@ func (s *stepCreateAlicloudInstance) buildCreateInstanceRequest(state multistep.
|
||||
request.InternetChargeType = s.InternetChargeType
|
||||
request.InternetMaxBandwidthOut = requests.Integer(convertNumber(s.InternetMaxBandwidthOut))
|
||||
|
||||
if s.IOOptimized != nil {
|
||||
if *s.IOOptimized {
|
||||
request.IoOptimized = IOOptimizedOptimized
|
||||
} else {
|
||||
request.IoOptimized = IOOptimizedNone
|
||||
}
|
||||
if s.IOOptimized.True() {
|
||||
request.IoOptimized = IOOptimizedOptimized
|
||||
} else if s.IOOptimized.False() {
|
||||
request.IoOptimized = IOOptimizedNone
|
||||
}
|
||||
|
||||
config := state.Get("config").(*Config)
|
||||
@ -174,8 +173,8 @@ func (s *stepCreateAlicloudInstance) buildCreateInstanceRequest(state multistep.
|
||||
dataDisk.Description = imageDisk.Description
|
||||
dataDisk.DeleteWithInstance = strconv.FormatBool(imageDisk.DeleteWithInstance)
|
||||
dataDisk.Device = imageDisk.Device
|
||||
if imageDisk.Encrypted != nil {
|
||||
dataDisk.Encrypted = strconv.FormatBool(*imageDisk.Encrypted)
|
||||
if imageDisk.Encrypted != confighelper.TriUnset {
|
||||
dataDisk.Encrypted = strconv.FormatBool(imageDisk.Encrypted.True())
|
||||
}
|
||||
|
||||
dataDisks = append(dataDisks, dataDisk)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
@ -20,7 +21,7 @@ type stepRegionCopyAlicloudImage struct {
|
||||
func (s *stepRegionCopyAlicloudImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
|
||||
if config.ImageEncrypted != nil {
|
||||
if config.ImageEncrypted != confighelper.TriUnset {
|
||||
s.AlicloudImageDestinationRegions = append(s.AlicloudImageDestinationRegions, s.RegionId)
|
||||
s.AlicloudImageDestinationNames = append(s.AlicloudImageDestinationNames, config.AlicloudImageName)
|
||||
}
|
||||
@ -38,7 +39,7 @@ func (s *stepRegionCopyAlicloudImage) Run(ctx context.Context, state multistep.S
|
||||
|
||||
ui.Say(fmt.Sprintf("Coping image %s from %s...", srcImageId, s.RegionId))
|
||||
for index, destinationRegion := range s.AlicloudImageDestinationRegions {
|
||||
if destinationRegion == s.RegionId && config.ImageEncrypted == nil {
|
||||
if destinationRegion == s.RegionId && config.ImageEncrypted == confighelper.TriUnset {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -52,8 +53,8 @@ func (s *stepRegionCopyAlicloudImage) Run(ctx context.Context, state multistep.S
|
||||
copyImageRequest.ImageId = srcImageId
|
||||
copyImageRequest.DestinationRegionId = destinationRegion
|
||||
copyImageRequest.DestinationImageName = ecsImageName
|
||||
if config.ImageEncrypted != nil {
|
||||
copyImageRequest.Encrypted = requests.NewBoolean(*config.ImageEncrypted)
|
||||
if config.ImageEncrypted != confighelper.TriUnset {
|
||||
copyImageRequest.Encrypted = requests.NewBoolean(config.ImageEncrypted.True())
|
||||
}
|
||||
|
||||
imageResponse, err := client.CopyImage(copyImageRequest)
|
||||
@ -65,7 +66,7 @@ func (s *stepRegionCopyAlicloudImage) Run(ctx context.Context, state multistep.S
|
||||
ui.Message(fmt.Sprintf("Copy image from %s(%s) to %s(%s)", s.RegionId, srcImageId, destinationRegion, imageResponse.ImageId))
|
||||
}
|
||||
|
||||
if config.ImageEncrypted != nil {
|
||||
if config.ImageEncrypted != confighelper.TriUnset {
|
||||
if _, err := client.WaitForImageStatus(s.RegionId, alicloudImages[s.RegionId], ImageStatusAvailable, time.Duration(ALICLOUD_DEFAULT_LONG_TIMEOUT)*time.Second); err != nil {
|
||||
return halt(state, err, fmt.Sprintf("Timeout waiting image %s finish copying", alicloudImages[s.RegionId]))
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
@ -14,7 +15,7 @@ import (
|
||||
// StepRegisterAMI creates the AMI.
|
||||
type StepRegisterAMI struct {
|
||||
RootVolumeSize int64
|
||||
EnableAMIENASupport *bool
|
||||
EnableAMIENASupport confighelper.Trilean
|
||||
EnableAMISriovNetSupport bool
|
||||
}
|
||||
|
||||
@ -41,7 +42,7 @@ func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) mul
|
||||
// As of February 2017, this applies to C3, C4, D2, I2, R3, and M4 (excluding m4.16xlarge)
|
||||
registerOpts.SriovNetSupport = aws.String("simple")
|
||||
}
|
||||
if s.EnableAMIENASupport != nil && *s.EnableAMIENASupport {
|
||||
if s.EnableAMIENASupport.True() {
|
||||
// Set EnaSupport to true
|
||||
// As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge
|
||||
registerOpts.EnaSupport = aws.Bool(true)
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"log"
|
||||
"regexp"
|
||||
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
@ -19,11 +20,11 @@ type AMIConfig struct {
|
||||
AMIRegions []string `mapstructure:"ami_regions"`
|
||||
AMISkipRegionValidation bool `mapstructure:"skip_region_validation"`
|
||||
AMITags TagMap `mapstructure:"tags"`
|
||||
AMIENASupport *bool `mapstructure:"ena_support"`
|
||||
AMIENASupport config.Trilean `mapstructure:"ena_support"`
|
||||
AMISriovNetSupport bool `mapstructure:"sriov_support"`
|
||||
AMIForceDeregister bool `mapstructure:"force_deregister"`
|
||||
AMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot"`
|
||||
AMIEncryptBootVolume *bool `mapstructure:"encrypt_boot"`
|
||||
AMIEncryptBootVolume config.Trilean `mapstructure:"encrypt_boot"`
|
||||
AMIKmsKeyId string `mapstructure:"kms_key_id"`
|
||||
AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids"`
|
||||
SnapshotTags TagMap `mapstructure:"snapshot_tags"`
|
||||
@ -62,7 +63,7 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
|
||||
|
||||
// Prevent sharing of default KMS key encrypted volumes with other aws users
|
||||
if len(c.AMIUsers) > 0 {
|
||||
if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
|
||||
if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume.True() {
|
||||
errs = append(errs, fmt.Errorf("Cannot share AMI encrypted with default KMS key"))
|
||||
}
|
||||
if len(c.AMIRegionKMSKeyIDs) > 0 {
|
||||
@ -92,7 +93,7 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
|
||||
}
|
||||
|
||||
if len(c.SnapshotUsers) > 0 {
|
||||
if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume != nil && *c.AMIEncryptBootVolume {
|
||||
if len(c.AMIKmsKeyId) == 0 && c.AMIEncryptBootVolume.True() {
|
||||
errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
|
||||
}
|
||||
if len(c.AMIRegionKMSKeyIDs) > 0 {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
)
|
||||
|
||||
func testAMIConfig() *AMIConfig {
|
||||
@ -138,7 +139,7 @@ func TestAMIConfigPrepare_regions(t *testing.T) {
|
||||
|
||||
c.SnapshotUsers = []string{"foo", "bar"}
|
||||
c.AMIKmsKeyId = "123-abc-456"
|
||||
c.AMIEncryptBootVolume = &[]bool{true}[0]
|
||||
c.AMIEncryptBootVolume = config.TriTrue
|
||||
c.AMIRegions = []string{"us-east-1", "us-west-1"}
|
||||
c.AMIRegionKMSKeyIDs = map[string]string{
|
||||
"us-east-1": "123-456-7890",
|
||||
@ -161,7 +162,7 @@ func TestAMIConfigPrepare_regions(t *testing.T) {
|
||||
func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
|
||||
c := testAMIConfig()
|
||||
c.AMIUsers = []string{"testAccountID"}
|
||||
c.AMIEncryptBootVolume = &[]bool{true}[0]
|
||||
c.AMIEncryptBootVolume = config.TriTrue
|
||||
|
||||
accessConf := testAccessConfig()
|
||||
|
||||
@ -177,7 +178,7 @@ func TestAMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
|
||||
|
||||
func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) {
|
||||
c := testAMIConfig()
|
||||
c.AMIEncryptBootVolume = aws.Bool(true)
|
||||
c.AMIEncryptBootVolume = config.TriTrue
|
||||
|
||||
accessConf := testAccessConfig()
|
||||
|
||||
|
@ -6,21 +6,22 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
// BlockDevice
|
||||
type BlockDevice struct {
|
||||
DeleteOnTermination bool `mapstructure:"delete_on_termination"`
|
||||
DeviceName string `mapstructure:"device_name"`
|
||||
Encrypted *bool `mapstructure:"encrypted"`
|
||||
IOPS int64 `mapstructure:"iops"`
|
||||
NoDevice bool `mapstructure:"no_device"`
|
||||
SnapshotId string `mapstructure:"snapshot_id"`
|
||||
VirtualName string `mapstructure:"virtual_name"`
|
||||
VolumeType string `mapstructure:"volume_type"`
|
||||
VolumeSize int64 `mapstructure:"volume_size"`
|
||||
KmsKeyId string `mapstructure:"kms_key_id"`
|
||||
DeleteOnTermination bool `mapstructure:"delete_on_termination"`
|
||||
DeviceName string `mapstructure:"device_name"`
|
||||
Encrypted config.Trilean `mapstructure:"encrypted"`
|
||||
IOPS int64 `mapstructure:"iops"`
|
||||
NoDevice bool `mapstructure:"no_device"`
|
||||
SnapshotId string `mapstructure:"snapshot_id"`
|
||||
VirtualName string `mapstructure:"virtual_name"`
|
||||
VolumeType string `mapstructure:"volume_type"`
|
||||
VolumeSize int64 `mapstructure:"volume_size"`
|
||||
KmsKeyId string `mapstructure:"kms_key_id"`
|
||||
// ebssurrogate only
|
||||
OmitFromArtifact bool `mapstructure:"omit_from_artifact"`
|
||||
}
|
||||
@ -74,7 +75,8 @@ func buildBlockDevices(b []BlockDevice) []*ec2.BlockDeviceMapping {
|
||||
if blockDevice.SnapshotId != "" {
|
||||
ebsBlockDevice.SnapshotId = aws.String(blockDevice.SnapshotId)
|
||||
}
|
||||
ebsBlockDevice.Encrypted = blockDevice.Encrypted
|
||||
|
||||
ebsBlockDevice.Encrypted = blockDevice.Encrypted.ToBoolPointer()
|
||||
|
||||
if blockDevice.KmsKeyId != "" {
|
||||
ebsBlockDevice.KmsKeyId = aws.String(blockDevice.KmsKeyId)
|
||||
@ -93,8 +95,9 @@ func (b *BlockDevice) Prepare(ctx *interpolate.Context) error {
|
||||
return fmt.Errorf("The `device_name` must be specified " +
|
||||
"for every device in the block device mapping.")
|
||||
}
|
||||
|
||||
// Warn that encrypted must be true or nil when setting kms_key_id
|
||||
if b.KmsKeyId != "" && b.Encrypted != nil && *b.Encrypted == false {
|
||||
if b.KmsKeyId != "" && b.Encrypted.False() {
|
||||
return fmt.Errorf("The device %v, must also have `encrypted: "+
|
||||
"true` when setting a kms_key_id.", b.DeviceName)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
)
|
||||
|
||||
func TestBlockDevice(t *testing.T) {
|
||||
@ -71,7 +72,7 @@ func TestBlockDevice(t *testing.T) {
|
||||
VolumeType: "gp2",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
Encrypted: aws.Bool(true),
|
||||
Encrypted: config.TriTrue,
|
||||
},
|
||||
|
||||
Result: &ec2.BlockDeviceMapping{
|
||||
@ -90,7 +91,7 @@ func TestBlockDevice(t *testing.T) {
|
||||
VolumeType: "gp2",
|
||||
VolumeSize: 8,
|
||||
DeleteOnTermination: true,
|
||||
Encrypted: aws.Bool(true),
|
||||
Encrypted: config.TriTrue,
|
||||
KmsKeyId: "2Fa48a521f-3aff-4b34-a159-376ac5d37812",
|
||||
},
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
@ -17,7 +18,7 @@ type StepAMIRegionCopy struct {
|
||||
Regions []string
|
||||
AMIKmsKeyId string
|
||||
RegionKeyIds map[string]string
|
||||
EncryptBootVolume *bool // nil means preserve
|
||||
EncryptBootVolume config.Trilean // nil means preserve
|
||||
Name string
|
||||
OriginalRegion string
|
||||
|
||||
@ -74,7 +75,7 @@ func (s *StepAMIRegionCopy) Run(ctx context.Context, state multistep.StateBag) m
|
||||
s.toDelete = ami
|
||||
}
|
||||
|
||||
if s.EncryptBootVolume != nil && *s.EncryptBootVolume {
|
||||
if s.EncryptBootVolume.True() {
|
||||
// encrypt_boot is true, so we have to copy the temporary
|
||||
// AMI with required encryption setting.
|
||||
// temp image was created by stepCreateAMI.
|
||||
@ -102,7 +103,7 @@ func (s *StepAMIRegionCopy) Run(ctx context.Context, state multistep.StateBag) m
|
||||
var regKeyID string
|
||||
ui.Message(fmt.Sprintf("Copying to: %s", region))
|
||||
|
||||
if s.EncryptBootVolume != nil && *s.EncryptBootVolume {
|
||||
if s.EncryptBootVolume.True() {
|
||||
// Encrypt is true, explicitly
|
||||
regKeyID = s.RegionKeyIds[region]
|
||||
} else {
|
||||
@ -112,7 +113,9 @@ func (s *StepAMIRegionCopy) Run(ctx context.Context, state multistep.StateBag) m
|
||||
|
||||
go func(region string) {
|
||||
defer wg.Done()
|
||||
id, snapshotIds, err := s.amiRegionCopy(ctx, state, s.AccessConfig, s.Name, ami, region, s.OriginalRegion, regKeyID, s.EncryptBootVolume)
|
||||
id, snapshotIds, err := s.amiRegionCopy(ctx, state, s.AccessConfig,
|
||||
s.Name, ami, region, s.OriginalRegion, regKeyID,
|
||||
s.EncryptBootVolume.ToBoolPointer())
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
amis[region] = id
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
@ -109,7 +110,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
|
||||
AMIKmsKeyId: "12345",
|
||||
// Original region key in regionkeyids is different than in amikmskeyid
|
||||
RegionKeyIds: map[string]string{"us-east-1": "12345"},
|
||||
EncryptBootVolume: aws.Bool(true),
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
@ -153,7 +154,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
|
||||
stepAMIRegionCopy = StepAMIRegionCopy{
|
||||
AccessConfig: testAccessConfig(),
|
||||
Regions: []string{"us-east-1"},
|
||||
EncryptBootVolume: aws.Bool(false),
|
||||
EncryptBootVolume: config.TriFalse,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
@ -179,7 +180,7 @@ func TestStepAMIRegionCopy_duplicates(t *testing.T) {
|
||||
AMIKmsKeyId: "IlikePancakes",
|
||||
// Original region key in regionkeyids is different than in amikmskeyid
|
||||
RegionKeyIds: map[string]string{"us-east-1": "12345", "us-west-2": "abcde", "ap-east-1": "xyz"},
|
||||
EncryptBootVolume: aws.Bool(true),
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
@ -226,7 +227,7 @@ func TestStepAmiRegionCopy_nil_encryption(t *testing.T) {
|
||||
Regions: make([]string, 0),
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: make(map[string]string),
|
||||
EncryptBootVolume: nil,
|
||||
EncryptBootVolume: config.TriUnset,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
@ -252,7 +253,7 @@ func TestStepAmiRegionCopy_true_encryption(t *testing.T) {
|
||||
Regions: make([]string, 0),
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: make(map[string]string),
|
||||
EncryptBootVolume: aws.Bool(true),
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
@ -278,7 +279,7 @@ func TestStepAmiRegionCopy_nil_intermediary(t *testing.T) {
|
||||
Regions: make([]string, 0),
|
||||
AMIKmsKeyId: "",
|
||||
RegionKeyIds: make(map[string]string),
|
||||
EncryptBootVolume: aws.Bool(false),
|
||||
EncryptBootVolume: config.TriFalse,
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
}
|
||||
@ -360,7 +361,7 @@ func TestStepAmiRegionCopy_AMISkipBuildRegion(t *testing.T) {
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
AMISkipBuildRegion: false,
|
||||
EncryptBootVolume: aws.Bool(true),
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
@ -386,7 +387,7 @@ func TestStepAmiRegionCopy_AMISkipBuildRegion(t *testing.T) {
|
||||
Name: "fake-ami-name",
|
||||
OriginalRegion: "us-east-1",
|
||||
AMISkipBuildRegion: true,
|
||||
EncryptBootVolume: aws.Bool(true),
|
||||
EncryptBootVolume: config.TriTrue,
|
||||
}
|
||||
// mock out the region connection code
|
||||
stepAMIRegionCopy.getRegionConn = getMockConn
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer/common/retry"
|
||||
commonhelper "github.com/hashicorp/packer/helper/common"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
@ -45,14 +46,13 @@ func (s *StepGetPassword) Run(ctx context.Context, state multistep.StateBag) mul
|
||||
// Get the password
|
||||
var password string
|
||||
var err error
|
||||
cancel := make(chan struct{})
|
||||
waitDone := make(chan bool, 1)
|
||||
go func() {
|
||||
ui.Say("Waiting for auto-generated password for instance...")
|
||||
ui.Message(
|
||||
"It is normal for this process to take up to 15 minutes,\n" +
|
||||
"but it usually takes around 5. Please wait.")
|
||||
password, err = s.waitForPassword(state, cancel)
|
||||
password, err = s.waitForPassword(ctx, state)
|
||||
waitDone <- true
|
||||
}()
|
||||
|
||||
@ -76,16 +76,12 @@ WaitLoop:
|
||||
err := fmt.Errorf("Timeout waiting for password.")
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
close(cancel)
|
||||
return multistep.ActionHalt
|
||||
case <-time.After(1 * time.Second):
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
// The step sequence was cancelled, so cancel waiting for password
|
||||
// and just start the halting process.
|
||||
close(cancel)
|
||||
log.Println("[WARN] Interrupt detected, quitting waiting for password.")
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
case <-ctx.Done():
|
||||
// The step sequence was cancelled, so cancel waiting for password
|
||||
// and just start the halting process.
|
||||
log.Println("[WARN] Interrupt detected, quitting waiting for password.")
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,24 +102,38 @@ func (s *StepGetPassword) Cleanup(multistep.StateBag) {
|
||||
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
|
||||
}
|
||||
|
||||
func (s *StepGetPassword) waitForPassword(state multistep.StateBag, cancel <-chan struct{}) (string, error) {
|
||||
func (s *StepGetPassword) waitForPassword(ctx context.Context, state multistep.StateBag) (string, error) {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
privateKey := s.Comm.SSHPrivateKey
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-cancel:
|
||||
case <-ctx.Done():
|
||||
log.Println("[INFO] Retrieve password wait cancelled. Exiting loop.")
|
||||
return "", errors.New("Retrieve password wait cancelled")
|
||||
case <-time.After(5 * time.Second):
|
||||
}
|
||||
|
||||
resp, err := ec2conn.GetPasswordData(&ec2.GetPasswordDataInput{
|
||||
InstanceId: instance.InstanceId,
|
||||
// Wrap in a retry so that we don't fail on rate-limiting.
|
||||
log.Printf("Retrieving auto-generated instance password...")
|
||||
var resp *ec2.GetPasswordDataOutput
|
||||
err := retry.Config{
|
||||
Tries: 11,
|
||||
RetryDelay: (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 30 * time.Second, Multiplier: 2}).Linear,
|
||||
}.Run(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
resp, err = ec2conn.GetPasswordData(&ec2.GetPasswordDataInput{
|
||||
InstanceId: instance.InstanceId,
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error retrieving auto-generated instance password: %s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error retrieving auto-generated instance password: %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
@ -5,19 +5,20 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type StepModifyEBSBackedInstance struct {
|
||||
EnableAMIENASupport *bool
|
||||
EnableAMIENASupport confighelper.Trilean
|
||||
EnableAMISriovNetSupport bool
|
||||
}
|
||||
|
||||
func (s *StepModifyEBSBackedInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ec2conn := state.Get("ec2").(ec2iface.EC2API)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
@ -40,9 +41,9 @@ func (s *StepModifyEBSBackedInstance) Run(ctx context.Context, state multistep.S
|
||||
|
||||
// Handle EnaSupport flag.
|
||||
// As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge
|
||||
if s.EnableAMIENASupport != nil {
|
||||
if s.EnableAMIENASupport != confighelper.TriUnset {
|
||||
var prefix string
|
||||
if *s.EnableAMIENASupport {
|
||||
if s.EnableAMIENASupport.True() {
|
||||
prefix = "En"
|
||||
} else {
|
||||
prefix = "Dis"
|
||||
@ -50,7 +51,7 @@ func (s *StepModifyEBSBackedInstance) Run(ctx context.Context, state multistep.S
|
||||
ui.Say(fmt.Sprintf("%sabling Enhanced Networking (ENA)...", prefix))
|
||||
_, err := ec2conn.ModifyInstanceAttribute(&ec2.ModifyInstanceAttributeInput{
|
||||
InstanceId: instance.InstanceId,
|
||||
EnaSupport: &ec2.AttributeBooleanValue{Value: aws.Bool(*s.EnableAMIENASupport)},
|
||||
EnaSupport: &ec2.AttributeBooleanValue{Value: s.EnableAMIENASupport.ToBoolPointer()},
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error %sabling Enhanced Networking (ENA) on %s: %s", strings.ToLower(prefix), *instance.InstanceId, err)
|
||||
|
105
builder/amazon/common/step_modify_ebs_instance_test.go
Normal file
105
builder/amazon/common/step_modify_ebs_instance_test.go
Normal file
@ -0,0 +1,105 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
|
||||
helperconfig "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
// Define a mock struct to be used in unit tests for common aws steps.
|
||||
type mockEC2Conn_ModifyEBS struct {
|
||||
ec2iface.EC2API
|
||||
Config *aws.Config
|
||||
|
||||
// Counters to figure out what code path was taken
|
||||
shouldError bool
|
||||
modifyImageAttrCount int
|
||||
}
|
||||
|
||||
func (m *mockEC2Conn_ModifyEBS) ModifyInstanceAttribute(modifyInput *ec2.ModifyInstanceAttributeInput) (*ec2.ModifyInstanceAttributeOutput, error) {
|
||||
m.modifyImageAttrCount++
|
||||
// don't need to define output since we always discard it anyway.
|
||||
output := &ec2.ModifyInstanceAttributeOutput{}
|
||||
if m.shouldError {
|
||||
return output, fmt.Errorf("fake ModifyInstanceAttribute error")
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// Create statebag for running test
|
||||
func fakeModifyEBSBackedInstanceState() multistep.StateBag {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packer.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
state.Put("instance", "i-12345")
|
||||
return state
|
||||
}
|
||||
|
||||
func StepModifyEBSBackedInstance_EnableAMIENASupport(t *testing.T) {
|
||||
// Value is unset, so we shouldn't modify
|
||||
stepModifyEBSBackedInstance := StepModifyEBSBackedInstance{
|
||||
EnableAMIENASupport: helperconfig.TriUnset,
|
||||
EnableAMISriovNetSupport: false,
|
||||
}
|
||||
|
||||
// mock out the region connection code
|
||||
mockConn := &mockEC2Conn_ModifyEBS{
|
||||
Config: aws.NewConfig(),
|
||||
}
|
||||
|
||||
state := fakeModifyEBSBackedInstanceState()
|
||||
state.Put("ec2", mockConn)
|
||||
stepModifyEBSBackedInstance.Run(context.Background(), state)
|
||||
|
||||
if mockConn.modifyImageAttrCount > 0 {
|
||||
t.Fatalf("Should not have modified image since EnableAMIENASupport is unset")
|
||||
}
|
||||
|
||||
// Value is true, so we should modify
|
||||
stepModifyEBSBackedInstance = StepModifyEBSBackedInstance{
|
||||
EnableAMIENASupport: helperconfig.TriTrue,
|
||||
EnableAMISriovNetSupport: false,
|
||||
}
|
||||
|
||||
// mock out the region connection code
|
||||
mockConn = &mockEC2Conn_ModifyEBS{
|
||||
Config: aws.NewConfig(),
|
||||
}
|
||||
|
||||
state = fakeModifyEBSBackedInstanceState()
|
||||
state.Put("ec2", mockConn)
|
||||
stepModifyEBSBackedInstance.Run(context.Background(), state)
|
||||
|
||||
if mockConn.modifyImageAttrCount != 1 {
|
||||
t.Fatalf("Should have modified image, since EnableAMIENASupport is true")
|
||||
}
|
||||
|
||||
// Value is false, so we should modify
|
||||
stepModifyEBSBackedInstance = StepModifyEBSBackedInstance{
|
||||
EnableAMIENASupport: helperconfig.TriFalse,
|
||||
EnableAMISriovNetSupport: false,
|
||||
}
|
||||
|
||||
// mock out the region connection code
|
||||
mockConn = &mockEC2Conn_ModifyEBS{
|
||||
Config: aws.NewConfig(),
|
||||
}
|
||||
|
||||
state = fakeModifyEBSBackedInstanceState()
|
||||
state.Put("ec2", mockConn)
|
||||
stepModifyEBSBackedInstance.Run(context.Background(), state)
|
||||
|
||||
if mockConn.modifyImageAttrCount != 1 {
|
||||
t.Fatalf("Should have modified image, since EnableAMIENASupport is true")
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
@ -20,7 +21,7 @@ import (
|
||||
type StepSourceAMIInfo struct {
|
||||
SourceAmi string
|
||||
EnableAMISriovNetSupport bool
|
||||
EnableAMIENASupport *bool
|
||||
EnableAMIENASupport confighelper.Trilean
|
||||
AMIVirtType string
|
||||
AmiFilters AmiFilterOptions
|
||||
}
|
||||
@ -94,7 +95,7 @@ func (s *StepSourceAMIInfo) Run(ctx context.Context, state multistep.StateBag) m
|
||||
|
||||
// Enhanced Networking can only be enabled on HVM AMIs.
|
||||
// See http://goo.gl/icuXh5
|
||||
if (s.EnableAMIENASupport != nil && *s.EnableAMIENASupport) || s.EnableAMISriovNetSupport {
|
||||
if s.EnableAMIENASupport.True() || s.EnableAMISriovNetSupport {
|
||||
err = s.canEnableEnhancedNetworking(image)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
|
@ -72,7 +72,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
|
||||
|
||||
if b.config.IsSpotInstance() && ((b.config.AMIENASupport != nil && *b.config.AMIENASupport) || b.config.AMISriovNetSupport) {
|
||||
if b.config.IsSpotInstance() && (b.config.AMIENASupport.True() || b.config.AMISriovNetSupport) {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Spot instances do not support modification, which is required "+
|
||||
"when either `ena_support` or `sriov_support` are set. Please ensure "+
|
||||
|
@ -27,7 +27,7 @@ func (s *stepCreateAMI) Run(ctx context.Context, state multistep.StateBag) multi
|
||||
// Create the image
|
||||
amiName := config.AMIName
|
||||
state.Put("intermediary_image", false)
|
||||
if config.AMIEncryptBootVolume != nil && *config.AMIEncryptBootVolume != false || s.AMISkipBuildRegion {
|
||||
if config.AMIEncryptBootVolume.True() || s.AMISkipBuildRegion {
|
||||
state.Put("intermediary_image", true)
|
||||
|
||||
// From AWS SDK docs: You can encrypt a copy of an unencrypted snapshot,
|
||||
|
@ -90,7 +90,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("no volume with name '%s' is found", b.config.RootDevice.SourceDeviceName))
|
||||
}
|
||||
|
||||
if b.config.IsSpotInstance() && ((b.config.AMIENASupport != nil && *b.config.AMIENASupport) || b.config.AMISriovNetSupport) {
|
||||
if b.config.IsSpotInstance() && (b.config.AMIENASupport.True() || b.config.AMISriovNetSupport) {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Spot instances do not support modification, which is required "+
|
||||
"when either `ena_support` or `sriov_support` are set. Please ensure "+
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
@ -16,7 +17,7 @@ type StepRegisterAMI struct {
|
||||
RootDevice RootBlockDevice
|
||||
AMIDevices []*ec2.BlockDeviceMapping
|
||||
LaunchDevices []*ec2.BlockDeviceMapping
|
||||
EnableAMIENASupport *bool
|
||||
EnableAMIENASupport confighelper.Trilean
|
||||
EnableAMISriovNetSupport bool
|
||||
Architecture string
|
||||
image *ec2.Image
|
||||
@ -46,7 +47,7 @@ func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) mul
|
||||
// As of February 2017, this applies to C3, C4, D2, I2, R3, and M4 (excluding m4.16xlarge)
|
||||
registerOpts.SriovNetSupport = aws.String("simple")
|
||||
}
|
||||
if s.EnableAMIENASupport != nil && *s.EnableAMIENASupport {
|
||||
if s.EnableAMIENASupport.True() {
|
||||
// Set EnaSupport to true
|
||||
// As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge
|
||||
registerOpts.EnaSupport = aws.Bool(true)
|
||||
|
@ -23,9 +23,10 @@ type Config struct {
|
||||
awscommon.AccessConfig `mapstructure:",squash"`
|
||||
awscommon.RunConfig `mapstructure:",squash"`
|
||||
|
||||
VolumeMappings []BlockDevice `mapstructure:"ebs_volumes"`
|
||||
AMIENASupport *bool `mapstructure:"ena_support"`
|
||||
AMISriovNetSupport bool `mapstructure:"sriov_support"`
|
||||
AMIENASupport config.Trilean `mapstructure:"ena_support"`
|
||||
AMISriovNetSupport bool `mapstructure:"sriov_support"`
|
||||
VolumeMappings []BlockDevice `mapstructure:"ebs_volumes"`
|
||||
VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"`
|
||||
|
||||
launchBlockDevices awscommon.BlockDevices
|
||||
ctx interpolate.Context
|
||||
@ -75,7 +76,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
|
||||
if b.config.IsSpotInstance() && ((b.config.AMIENASupport != nil && *b.config.AMIENASupport) || b.config.AMISriovNetSupport) {
|
||||
if b.config.IsSpotInstance() && ((b.config.AMIENASupport.True()) || b.config.AMISriovNetSupport) {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Spot instances do not support modification, which is required "+
|
||||
"when either `ena_support` or `sriov_support` are set. Please ensure "+
|
||||
@ -120,8 +121,8 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
||||
BlockDevices: b.config.launchBlockDevices,
|
||||
BlockDurationMinutes: b.config.BlockDurationMinutes,
|
||||
Ctx: b.config.ctx,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
EbsOptimized: b.config.EbsOptimized,
|
||||
ExpectedRootDevice: "ebs",
|
||||
@ -129,12 +130,13 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
|
||||
InstanceType: b.config.InstanceType,
|
||||
SourceAMI: b.config.SourceAmi,
|
||||
SpotPrice: b.config.SpotPrice,
|
||||
SpotInstanceTypes: b.config.SpotInstanceTypes,
|
||||
SpotPrice: b.config.SpotPrice,
|
||||
SpotTags: b.config.SpotTags,
|
||||
Tags: b.config.RunTags,
|
||||
UserData: b.config.UserData,
|
||||
UserDataFile: b.config.UserDataFile,
|
||||
VolumeTags: b.config.VolumeRunTags,
|
||||
}
|
||||
} else {
|
||||
instanceStep = &awscommon.StepRunSourceInstance{
|
||||
@ -154,6 +156,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
Tags: b.config.RunTags,
|
||||
UserData: b.config.UserData,
|
||||
UserDataFile: b.config.UserDataFile,
|
||||
VolumeTags: b.config.VolumeRunTags,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,9 @@ package ebsvolume
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
@ -19,6 +21,7 @@ func (s *stepTagEBSVolumes) Run(ctx context.Context, state multistep.StateBag) m
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
config := state.Get("config").(*Config)
|
||||
|
||||
volumes := make(EbsVolumes)
|
||||
for _, instanceBlockDevices := range instance.BlockDeviceMappings {
|
||||
@ -36,8 +39,50 @@ func (s *stepTagEBSVolumes) Run(ctx context.Context, state multistep.StateBag) m
|
||||
state.Put("ebsvolumes", volumes)
|
||||
|
||||
if len(s.VolumeMapping) > 0 {
|
||||
ui.Say("Tagging EBS volumes...")
|
||||
// If run_volume_tags were set in the template any attached EBS
|
||||
// volume will have had these tags applied when the instance was
|
||||
// created. We now need to remove these tags to ensure only the EBS
|
||||
// volume tags are applied (if any)
|
||||
if config.VolumeRunTags.IsSet() {
|
||||
ui.Say("Removing any tags applied to EBS volumes when the source instance was created...")
|
||||
|
||||
ui.Message("Compiling list of existing tags to remove...")
|
||||
existingTags, err := config.VolumeRunTags.EC2Tags(s.Ctx, *ec2conn.Config.Region, state)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error generating list of tags to remove: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
existingTags.Report(ui)
|
||||
|
||||
// Generate the list of volumes with tags to delete.
|
||||
// Looping over the instance block device mappings allows us to
|
||||
// obtain the volumeId
|
||||
volumeIds := []string{}
|
||||
for _, mapping := range s.VolumeMapping {
|
||||
for _, v := range instance.BlockDeviceMappings {
|
||||
if *v.DeviceName == mapping.DeviceName {
|
||||
volumeIds = append(volumeIds, *v.Ebs.VolumeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the tags
|
||||
ui.Message(fmt.Sprintf("Deleting 'run_volume_tags' on EBS Volumes: %s", strings.Join(volumeIds, ", ")))
|
||||
_, err = ec2conn.DeleteTags(&ec2.DeleteTagsInput{
|
||||
Resources: aws.StringSlice(volumeIds),
|
||||
Tags: existingTags,
|
||||
})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error deleting tags on EBS Volumes %s: %s", strings.Join(volumeIds, ", "), err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("Tagging EBS volumes...")
|
||||
toTag := map[string][]*ec2.Tag{}
|
||||
for _, mapping := range s.VolumeMapping {
|
||||
if len(mapping.Tags) == 0 {
|
||||
@ -45,15 +90,19 @@ func (s *stepTagEBSVolumes) Run(ctx context.Context, state multistep.StateBag) m
|
||||
continue
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Compiling list of tags to apply to volume on %s...", mapping.DeviceName))
|
||||
tags, err := mapping.Tags.EC2Tags(s.Ctx, *ec2conn.Config.Region, state)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error tagging device %s with %s", mapping.DeviceName, err)
|
||||
err := fmt.Errorf("Error generating tags for device %s: %s", mapping.DeviceName, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
tags.Report(ui)
|
||||
|
||||
// Generate the map of volumes and associated tags to apply.
|
||||
// Looping over the instance block device mappings allows us to
|
||||
// obtain the volumeId
|
||||
for _, v := range instance.BlockDeviceMappings {
|
||||
if *v.DeviceName == mapping.DeviceName {
|
||||
toTag[*v.Ebs.VolumeId] = tags
|
||||
@ -61,9 +110,11 @@ func (s *stepTagEBSVolumes) Run(ctx context.Context, state multistep.StateBag) m
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the tags
|
||||
for volumeId, tags := range toTag {
|
||||
ui.Message(fmt.Sprintf("Applying tags to EBS Volume: %s", volumeId))
|
||||
_, err := ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
Resources: []*string{&volumeId},
|
||||
Resources: aws.StringSlice([]string{volumeId}),
|
||||
Tags: tags,
|
||||
})
|
||||
if err != nil {
|
||||
@ -72,7 +123,6 @@ func (s *stepTagEBSVolumes) Run(ctx context.Context, state multistep.StateBag) m
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
errs, fmt.Errorf("x509_key_path points to bad file: %s", err))
|
||||
}
|
||||
|
||||
if b.config.IsSpotInstance() && ((b.config.AMIENASupport != nil && *b.config.AMIENASupport) || b.config.AMISriovNetSupport) {
|
||||
if b.config.IsSpotInstance() && ((b.config.AMIENASupport.True()) || b.config.AMISriovNetSupport) {
|
||||
errs = packer.MultiErrorAppend(errs,
|
||||
fmt.Errorf("Spot instances do not support modification, which is required "+
|
||||
"when either `ena_support` or `sriov_support` are set. Please ensure "+
|
||||
|
@ -7,12 +7,13 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
confighelper "github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type StepRegisterAMI struct {
|
||||
EnableAMIENASupport *bool
|
||||
EnableAMIENASupport confighelper.Trilean
|
||||
EnableAMISriovNetSupport bool
|
||||
}
|
||||
|
||||
@ -38,7 +39,7 @@ func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) mul
|
||||
// As of February 2017, this applies to C3, C4, D2, I2, R3, and M4 (excluding m4.16xlarge)
|
||||
registerOpts.SriovNetSupport = aws.String("simple")
|
||||
}
|
||||
if s.EnableAMIENASupport != nil && *s.EnableAMIENASupport {
|
||||
if s.EnableAMIENASupport.True() {
|
||||
// Set EnaSupport to true
|
||||
// As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge
|
||||
registerOpts.EnaSupport = aws.Bool(true)
|
||||
|
@ -439,8 +439,9 @@ func getObjectIdFromToken(ui packer.Ui, token *adal.ServicePrincipalToken) strin
|
||||
ui.Error(fmt.Sprintf("Failed to parse the token,Error: %s", err.Error()))
|
||||
return ""
|
||||
}
|
||||
return claims["oid"].(string)
|
||||
|
||||
oid, _ := claims["oid"].(string)
|
||||
return oid
|
||||
}
|
||||
|
||||
func normalizeAzureRegion(name string) string {
|
||||
|
@ -393,6 +393,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&common.StepHTTPServer{
|
||||
HTTPDir: b.config.HTTPDir,
|
||||
|
@ -432,6 +432,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&common.StepHTTPServer{
|
||||
HTTPDir: b.config.HTTPDir,
|
||||
|
@ -40,6 +40,12 @@ func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag)
|
||||
}
|
||||
|
||||
client, err := config.imageV2Client()
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error creating image client: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if s.SourceImageName != "" {
|
||||
s.SourceImageOpts = images.ListOpts{
|
||||
|
@ -25,15 +25,6 @@ type OMIConfig struct {
|
||||
SnapshotGroups []string `mapstructure:"snapshot_groups"`
|
||||
}
|
||||
|
||||
func stringInSlice(s []string, searchstr string) bool {
|
||||
for _, item := range s {
|
||||
if item == searchstr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *OMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context) []error {
|
||||
var errs []error
|
||||
|
||||
|
@ -3,6 +3,7 @@ package common
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
@ -27,35 +28,42 @@ func SSHHost(e oapiDescriber, sshInterface string) func(multistep.StateBag) (str
|
||||
for j := 0; j <= tries; j++ {
|
||||
var host string
|
||||
i := state.Get("vm").(oapi.Vm)
|
||||
|
||||
if len(i.Nics) <= 0 {
|
||||
return "", errors.New("couldn't determine address for vm, nics are empty")
|
||||
}
|
||||
|
||||
nic := i.Nics[0]
|
||||
|
||||
if sshInterface != "" {
|
||||
switch sshInterface {
|
||||
case "public_ip":
|
||||
if i.PublicIp != "" {
|
||||
host = i.PublicIp
|
||||
}
|
||||
case "private_ip":
|
||||
if i.PrivateIp != "" {
|
||||
host = i.PrivateIp
|
||||
if nic.LinkPublicIp.PublicIp != "" {
|
||||
host = nic.LinkPublicIp.PublicIp
|
||||
}
|
||||
case "public_dns":
|
||||
if i.PublicDnsName != "" {
|
||||
host = i.PublicDnsName
|
||||
if nic.LinkPublicIp.PublicDnsName != "" {
|
||||
host = nic.LinkPublicIp.PublicDnsName
|
||||
}
|
||||
case "private_ip":
|
||||
if privateIP, err := getPrivateIP(nic); err != nil {
|
||||
host = privateIP.PrivateIp
|
||||
}
|
||||
case "private_dns":
|
||||
if i.PrivateDnsName != "" {
|
||||
host = i.PrivateDnsName
|
||||
if privateIP, err := getPrivateIP(nic); err != nil {
|
||||
host = privateIP.PrivateDnsName
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown interface type: %s", sshInterface))
|
||||
}
|
||||
} else if i.NetId != "" {
|
||||
if i.PublicIp != "" {
|
||||
host = i.PublicIp
|
||||
} else if i.PrivateIp != "" {
|
||||
host = i.PrivateIp
|
||||
if nic.LinkPublicIp.PublicIp != "" {
|
||||
host = nic.LinkPublicIp.PublicIp
|
||||
} else if privateIP, err := getPrivateIP(nic); err != nil {
|
||||
host = privateIP.PrivateIp
|
||||
}
|
||||
} else if i.PublicDnsName != "" {
|
||||
host = i.PublicDnsName
|
||||
} else if nic.LinkPublicIp.PublicDnsName != "" {
|
||||
host = nic.LinkPublicIp.PublicDnsName
|
||||
}
|
||||
|
||||
if host != "" {
|
||||
@ -82,3 +90,20 @@ func SSHHost(e oapiDescriber, sshInterface string) func(multistep.StateBag) (str
|
||||
return "", errors.New("couldn't determine address for vm")
|
||||
}
|
||||
}
|
||||
|
||||
func getPrivateIP(nic oapi.NicLight) (oapi.PrivateIpLightForVm, error) {
|
||||
isPrimary := true
|
||||
|
||||
i := sort.Search(len(nic.PrivateIps), func(i int) bool { return nic.PrivateIps[i].IsPrimary == isPrimary })
|
||||
|
||||
if i < len(nic.PrivateIps) && nic.PrivateIps[i].IsPrimary == isPrimary {
|
||||
return nic.PrivateIps[i], nil
|
||||
}
|
||||
|
||||
if len(nic.PrivateIps) > 0 {
|
||||
return nic.PrivateIps[0], nil
|
||||
}
|
||||
|
||||
return oapi.PrivateIpLightForVm{}, fmt.Errorf("couldn't determine private address for vm")
|
||||
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ func (s *StepRunSourceVm) Run(ctx context.Context, state multistep.StateBag) mul
|
||||
}
|
||||
|
||||
if vm.PrivateIp != "" {
|
||||
ui.Message(fmt.Sprintf("Private IP: %s", vm.PublicIp))
|
||||
ui.Message(fmt.Sprintf("Private IP: %s", vm.PrivateIp))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&common.StepHTTPServer{
|
||||
HTTPDir: b.config.HTTPDir,
|
||||
|
@ -61,6 +61,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&StepImport{
|
||||
Name: b.config.VMName,
|
||||
|
@ -102,13 +102,10 @@ func (p *proxmoxDriver) SendSpecial(special string, action bootcommand.KeyAction
|
||||
}
|
||||
|
||||
func (p *proxmoxDriver) send(keys string) error {
|
||||
res, err := p.client.MonitorCmd(p.vmRef, "sendkey "+keys)
|
||||
err := p.client.Sendkey(p.vmRef, keys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if data, ok := res["data"].(string); ok && len(data) > 0 {
|
||||
return fmt.Errorf("failed to send keys: %s", data)
|
||||
}
|
||||
|
||||
time.Sleep(p.interval)
|
||||
return nil
|
||||
|
@ -3,6 +3,7 @@ package proxmox
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/Telmate/proxmox-api-go/proxmox"
|
||||
@ -45,7 +46,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = b.proxmoxClient.Login(b.config.Username, b.config.Password)
|
||||
err = b.proxmoxClient.Login(b.config.Username, b.config.Password, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -89,9 +90,19 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
if rawErr, ok := state.GetOk("error"); ok {
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
// If we were interrupted or cancelled, then just exit.
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return nil, errors.New("build was cancelled")
|
||||
}
|
||||
|
||||
// Verify that the template_id was set properly, otherwise we didn't progress through the last step
|
||||
tplID, ok := state.Get("template_id").(int)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("template ID could not be determined")
|
||||
}
|
||||
|
||||
artifact := &Artifact{
|
||||
templateID: state.Get("template_id").(int),
|
||||
templateID: tplID,
|
||||
proxmoxClient: b.proxmoxClient,
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
c.RawBootKeyInterval = os.Getenv(common.PackerKeyEnv)
|
||||
}
|
||||
if c.RawBootKeyInterval == "" {
|
||||
c.BootKeyInterval = common.PackerKeyDefault
|
||||
c.BootKeyInterval = 5 * time.Millisecond
|
||||
} else {
|
||||
if interval, err := time.ParseDuration(c.RawBootKeyInterval); err == nil {
|
||||
c.BootKeyInterval = interval
|
||||
@ -151,6 +151,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
log.Printf("Disk %d cache mode not set, using default 'none'", idx)
|
||||
c.Disks[idx].CacheMode = "none"
|
||||
}
|
||||
// For any storage pool types which aren't in rxStorageTypes in proxmox-api/proxmox/config_qemu.go:651
|
||||
// (currently zfspool and lvm), the format parameter is mandatory. Make sure this is still up to date
|
||||
// when updating the vendored code!
|
||||
if !contains([]string{"zfspool", "lvm"}, c.Disks[idx].StoragePoolType) && c.Disks[idx].DiskFormat == "" {
|
||||
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("disk format must be specified for pool type %q", c.Disks[idx].StoragePoolType)))
|
||||
}
|
||||
}
|
||||
|
||||
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
|
||||
@ -197,3 +203,12 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
packer.LogSecretFilter.Set(c.Password)
|
||||
return c, nil, nil
|
||||
}
|
||||
|
||||
func contains(haystack []string, needle string) bool {
|
||||
for _, candidate := range haystack {
|
||||
if candidate == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package proxmox
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Telmate/proxmox-api-go/proxmox"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
@ -44,7 +45,7 @@ func (s *stepConvertToTemplate) Run(ctx context.Context, state multistep.StateBa
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
log.Printf("template_id: %d", vmRef.VmId())
|
||||
state.Put("template_id", vmRef.VmId())
|
||||
|
||||
return multistep.ActionContinue
|
||||
|
@ -30,6 +30,8 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist
|
||||
config := proxmox.ConfigQemu{
|
||||
Name: c.VMName,
|
||||
Agent: agent,
|
||||
Boot: "cdn", // Boot priority, c:CDROM -> d:Disk -> n:Network
|
||||
QemuCpu: "host",
|
||||
Description: "Packer ephemeral build VM",
|
||||
Memory: c.Memory,
|
||||
QemuCores: c.Cores,
|
||||
@ -142,7 +144,7 @@ func (s *stepStartVM) Cleanup(state multistep.StateBag) {
|
||||
ui.Say("Stopping VM")
|
||||
_, err := client.StopVm(vmRef)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error stop VM. Please stop and delete it manually: %s", err))
|
||||
ui.Error(fmt.Sprintf("Error stopping VM. Please stop and delete it manually: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ type bootCommandTemplateData struct {
|
||||
}
|
||||
|
||||
type commandTyper interface {
|
||||
MonitorCmd(*proxmox.VmRef, string) (map[string]interface{}, error)
|
||||
Sendkey(*proxmox.VmRef, string) error
|
||||
}
|
||||
|
||||
var _ commandTyper = &proxmox.Client{}
|
||||
|
@ -13,75 +13,74 @@ import (
|
||||
)
|
||||
|
||||
type commandTyperMock struct {
|
||||
monitorCmd func(*proxmox.VmRef, string) (map[string]interface{}, error)
|
||||
sendkey func(*proxmox.VmRef, string) error
|
||||
}
|
||||
|
||||
func (m commandTyperMock) MonitorCmd(ref *proxmox.VmRef, cmd string) (map[string]interface{}, error) {
|
||||
return m.monitorCmd(ref, cmd)
|
||||
func (m commandTyperMock) Sendkey(ref *proxmox.VmRef, cmd string) error {
|
||||
return m.sendkey(ref, cmd)
|
||||
}
|
||||
|
||||
var _ commandTyper = commandTyperMock{}
|
||||
|
||||
func TestTypeBootCommand(t *testing.T) {
|
||||
cs := []struct {
|
||||
name string
|
||||
builderConfig *Config
|
||||
expectCallMonitorCmd bool
|
||||
monitorCmdErr error
|
||||
monitorCmdRet map[string]interface{}
|
||||
expectedKeysSent string
|
||||
expectedAction multistep.StepAction
|
||||
name string
|
||||
builderConfig *Config
|
||||
expectCallSendkey bool
|
||||
sendkeyErr error
|
||||
expectedKeysSent string
|
||||
expectedAction multistep.StepAction
|
||||
}{
|
||||
{
|
||||
name: "simple boot command is typed",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"hello"}}},
|
||||
expectCallMonitorCmd: true,
|
||||
expectedKeysSent: "hello",
|
||||
expectedAction: multistep.ActionContinue,
|
||||
name: "simple boot command is typed",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"hello"}}},
|
||||
expectCallSendkey: true,
|
||||
expectedKeysSent: "hello",
|
||||
expectedAction: multistep.ActionContinue,
|
||||
},
|
||||
{
|
||||
name: "interpolated boot command",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"hello<enter>world"}}},
|
||||
expectCallMonitorCmd: true,
|
||||
expectedKeysSent: "helloretworld",
|
||||
expectedAction: multistep.ActionContinue,
|
||||
name: "interpolated boot command",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"hello<enter>world"}}},
|
||||
expectCallSendkey: true,
|
||||
expectedKeysSent: "helloretworld",
|
||||
expectedAction: multistep.ActionContinue,
|
||||
},
|
||||
{
|
||||
name: "merge multiple interpolated boot command",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"Hello World 2.0", "foo!bar@baz"}}},
|
||||
expectCallMonitorCmd: true,
|
||||
expectedKeysSent: "shift-hellospcshift-worldspc2dot0fooshift-1barshift-2baz",
|
||||
expectedAction: multistep.ActionContinue,
|
||||
name: "merge multiple interpolated boot command",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"Hello World 2.0", "foo!bar@baz"}}},
|
||||
expectCallSendkey: true,
|
||||
expectedKeysSent: "shift-hellospcshift-worldspc2dot0fooshift-1barshift-2baz",
|
||||
expectedAction: multistep.ActionContinue,
|
||||
},
|
||||
{
|
||||
name: "without boot command monitorcmd should not be called",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{}}},
|
||||
expectCallMonitorCmd: false,
|
||||
expectedAction: multistep.ActionContinue,
|
||||
name: "without boot command sendkey should not be called",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{}}},
|
||||
expectCallSendkey: false,
|
||||
expectedAction: multistep.ActionContinue,
|
||||
},
|
||||
{
|
||||
name: "invalid boot command template function",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"{{ foo }}"}}},
|
||||
expectCallMonitorCmd: false,
|
||||
expectedAction: multistep.ActionHalt,
|
||||
name: "invalid boot command template function",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"{{ foo }}"}}},
|
||||
expectCallSendkey: false,
|
||||
expectedAction: multistep.ActionHalt,
|
||||
},
|
||||
{
|
||||
// When proxmox (or Qemu, really) doesn't recognize the keycode we send, we get no error back, but
|
||||
// a map {"data": "invalid parameter: X"}, where X is the keycode.
|
||||
name: "invalid keys sent to proxmox",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"x"}}},
|
||||
expectCallMonitorCmd: true,
|
||||
monitorCmdRet: map[string]interface{}{"data": "invalid parameter: x"},
|
||||
expectedKeysSent: "x",
|
||||
expectedAction: multistep.ActionHalt,
|
||||
name: "invalid keys sent to proxmox",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"x"}}},
|
||||
expectCallSendkey: true,
|
||||
sendkeyErr: fmt.Errorf("invalid parameter: x"),
|
||||
expectedKeysSent: "x",
|
||||
expectedAction: multistep.ActionHalt,
|
||||
},
|
||||
{
|
||||
name: "error in typing should return halt",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"hello"}}},
|
||||
expectCallMonitorCmd: true,
|
||||
monitorCmdErr: fmt.Errorf("some error"),
|
||||
expectedKeysSent: "h",
|
||||
expectedAction: multistep.ActionHalt,
|
||||
name: "error in typing should return halt",
|
||||
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"hello"}}},
|
||||
expectCallSendkey: true,
|
||||
sendkeyErr: fmt.Errorf("some error"),
|
||||
expectedKeysSent: "h",
|
||||
expectedAction: multistep.ActionHalt,
|
||||
},
|
||||
}
|
||||
|
||||
@ -89,17 +88,14 @@ func TestTypeBootCommand(t *testing.T) {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
accumulator := strings.Builder{}
|
||||
typer := commandTyperMock{
|
||||
monitorCmd: func(ref *proxmox.VmRef, cmd string) (map[string]interface{}, error) {
|
||||
if !c.expectCallMonitorCmd {
|
||||
t.Error("Did not expect MonitorCmd to be called")
|
||||
}
|
||||
if !strings.HasPrefix(cmd, "sendkey ") {
|
||||
t.Errorf("Expected all commands to be sendkey, got %s", cmd)
|
||||
sendkey: func(ref *proxmox.VmRef, cmd string) error {
|
||||
if !c.expectCallSendkey {
|
||||
t.Error("Did not expect sendkey to be called")
|
||||
}
|
||||
|
||||
accumulator.WriteString(strings.TrimPrefix(cmd, "sendkey "))
|
||||
accumulator.WriteString(cmd)
|
||||
|
||||
return c.monitorCmdRet, c.monitorCmdErr
|
||||
return c.sendkeyErr
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -413,6 +413,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
new(stepCreateDisk),
|
||||
new(stepCopyDisk),
|
||||
|
@ -18,6 +18,7 @@ type AccessConfig struct {
|
||||
PrivateKey string `mapstructure:"private_key"`
|
||||
Region string `mapstructure:"region"`
|
||||
ProjectId string `mapstructure:"project_id"`
|
||||
BaseUrl string `mapstructure:"base_url"`
|
||||
|
||||
client *UCloudClient
|
||||
}
|
||||
@ -30,6 +31,9 @@ func (c *AccessConfig) Client() (*UCloudClient, error) {
|
||||
cfg := ucloud.NewConfig()
|
||||
cfg.Region = c.Region
|
||||
cfg.ProjectId = c.ProjectId
|
||||
if c.BaseUrl != "" {
|
||||
cfg.BaseUrl = c.BaseUrl
|
||||
}
|
||||
cfg.UserAgent = fmt.Sprintf("Packer-UCloud/%s", version.FormattedVersion())
|
||||
|
||||
cred := auth.NewCredential()
|
||||
|
@ -3,6 +3,7 @@ package uhost
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@ -193,6 +194,17 @@ func testAccPreCheck(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUCloudClientBaseUrlConfigurable(t *testing.T) {
|
||||
const url = "baseUrl"
|
||||
access := &AccessConfig{BaseUrl: url}
|
||||
client, err := access.Client()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, url, client.uaccountconn.Client.GetConfig().BaseUrl, "account conn's base url not configurable")
|
||||
assert.Equal(t, url, client.uhostconn.Client.GetConfig().BaseUrl, "host conn's base url not configurable")
|
||||
assert.Equal(t, url, client.unetconn.Client.GetConfig().BaseUrl, "net conn's base url not configurable")
|
||||
assert.Equal(t, url, client.vpcconn.Client.GetConfig().BaseUrl, "vpc conn's base url not configurable")
|
||||
}
|
||||
|
||||
func testUCloudClient() (*UCloudClient, error) {
|
||||
access := &AccessConfig{Region: "cn-bj2"}
|
||||
err := access.Config()
|
||||
|
@ -14,23 +14,28 @@ type StepUp struct {
|
||||
GlobalID string
|
||||
}
|
||||
|
||||
func (s *StepUp) generateArgs() []string {
|
||||
box := "source"
|
||||
if s.GlobalID != "" {
|
||||
box = s.GlobalID
|
||||
}
|
||||
|
||||
// start only the source box
|
||||
args := []string{box}
|
||||
|
||||
if s.Provider != "" {
|
||||
args = append(args, fmt.Sprintf("--provider=%s", s.Provider))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func (s *StepUp) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
driver := state.Get("driver").(VagrantDriver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Calling Vagrant Up...")
|
||||
|
||||
// start only the source box
|
||||
args := []string{"source"}
|
||||
if s.GlobalID != "" {
|
||||
args = append(args, s.GlobalID)
|
||||
}
|
||||
|
||||
if s.Provider != "" {
|
||||
args = append(args, fmt.Sprintf("--provider=%s", s.Provider))
|
||||
}
|
||||
|
||||
_, _, err := driver.Up(args)
|
||||
_, _, err := driver.Up(s.generateArgs())
|
||||
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
@ -46,16 +51,21 @@ func (s *StepUp) Cleanup(state multistep.StateBag) {
|
||||
|
||||
ui.Say(fmt.Sprintf("%sing Vagrant box...", s.TeardownMethod))
|
||||
|
||||
box := "source"
|
||||
if s.GlobalID != "" {
|
||||
box = s.GlobalID
|
||||
}
|
||||
|
||||
var err error
|
||||
if s.TeardownMethod == "halt" {
|
||||
err = driver.Halt(s.GlobalID)
|
||||
err = driver.Halt(box)
|
||||
} else if s.TeardownMethod == "suspend" {
|
||||
err = driver.Suspend(s.GlobalID)
|
||||
err = driver.Suspend(box)
|
||||
} else if s.TeardownMethod == "destroy" {
|
||||
err = driver.Destroy(s.GlobalID)
|
||||
err = driver.Destroy(box)
|
||||
} else {
|
||||
// Should never get here because of template validation
|
||||
state.Put("error", fmt.Errorf("Invalid teardown method selected; must be either halt, suspend, or destory."))
|
||||
state.Put("error", fmt.Errorf("Invalid teardown method selected; must be either halt, suspend, or destroy."))
|
||||
}
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("Error halting Vagrant machine; please try to do this manually"))
|
||||
|
40
builder/vagrant/step_up_test.go
Normal file
40
builder/vagrant/step_up_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
package vagrant
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPrepUpArgs(t *testing.T) {
|
||||
type testArgs struct {
|
||||
Step StepUp
|
||||
Expected []string
|
||||
}
|
||||
tests := []testArgs{
|
||||
{
|
||||
Step: StepUp{
|
||||
GlobalID: "foo",
|
||||
Provider: "bar",
|
||||
},
|
||||
Expected: []string{"foo", "--provider=bar"},
|
||||
},
|
||||
{
|
||||
Step: StepUp{},
|
||||
Expected: []string{"source"},
|
||||
},
|
||||
{
|
||||
Step: StepUp{
|
||||
Provider: "pro",
|
||||
},
|
||||
Expected: []string{"source", "--provider=pro"},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
args := test.Step.generateArgs()
|
||||
for i, val := range test.Expected {
|
||||
if strings.Compare(args[i], val) != 0 {
|
||||
t.Fatalf("expected %#v but received %#v", test.Expected, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -252,17 +252,18 @@ func (d *VBox42Driver) LoadSnapshots(vmName string) (*VBoxSnapshot, error) {
|
||||
}
|
||||
log.Printf("Executing LoadSnapshots: VM: %s", vmName)
|
||||
|
||||
var rootNode *VBoxSnapshot
|
||||
stdoutString, err := d.VBoxManageWithOutput("snapshot", vmName, "list", "--machinereadable")
|
||||
if stdoutString == "This machine does not have any snapshots" {
|
||||
return rootNode, nil
|
||||
}
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rootNode *VBoxSnapshot
|
||||
if stdoutString != "This machine does not have any snapshots" {
|
||||
rootNode, err = ParseSnapshotData(stdoutString)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
rootNode, err = ParseSnapshotData(stdoutString)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rootNode, nil
|
||||
|
@ -159,7 +159,7 @@ func TestStepShutdown_shutdownDelay(t *testing.T) {
|
||||
t.Fatalf("bad action: %#v", action)
|
||||
}
|
||||
testDuration = time.Since(start)
|
||||
if testDuration > 600*time.Millisecond {
|
||||
if testDuration > 700*time.Millisecond {
|
||||
t.Fatalf("incorrect duration %s", testDuration)
|
||||
}
|
||||
|
||||
|
@ -223,6 +223,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&common.StepHTTPServer{
|
||||
HTTPDir: b.config.HTTPDir,
|
||||
|
@ -57,6 +57,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&common.StepHTTPServer{
|
||||
HTTPDir: b.config.HTTPDir,
|
||||
|
@ -86,6 +86,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&stepRemoteUpload{
|
||||
Key: "floppy_path",
|
||||
|
@ -82,6 +82,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&common.StepCreateFloppy{
|
||||
Files: b.config.FloppyConfig.FloppyFiles,
|
||||
Directories: b.config.FloppyConfig.FloppyDirectories,
|
||||
Label: b.config.FloppyConfig.FloppyLabel,
|
||||
},
|
||||
&StepCloneVMX{
|
||||
OutputDir: b.config.OutputDir,
|
||||
|
@ -61,7 +61,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||
&stepInstanceInfo{},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.Communicator,
|
||||
Host: communicator.CommHost(b.config.Communicator.SSHHost, "instance_ip"),
|
||||
Host: commHost,
|
||||
SSHConfig: b.config.Communicator.SSHConfigFunc(),
|
||||
},
|
||||
&common.StepProvision{},
|
||||
|
@ -18,6 +18,8 @@ import (
|
||||
)
|
||||
|
||||
const defaultEndpoint = "api.cloud.yandex.net:443"
|
||||
const defaultGpuPlatformID = "gpu-standard-v1"
|
||||
const defaultPlatformID = "standard-v1"
|
||||
const defaultZone = "ru-central1-a"
|
||||
|
||||
var reImageFamily = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`)
|
||||
@ -40,6 +42,7 @@ type Config struct {
|
||||
ImageName string `mapstructure:"image_name"`
|
||||
ImageProductIDs []string `mapstructure:"image_product_ids"`
|
||||
InstanceCores int `mapstructure:"instance_cores"`
|
||||
InstanceGpus int `mapstructure:"instance_gpus"`
|
||||
InstanceMemory int `mapstructure:"instance_mem_gb"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
Labels map[string]string `mapstructure:"labels"`
|
||||
@ -51,6 +54,7 @@ type Config struct {
|
||||
SourceImageFamily string `mapstructure:"source_image_family"`
|
||||
SourceImageFolderID string `mapstructure:"source_image_folder_id"`
|
||||
SourceImageID string `mapstructure:"source_image_id"`
|
||||
SourceImageName string `mapstructure:"source_image_name"`
|
||||
SubnetID string `mapstructure:"subnet_id"`
|
||||
UseIPv4Nat bool `mapstructure:"use_ipv4_nat"`
|
||||
UseIPv6 bool `mapstructure:"use_ipv6"`
|
||||
@ -134,7 +138,10 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
}
|
||||
|
||||
if c.PlatformID == "" {
|
||||
c.PlatformID = "standard-v1"
|
||||
c.PlatformID = defaultPlatformID
|
||||
if c.InstanceGpus != 0 {
|
||||
c.PlatformID = defaultGpuPlatformID
|
||||
}
|
||||
}
|
||||
|
||||
if es := c.Communicator.Prepare(&c.ctx); len(es) > 0 {
|
||||
@ -142,9 +149,15 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
}
|
||||
|
||||
// Process required parameters.
|
||||
if c.SourceImageID == "" && c.SourceImageFamily == "" {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("a source_image_id or source_image_family must be specified"))
|
||||
if c.SourceImageID == "" {
|
||||
if c.SourceImageFamily == "" && c.SourceImageName == "" {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("a source_image_name or source_image_family must be specified"))
|
||||
}
|
||||
if c.SourceImageFamily != "" && c.SourceImageName != "" {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("one of source_image_name or source_image_family must be specified, not both"))
|
||||
}
|
||||
}
|
||||
|
||||
if c.Endpoint == "" {
|
||||
@ -168,6 +181,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
c.FolderID = os.Getenv("YC_FOLDER_ID")
|
||||
}
|
||||
|
||||
if c.PlatformID != defaultGpuPlatformID && c.InstanceGpus != 0 {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, fmt.Errorf("for instances with gpu platform_id must be specified as `%s`", defaultGpuPlatformID))
|
||||
}
|
||||
|
||||
if c.Token == "" && c.ServiceAccountKeyFile == "" {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("a token or service account key file must be specified"))
|
||||
|
@ -214,6 +214,25 @@ func TestZone(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGpuDefaultPlatformID(t *testing.T) {
|
||||
raw := testConfig(t)
|
||||
raw["instance_gpus"] = 1
|
||||
|
||||
c, _, _ := NewConfig(raw)
|
||||
if c.PlatformID != "gpu-standard-v1" {
|
||||
t.Fatalf("expected 'gpu-standard-v1', but got '%s'", c.PlatformID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGpuWrongPlatformID(t *testing.T) {
|
||||
raw := testConfig(t)
|
||||
raw["instance_gpus"] = 1
|
||||
raw["platform_id"] = "standard-v1"
|
||||
|
||||
_, warns, errs := NewConfig(raw)
|
||||
testConfigErr(t, warns, errs, "incompatible GPU platform_id")
|
||||
}
|
||||
|
||||
// Helper stuff below
|
||||
|
||||
func testConfig(t *testing.T) (config map[string]interface{}) {
|
||||
|
@ -11,6 +11,7 @@ type Driver interface {
|
||||
SDK() *ycsdk.SDK
|
||||
GetImage(imageID string) (*Image, error)
|
||||
GetImageFromFolder(ctx context.Context, folderID string, family string) (*Image, error)
|
||||
GetImageFromFolderByName(ctx context.Context, folderID string, name string) (*Image, error)
|
||||
DeleteDisk(ctx context.Context, diskID string) error
|
||||
DeleteInstance(ctx context.Context, instanceID string) error
|
||||
DeleteSubnet(ctx context.Context, subnetID string) error
|
||||
|
@ -2,6 +2,7 @@ package yandex
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/packer/helper/useragent"
|
||||
@ -15,6 +16,7 @@ import (
|
||||
ycsdk "github.com/yandex-cloud/go-sdk"
|
||||
"github.com/yandex-cloud/go-sdk/iamkey"
|
||||
"github.com/yandex-cloud/go-sdk/pkg/requestid"
|
||||
"github.com/yandex-cloud/go-sdk/sdkresolvers"
|
||||
)
|
||||
|
||||
type driverYC struct {
|
||||
@ -110,6 +112,16 @@ func (d *driverYC) GetImageFromFolder(ctx context.Context, folderID string, fami
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *driverYC) GetImageFromFolderByName(ctx context.Context, folderID string, imageName string) (*Image, error) {
|
||||
imageResolver := sdkresolvers.ImageResolver(imageName, sdkresolvers.FolderID(folderID))
|
||||
|
||||
if err := d.sdk.Resolve(ctx, imageResolver); err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve image name: %s", err)
|
||||
}
|
||||
|
||||
return d.GetImage(imageResolver.ID())
|
||||
}
|
||||
|
||||
func (d *driverYC) DeleteImage(ID string) error {
|
||||
ctx := context.TODO()
|
||||
op, err := d.sdk.WrapOperation(d.sdk.Compute().Image().Delete(ctx, &compute.DeleteImageRequest{
|
||||
|
10
builder/yandex/ssh.go
Normal file
10
builder/yandex/ssh.go
Normal file
@ -0,0 +1,10 @@
|
||||
package yandex
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
)
|
||||
|
||||
func commHost(state multistep.StateBag) (string, error) {
|
||||
ipAddress := state.Get("instance_ip").(string)
|
||||
return ipAddress, nil
|
||||
}
|
@ -91,11 +91,19 @@ func getImage(ctx context.Context, c *Config, d Driver) (*Image, error) {
|
||||
return d.GetImage(c.SourceImageID)
|
||||
}
|
||||
|
||||
familyName := c.SourceImageFamily
|
||||
if c.SourceImageFolderID != "" {
|
||||
return d.GetImageFromFolder(ctx, c.SourceImageFolderID, familyName)
|
||||
folderID := c.SourceImageFolderID
|
||||
if folderID == "" {
|
||||
folderID = StandardImagesFolderID
|
||||
}
|
||||
return d.GetImageFromFolder(ctx, StandardImagesFolderID, familyName)
|
||||
|
||||
switch {
|
||||
case c.SourceImageFamily != "":
|
||||
return d.GetImageFromFolder(ctx, folderID, c.SourceImageFamily)
|
||||
case c.SourceImageName != "":
|
||||
return d.GetImageFromFolderByName(ctx, folderID, c.SourceImageName)
|
||||
}
|
||||
|
||||
return &Image{}, errors.New("neither source_image_name nor source_image_family defined in config")
|
||||
}
|
||||
|
||||
func (s *stepCreateInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
@ -173,6 +181,7 @@ runcmd:
|
||||
ResourcesSpec: &compute.ResourcesSpec{
|
||||
Memory: toBytes(config.InstanceMemory),
|
||||
Cores: int64(config.InstanceCores),
|
||||
Gpus: int64(config.InstanceGpus),
|
||||
},
|
||||
Metadata: instanceMetadata,
|
||||
BootDiskSpec: &compute.AttachedDiskSpec{
|
||||
|
@ -20,7 +20,7 @@ func (s *stepInstanceInfo) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
c := state.Get("config").(*Config)
|
||||
instanceID := state.Get("instance_id").(string)
|
||||
|
||||
ui.Say("Waiting for instance to become active...")
|
||||
ui.Say(fmt.Sprintf("Waiting for instance with id %s to become active...", instanceID))
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, c.StateTimeout)
|
||||
defer cancel()
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
type FloppyConfig struct {
|
||||
FloppyFiles []string `mapstructure:"floppy_files"`
|
||||
FloppyDirectories []string `mapstructure:"floppy_dirs"`
|
||||
FloppyLabel string `mapstructure:"floppy_label"`
|
||||
}
|
||||
|
||||
func (c *FloppyConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
@ -72,7 +72,11 @@ func TestListenRangeConfig_Listen(t *testing.T) {
|
||||
l.Close()
|
||||
t.Fatalf("port should be taken, this should timeout.")
|
||||
}
|
||||
if p := int(err.(ErrPortFileLocked)); p != lockedListener.Port {
|
||||
portErr, ok := err.(ErrPortFileLocked)
|
||||
if !ok {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if p := int(portErr); p != lockedListener.Port {
|
||||
t.Fatalf("wrong fileport: %d", p)
|
||||
}
|
||||
cancel()
|
||||
|
@ -32,20 +32,25 @@ type scriptOptions struct {
|
||||
func GetHostAdapterIpAddressForSwitch(switchName string) (string, error) {
|
||||
var script = `
|
||||
param([string]$switchName, [int]$addressIndex)
|
||||
|
||||
$HostVMAdapter = Hyper-V\Get-VMNetworkAdapter -ManagementOS -SwitchName $switchName
|
||||
if ($HostVMAdapter){
|
||||
$HostNetAdapter = Get-NetAdapter | ?{ $_.DeviceId -eq $HostVMAdapter.DeviceId }
|
||||
if ($HostNetAdapter){
|
||||
$HostNetAdapterIfIndex = @()
|
||||
$HostNetAdapterIfIndex += $HostNetAdapter.ifIndex
|
||||
$HostNetAdapterConfiguration = @(get-wmiobject win32_networkadapterconfiguration -filter "IPEnabled = 'TRUE'") | Where-Object { $HostNetAdapterIfIndex.Contains($_.InterfaceIndex) }
|
||||
if ($HostNetAdapterConfiguration){
|
||||
return @($HostNetAdapterConfiguration.IpAddress)[$addressIndex]
|
||||
}
|
||||
$HostNetAdapter = Get-NetAdapter | Where-Object { $_.DeviceId -eq $HostVMAdapter.DeviceId }
|
||||
if ($HostNetAdapter){
|
||||
$HostNetAdapterIfIndex = @()
|
||||
$HostNetAdapterIfIndex += $HostNetAdapter.ifIndex
|
||||
$HostNetAdapterConfiguration = @(get-wmiobject win32_networkadapterconfiguration -filter "IPEnabled = 'TRUE'") | Where-Object { $HostNetAdapterIfIndex.Contains($_.InterfaceIndex)
|
||||
if ($HostNetAdapterConfiguration){
|
||||
return @($HostNetAdapterConfiguration.IpAddress)[$addressIndex]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$HostNetAdapterConfiguration=@(Get-NetIPAddress -CimSession $env:computername -AddressFamily IPv4 | Where-Object { ( $_.InterfaceAlias -notmatch 'Loopback' ) -and ( $_.SuffixOrigin -notmatch "Link" )})
|
||||
if ($HostNetAdapterConfiguration) {
|
||||
return @($HostNetAdapterConfiguration.IpAddress)[$addressIndex]
|
||||
} else {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
return $false
|
||||
`
|
||||
|
||||
var ps powershell.PowerShellCmd
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
type StepCreateFloppy struct {
|
||||
Files []string
|
||||
Directories []string
|
||||
Label string
|
||||
|
||||
floppyPath string
|
||||
|
||||
@ -33,6 +34,12 @@ func (s *StepCreateFloppy) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
if s.Label == "" {
|
||||
s.Label = "packer"
|
||||
} else {
|
||||
log.Printf("Floppy label is set to %s", s.Label)
|
||||
}
|
||||
|
||||
s.FilesAdded = make(map[string]bool)
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
@ -70,8 +77,8 @@ func (s *StepCreateFloppy) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
log.Println("Formatting the block device with a FAT filesystem...")
|
||||
formatConfig := &fat.SuperFloppyConfig{
|
||||
FATType: fat.FAT12,
|
||||
Label: "packer",
|
||||
OEMName: "packer",
|
||||
Label: s.Label,
|
||||
OEMName: s.Label,
|
||||
}
|
||||
if err := fat.FormatSuperFloppy(device, formatConfig); err != nil {
|
||||
state.Put("error", fmt.Errorf("Error creating floppy: %s", err))
|
||||
|
31
go.mod
31
go.mod
@ -8,7 +8,7 @@ require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4 // indirect
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190614181158-26cd147831a4
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190815172943-ef9222844e60
|
||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190418113227-25233c783f4e
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f
|
||||
@ -31,6 +31,7 @@ require (
|
||||
github.com/digitalocean/godo v1.11.1
|
||||
github.com/dnaeon/go-vcr v1.0.0 // indirect
|
||||
github.com/docker/docker v0.0.0-20180422163414-57142e89befe // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/dylanmei/iso8601 v0.1.0 // indirect
|
||||
github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08
|
||||
github.com/exoscale/egoscale v0.18.1
|
||||
@ -38,7 +39,8 @@ require (
|
||||
github.com/gofrs/flock v0.7.1
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
|
||||
github.com/google/go-cmp v0.2.0
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20150127133951-6f45313302b9
|
||||
github.com/google/uuid v1.0.0
|
||||
github.com/gophercloud/gophercloud v0.2.0
|
||||
@ -49,7 +51,7 @@ require (
|
||||
github.com/hashicorp/errwrap v1.0.0
|
||||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0
|
||||
github.com/hashicorp/go-getter v1.3.1-0.20190627223108-da0323b9545e
|
||||
github.com/hashicorp/go-getter v1.3.1-0.20190906090232-a0f878cb75da
|
||||
github.com/hashicorp/go-multierror v1.0.0
|
||||
github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79
|
||||
github.com/hashicorp/go-retryablehttp v0.5.2 // indirect
|
||||
@ -83,7 +85,6 @@ require (
|
||||
github.com/mitchellh/go-fs v0.0.0-20180402234041-7b48fa161ea7
|
||||
github.com/mitchellh/go-homedir v1.0.0
|
||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed
|
||||
github.com/mitchellh/gox v1.0.1 // indirect
|
||||
github.com/mitchellh/iochan v1.0.0
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180111000720-b4575eea38cc
|
||||
github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557
|
||||
@ -120,18 +121,20 @@ require (
|
||||
github.com/ulikunitz/xz v0.5.5
|
||||
github.com/vmware/govmomi v0.0.0-20170707011325-c2105a174311
|
||||
github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20190401174212-1db0ef3dce9b
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20190402114215-3fc1d6947035
|
||||
golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20190802103534-6089d9ff8d82
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20190802103531-4ab1dac90bf7
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sys v0.0.0-20190425145619-16072639606e
|
||||
golang.org/x/text v0.3.1 // indirect
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 // indirect
|
||||
google.golang.org/api v0.4.0
|
||||
google.golang.org/grpc v1.20.1
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0
|
||||
google.golang.org/api v0.9.0
|
||||
google.golang.org/grpc v1.21.1
|
||||
gopkg.in/h2non/gock.v1 v1.0.12 // indirect
|
||||
gopkg.in/ini.v1 v1.42.0 // indirect
|
||||
gopkg.in/jarcoal/httpmock.v1 v1.0.0-20181117152235-275e9df93516 // indirect
|
||||
)
|
||||
|
||||
replace github.com/gofrs/flock => github.com/azr/flock v0.0.0-20190823144736-958d66434653
|
||||
|
||||
go 1.13
|
||||
|
205
go.sum
205
go.sum
@ -1,15 +1,14 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.36.0 h1:+aCSj7tOo2LODWVEuZDZeGCckdt6MlSF+X/rB3wUiS8=
|
||||
cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.5.0 h1:TKXjQSRS0/cCDrP7KvkgU6SmILtF/yV2TOs/02K/WZQ=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1 h1:RMTyvS5bjvSWiUcfqfr/E2pxHEMrALvU+E12n6biymg=
|
||||
github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1/go.mod h1:61apmbkVJH4kg+38ftT+/l0XxdUCVnHggqcOTqZRSEE=
|
||||
github.com/Azure/azure-sdk-for-go v30.0.0+incompatible h1:6o1Yzl7wTBYg+xw0pY4qnalaPmEQolubEEdepo1/kmI=
|
||||
@ -19,19 +18,21 @@ github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4 h1:pSm8mp0T2OH2CPmPDPtwHPr3VAQaOwVF/JbllOPP4xA=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 h1:K9I21XUHNbYD3GNMmJBN0UKJCpdP+glftwNZ7Bo8kqY=
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591 h1:/P9HCl71+Eh6vDbKNyRu+rpIIR70UCZWNOGexVV3e6k=
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591/go.mod h1:EHGzQGbwozJBj/4qj3WGrTJ0FqjgOTOxLQ0VNWvPn08=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190614181158-26cd147831a4 h1:o//09WenT9BNcQypCYfOBfRe5gtLUvUfTPq0xQqPMEI=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190614181158-26cd147831a4/go.mod h1:OGWyIMJ87/k/GCz8CGiWB2HOXsOVDM6Lpe/nFPkC4IQ=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190815172943-ef9222844e60 h1:iEmbIRk4brAP3wevhCr5MGAqxHUbbIDHvE+6D1/7pRA=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190815172943-ef9222844e60/go.mod h1:OGWyIMJ87/k/GCz8CGiWB2HOXsOVDM6Lpe/nFPkC4IQ=
|
||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=
|
||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190418113227-25233c783f4e h1:/8wOj52pewmIX/8d5eVO3t7Rr3astkBI/ruyg4WNqRo=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190418113227-25233c783f4e/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f h1:jI4DIE5Vf4oRaHfthB0oRhU+yuYuoOTurDzwAlskP00=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd h1:S3Fr6QnkpW9VRjiEY4psQHhhbbahASuNVj52YIce7lI=
|
||||
github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||
github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607 h1:BFFG6KP8ASFBg2ptWsJn8p8RDufBjBDKIxLU7BTYGOM=
|
||||
@ -48,18 +49,16 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
|
||||
github.com/aws/aws-sdk-go v1.16.22/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.16.24 h1:I/A3Hwbgs3IEAP6v1bFpHKXiT7wZDoToX9cb00nxZnM=
|
||||
github.com/aws/aws-sdk-go v1.16.24/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.22.2 h1:uYP58k2Cd9y1qBy8CxTe5ADmdi4kANm8Ul8ch3kkIcQ=
|
||||
github.com/aws/aws-sdk-go v1.22.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/azr/flock v0.0.0-20190823144736-958d66434653 h1:2H3Cu0cbG8iszfcgnANwC/cm0YkPJIQvaJ9/tSpwh9o=
|
||||
github.com/azr/flock v0.0.0-20190823144736-958d66434653/go.mod h1:EI7lzWWilX2K3ZMZ7Ta+E4DZtWzMC2tbn3cM3oVPuAU=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3 h1:3b+p838vN4sc37brz9W2HDphtSwZFcXZwFLyzm5Vk28=
|
||||
github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3/go.mod h1:YOY5xnRf7Jz2SZCLSKgVfyqNzbRgyTznM3HyDqQMxcU=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae h1:2Zmk+8cNvAGuY8AyvZuWpUdpQUAXwfom4ReVMe/CTIo=
|
||||
github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
|
||||
@ -73,7 +72,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/creack/goselect v0.1.0 h1:4QiXIhcpSQF50XGaBsFzesjwX/1qOY5bOveQPmN9CXY=
|
||||
github.com/creack/goselect v0.1.0/go.mod h1:gHrIcH/9UZDn2qgeTUeW5K9eZsVYCH6/60J/FHysWyE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -101,64 +99,58 @@ github.com/exoscale/egoscale v0.18.1 h1:1FNZVk8jHUx0AvWhOZxLEDNlacTU0chMXUUNkm9E
|
||||
github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-ini/ini v1.25.4 h1:Mujh4R/dH6YL8bxuISne3xX2+qcQ9p0IxKAP6ExWoUo=
|
||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=
|
||||
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
|
||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/shlex v0.0.0-20150127133951-6f45313302b9 h1:JM174NTeGNJ2m/oLH3UOWOvWQQKd+BoL3hcSCUWFLt0=
|
||||
github.com/google/shlex v0.0.0-20150127133951-6f45313302b9/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
|
||||
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3 h1:siORttZ36U2R/WjiJuDz8znElWBiAlO9rVt+mqJt0Cc=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gophercloud/gophercloud v0.0.0-20180903124057-ea7289ebdf06 h1:m7Rt/8En7PLrM7PQpykdZBPKUdgZWN6MwiA/ChVIoxs=
|
||||
github.com/gophercloud/gophercloud v0.0.0-20180903124057-ea7289ebdf06/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gophercloud/gophercloud v0.2.0 h1:lD2Bce2xBAMNNcFZ0dObTpXkGLlVIb33RPVUNVpw6ic=
|
||||
github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gophercloud/utils v0.0.0-20190124192022-a5c25e7a53a6 h1:Cw/B8Bu7Rryomxf7bjc8zNfIyLgjxsDd91n0eGRWpuo=
|
||||
github.com/gophercloud/utils v0.0.0-20190124192022-a5c25e7a53a6/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 h1:JIM+OacoOJRU30xpjMf8sulYqjr0ViA3WDrTX6j/yDI=
|
||||
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul v1.4.0 h1:PQTW4xCuAExEiSbhrsFsikzbW5gVBoi74BjUvYFyKHw=
|
||||
@ -169,8 +161,8 @@ github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de h1:XDCSyth
|
||||
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-getter v1.3.1-0.20190627223108-da0323b9545e h1:6krcdHPiS+aIP9XKzJzSahfjD7jG7Z+4+opm0z39V1M=
|
||||
github.com/hashicorp/go-getter v1.3.1-0.20190627223108-da0323b9545e/go.mod h1:/O1k/AizTN0QmfEKknCYGvICeyKUDqCYA8vvWtGWDeQ=
|
||||
github.com/hashicorp/go-getter v1.3.1-0.20190906090232-a0f878cb75da h1:HAasZmyRrb7/paYuww5RfVwY3wkFpsbMNYwBxOSZquY=
|
||||
github.com/hashicorp/go-getter v1.3.1-0.20190906090232-a0f878cb75da/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
|
||||
@ -191,7 +183,6 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
|
||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
|
||||
@ -199,6 +190,8 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
@ -219,7 +212,6 @@ github.com/hyperonecom/h1-client-go v0.0.0-20190122232013-cf38e8387775 h1:MIteIo
|
||||
github.com/hyperonecom/h1-client-go v0.0.0-20190122232013-cf38e8387775/go.mod h1:R9rU87RxxmcD3DkspW9JqGBXiJyg5MA+WNCtJrBtnXs=
|
||||
github.com/jdcloud-api/jdcloud-sdk-go v1.9.1-0.20190605102154-3d81a50ca961 h1:a2/K4HRhg31A5vafiz5yYiGMjaCxwRpyjJStfVquKds=
|
||||
github.com/jdcloud-api/jdcloud-sdk-go v1.9.1-0.20190605102154-3d81a50ca961/go.mod h1:UrKjuULIWLjHFlG6aSPunArE5QX57LftMmStAZJBEX8=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
@ -227,11 +219,11 @@ github.com/joyent/triton-go v0.0.0-20180116165742-545edbe0d564 h1:+HMa2xWQOm+9eb
|
||||
github.com/joyent/triton-go v0.0.0-20180116165742-545edbe0d564/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77 h1:rJnR80lkojFgjdg/oQPhbZoY8t8uM51XMz8DrJrjabk=
|
||||
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20160106104451-349c67577817 h1:/7pPahIC+GoCm/euDCi2Pm29bAj9tc6TcK4Zcc8D3WI=
|
||||
@ -247,7 +239,6 @@ github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169/go.mod h1:glhvuHOU9Hy7/8Pwwd
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
|
||||
@ -269,8 +260,6 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859 h1:smQbSzmT3EHl4EUwtFwFGmGIpiYgIiiPeVv1uguIQEE=
|
||||
github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.1 h1:DVkblRdiScEnEr0LR9nTnEQqHYycjkXW9bOjd+2EL2o=
|
||||
github.com/miekg/dns v1.1.1/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@ -285,8 +274,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI
|
||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed h1:FI2NIv6fpef6BQl2u3IZX/Cj20tfypRF4yd+uaHOMtI=
|
||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
|
||||
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
|
||||
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
@ -308,8 +295,6 @@ github.com/moul/gotty-client v0.0.0-20180327180212-b26a57ebc215 h1:y6FZWUBBt1iPm
|
||||
github.com/moul/gotty-client v0.0.0-20180327180212-b26a57ebc215/go.mod h1:CxM/JGtpRrEPve5H04IhxJrGhxgwxMc6jSP2T4YD60w=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20180105111133-96aac992fc8b h1:LGItPaClbzopugAomw5VFKnG3h1dUr9QW5KOU+m8gu0=
|
||||
@ -319,7 +304,6 @@ github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/oracle/oci-go-sdk v1.8.0 h1:4SO45bKV0I3/Mn1os3ANDZmV0eSE5z5CLdSUIkxtyzs=
|
||||
github.com/oracle/oci-go-sdk v1.8.0/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||
github.com/outscale/osc-go v0.0.1 h1:hvBtORyu7sWSKW1norGlfIP8C7c2aegI2Vkq75SRPCE=
|
||||
@ -340,14 +324,9 @@ github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible h1:ZoVHH6voxW9Onzo6z2yLtocVoN6mBocyDoqoyAMHokE=
|
||||
github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible/go.mod h1:T3/WrziK7fYH3C8ilAFAHe99R452/IzIG3YYkqaOFeQ=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/renstrom/fuzzysearch v0.0.0-20160331204855-2d205ac6ec17 h1:4qPms2txLWMLXKzqlnYSulKRS4cS9aYgPtAEpUelQok=
|
||||
github.com/renstrom/fuzzysearch v0.0.0-20160331204855-2d205ac6ec17/go.mod h1:SAEjPB4voP88qmWJXI7mA5m15uNlEnuHLx4Eu2mPGpQ=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/rwtodd/Go.Sed v0.0.0-20170507045331-d6d5d585814e h1:lN+IKs+Jb9uwDOMO4VJZzH9vOjjist0THR5s9akp+Ss=
|
||||
github.com/rwtodd/Go.Sed v0.0.0-20170507045331-d6d5d585814e/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
@ -359,37 +338,12 @@ github.com/scaleway/scaleway-cli v0.0.0-20180921094345-7b12c9699d70 h1:DaqC32ZwO
|
||||
github.com/scaleway/scaleway-cli v0.0.0-20180921094345-7b12c9699d70/go.mod h1:XjlXWPd6VONhsRSEuzGkV8mzRpH7ou1cdLV7IKJk96s=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -397,7 +351,6 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible h1:9sIWfe6ZC7xoSlshYWNGicPqomK7N+CsHMa1YFWBCWU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go v3.0.71+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4=
|
||||
github.com/ucloud/ucloud-sdk-go v0.8.7 h1:BmXOb5RivI0Uu4oZRpjI6SQ9/y7n/H9wxTGR1txIE8o=
|
||||
@ -412,36 +365,37 @@ github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0 h1:NJrcIkdzq0C
|
||||
github.com/xanzy/go-cloudstack v0.0.0-20190526095453-42f262b63ed0/go.mod h1:sBh287mCRwCz6zyXHMmw7sSZGPohVpnx+o+OY4M+i3A=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20190401174212-1db0ef3dce9b h1:WcWw17zHjM1QoM5dPD2XUK9S0wSKlyohlCMeb1rwr0g=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20190401174212-1db0ef3dce9b/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20190802103534-6089d9ff8d82 h1:HLQoCLW2021qJKLrGQbcdEikBJ3gfYF94JYqZuw6Qxg=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20190802103534-6089d9ff8d82/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20190402114215-3fc1d6947035 h1:2ZLZeg6xp+kYYGR2iMWSZyTn6j8bphNguO3drw7S1l4=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20190402114215-3fc1d6947035/go.mod h1:Eml0jFLU4VVHgIN8zPHMuNwZXVzUMILyO6lQZSfz854=
|
||||
go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20190802103531-4ab1dac90bf7 h1:rWXARBMLHylvASK6spamDC8zSL5v2voZop3M6SBul9Y=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20190802103531-4ab1dac90bf7/go.mod h1:Eml0jFLU4VVHgIN8zPHMuNwZXVzUMILyO6lQZSfz854=
|
||||
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3 h1:KYQXGkl6vs02hK7pK4eIbw0NpNPedieTSTEiJ//bwGs=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d h1:adrbvkTDn9rGnXg2IJDKozEpXXLZN89pdIA+Syt4/u0=
|
||||
golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -451,15 +405,16 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6 h1:FP8hkuE6yUEaJnK7O2eTuejKWwW+Rhfj80dQ2JcKxCU=
|
||||
golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||
@ -475,61 +430,64 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUk
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5 h1:x6r4Jo0KNzOOzYd8lbcRsqjuqEASK6ob3auvWYM4/8U=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190425145619-16072639606e h1:4ktJgTV34+N3qOZUc5fAaG3Pb11qzMm3PkAoTAgUZ2I=
|
||||
golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1 h1:nsUiJHvm6yOoRozW9Tz0siNk9sHieLzR+w814Ihse3A=
|
||||
golang.org/x/text v0.3.1/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138 h1:H3uGjxCR/6Ds0Mjgyp7LMK81+LvmbvWWEnJhzk1Pi9E=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524210228-3d17549cdc6b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 h1:fTfk6GjmihJbK0mSUFgPPgYpsdmApQ86Mcd4GuKax9U=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
google.golang.org/api v0.4.0 h1:KKgc1aqhV8wDPbDzlDtpvyjZFY3vjz85FP7p4wcQUyI=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 h1:mBVYJnbrXLA/ZCBTCe7PtEgAUP+1bg92qTaFoPHdz+8=
|
||||
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0 h1:TRJYBgMclJvGYn2rIMjj+h9KtMt5r1Ij7ODVRIZkwhk=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
@ -540,7 +498,6 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/h2non/gock.v1 v1.0.12 h1:o3JJqe+h7R9Ay6LtMeFrKz1WnokrJDrNpDQs9KGqVn8=
|
||||
gopkg.in/h2non/gock.v1 v1.0.12/go.mod h1:KHI4Z1sxDW6P4N3DfTWSEza07YpkQP7KJBfglRMEjKY=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/jarcoal/httpmock.v1 v1.0.0-20181117152235-275e9df93516 h1:H6trpavCIuipdInWrab8l34Mf+GGVfphniHostMdMaQ=
|
||||
@ -554,9 +511,7 @@ gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
72
helper/config/custom_types.go
Normal file
72
helper/config/custom_types.go
Normal file
@ -0,0 +1,72 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Trilean uint8
|
||||
|
||||
const (
|
||||
// This will assign unset to 0, which is the default value in interpolation
|
||||
TriUnset Trilean = iota
|
||||
TriTrue
|
||||
TriFalse
|
||||
)
|
||||
|
||||
func (t Trilean) ToString() string {
|
||||
if t == TriTrue {
|
||||
return "TriTrue"
|
||||
} else if t == TriFalse {
|
||||
return "TriFalse"
|
||||
}
|
||||
return "TriUnset"
|
||||
}
|
||||
|
||||
func (t Trilean) ToBoolPointer() *bool {
|
||||
if t == TriTrue {
|
||||
return boolPointer(true)
|
||||
} else if t == TriFalse {
|
||||
return boolPointer(false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t Trilean) True() bool {
|
||||
if t == TriTrue {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t Trilean) False() bool {
|
||||
if t == TriFalse {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TrileanFromString(s string) (Trilean, error) {
|
||||
if s == "" {
|
||||
return TriUnset, nil
|
||||
}
|
||||
|
||||
b, err := strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return TriUnset, err
|
||||
} else if b == true {
|
||||
return TriTrue, nil
|
||||
} else {
|
||||
return TriFalse, nil
|
||||
}
|
||||
}
|
||||
|
||||
func TrileanFromBool(b bool) Trilean {
|
||||
if b {
|
||||
return TriTrue
|
||||
}
|
||||
return TriFalse
|
||||
}
|
||||
|
||||
func boolPointer(b bool) *bool {
|
||||
return &b
|
||||
}
|
30
helper/config/custom_types_test.go
Normal file
30
helper/config/custom_types_test.go
Normal file
@ -0,0 +1,30 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTrilianParsing(t *testing.T) {
|
||||
type testCase struct {
|
||||
Input string
|
||||
Output Trilean
|
||||
ErrExpected bool
|
||||
}
|
||||
testCases := []testCase{
|
||||
{"true", TriTrue, false}, {"True", TriTrue, false},
|
||||
{"false", TriFalse, false}, {"False", TriFalse, false},
|
||||
{"", TriUnset, false}, {"badvalue", TriUnset, true},
|
||||
{"FAlse", TriUnset, true}, {"TrUe", TriUnset, true},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
tril, err := TrileanFromString(tc.Input)
|
||||
if err != nil {
|
||||
if tc.ErrExpected == false {
|
||||
t.Fatalf("Didn't expect error: %v", tc)
|
||||
}
|
||||
}
|
||||
if tc.Output != tril {
|
||||
t.Fatalf("Didn't return proper trilean. %v", tc)
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ type DecodeOpts struct {
|
||||
|
||||
var DefaultDecodeHookFuncs = []mapstructure.DecodeHookFunc{
|
||||
uint8ToStringHook,
|
||||
stringToTrilean,
|
||||
mapstructure.StringToSliceHookFunc(","),
|
||||
mapstructure.StringToTimeDurationHookFunc(),
|
||||
}
|
||||
@ -154,3 +155,30 @@ func uint8ToStringHook(f reflect.Kind, t reflect.Kind, v interface{}) (interface
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func stringToTrilean(f reflect.Type, t reflect.Type, v interface{}) (interface{}, error) {
|
||||
// We have a custom data type, config, which we read from a string and
|
||||
// then cast to a *bool. Why? So that we can appropriately read "unset"
|
||||
// *bool values in order to intelligently default, even when the values are
|
||||
// being set by a template variable.
|
||||
|
||||
testTril, _ := TrileanFromString("")
|
||||
if t == reflect.TypeOf(testTril) {
|
||||
// From value is string
|
||||
if f == reflect.TypeOf("") {
|
||||
tril, err := TrileanFromString(v.(string))
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("Error parsing bool from given var: %s", err)
|
||||
}
|
||||
return tril, nil
|
||||
} else {
|
||||
// From value is boolean
|
||||
if f == reflect.TypeOf(true) {
|
||||
tril := TrileanFromBool(v.(bool))
|
||||
return tril, nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ func TestDecode(t *testing.T) {
|
||||
Name string
|
||||
Address string
|
||||
Time time.Duration
|
||||
Trilean Trilean
|
||||
}
|
||||
|
||||
cases := map[string]struct {
|
||||
@ -23,13 +24,27 @@ func TestDecode(t *testing.T) {
|
||||
"basic": {
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "bar",
|
||||
"time": "5s",
|
||||
"name": "bar",
|
||||
"time": "5s",
|
||||
"trilean": "true",
|
||||
},
|
||||
},
|
||||
&Target{
|
||||
Name: "bar",
|
||||
Time: 5 * time.Second,
|
||||
Name: "bar",
|
||||
Time: 5 * time.Second,
|
||||
Trilean: TriTrue,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
|
||||
"empty-string-trilean": {
|
||||
[]interface{}{
|
||||
map[string]interface{}{
|
||||
"trilean": "",
|
||||
},
|
||||
},
|
||||
&Target{
|
||||
Trilean: TriUnset,
|
||||
},
|
||||
nil,
|
||||
},
|
||||
|
@ -398,10 +398,5 @@ func (c *Core) init() error {
|
||||
c.secrets = append(c.secrets, secret)
|
||||
}
|
||||
|
||||
// Interpolate the push configuration
|
||||
if _, err := interpolate.RenderInterface(&c.Template.Push, c.Context()); err != nil {
|
||||
return fmt.Errorf("Error interpolating 'push': %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -427,40 +427,6 @@ func TestCoreBuild_templatePath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCore_pushInterpolate(t *testing.T) {
|
||||
cases := []struct {
|
||||
File string
|
||||
Vars map[string]string
|
||||
Result template.Push
|
||||
}{
|
||||
{
|
||||
"push-vars.json",
|
||||
map[string]string{"foo": "bar"},
|
||||
template.Push{Name: "bar"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tpl, err := template.ParseFile(fixtureDir(tc.File))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s\n\n%s", tc.File, err)
|
||||
}
|
||||
|
||||
core, err := NewCore(&CoreConfig{
|
||||
Template: tpl,
|
||||
Variables: tc.Vars,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s\n\n%s", tc.File, err)
|
||||
}
|
||||
|
||||
expected := core.Template.Push
|
||||
if !reflect.DeepEqual(expected, tc.Result) {
|
||||
t.Fatalf("err: %s\n\n%#v", tc.File, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreValidate(t *testing.T) {
|
||||
cases := []struct {
|
||||
File string
|
||||
|
@ -12,14 +12,15 @@ func testConn(t *testing.T) (net.Conn, net.Conn) {
|
||||
}
|
||||
|
||||
var serverConn net.Conn
|
||||
doneCh := make(chan struct{})
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
defer close(errChan)
|
||||
defer l.Close()
|
||||
var err error
|
||||
serverConn, err = l.Accept()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
@ -27,7 +28,11 @@ func testConn(t *testing.T) (net.Conn, net.Conn) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
<-doneCh
|
||||
|
||||
err = <-errChan
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
return clientConn, serverConn
|
||||
}
|
||||
|
@ -60,18 +60,19 @@ func testYamux(t *testing.T) (client *yamux.Session, server *yamux.Session) {
|
||||
}
|
||||
|
||||
// Server side
|
||||
doneCh := make(chan struct{})
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
defer close(errChan)
|
||||
conn, err := l.Accept()
|
||||
l.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
server, err = yamux.Server(conn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
errChan <- err
|
||||
}
|
||||
}()
|
||||
|
||||
@ -86,7 +87,10 @@ func testYamux(t *testing.T) (client *yamux.Session, server *yamux.Session) {
|
||||
}
|
||||
|
||||
// Wait for the server
|
||||
<-doneCh
|
||||
err = <-errChan
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -19,11 +19,6 @@ import (
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
var builtins = map[string]string{
|
||||
"mitchellh.vmware": "vmware",
|
||||
"mitchellh.vmware-esx": "vmware",
|
||||
}
|
||||
|
||||
var ovftool string = "ovftool"
|
||||
|
||||
var (
|
||||
@ -116,10 +111,6 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
|
||||
}
|
||||
|
||||
func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, bool, error) {
|
||||
if _, ok := builtins[artifact.BuilderId()]; !ok {
|
||||
return nil, false, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
|
||||
}
|
||||
|
||||
source := ""
|
||||
for _, path := range artifact.Files() {
|
||||
if strings.HasSuffix(path, ".vmx") || strings.HasSuffix(path, ".ovf") || strings.HasSuffix(path, ".ova") {
|
||||
|
@ -242,17 +242,6 @@ func (r *rawTemplate) Template() (*Template, error) {
|
||||
result.Provisioners = append(result.Provisioners, &p)
|
||||
}
|
||||
|
||||
// Push
|
||||
if len(r.Push) > 0 {
|
||||
var p Push
|
||||
if err := r.decoder(&p, nil).Decode(r.Push); err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf(
|
||||
"push: %s", err))
|
||||
}
|
||||
|
||||
result.Push = p
|
||||
}
|
||||
|
||||
// If we have errors, return those with a nil result
|
||||
if errs != nil {
|
||||
return nil, errs
|
||||
|
@ -358,15 +358,6 @@ func TestParse(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
"parse-push.json",
|
||||
&Template{
|
||||
Push: Push{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"parse-comment.json",
|
||||
&Template{
|
||||
@ -480,9 +471,6 @@ func TestParse(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
Push: Push{
|
||||
Name: "push test",
|
||||
},
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
@ -25,7 +25,6 @@ type Template struct {
|
||||
Builders map[string]*Builder
|
||||
Provisioners []*Provisioner
|
||||
PostProcessors [][]*PostProcessor
|
||||
Push Push
|
||||
|
||||
// RawContents is just the raw data for this template
|
||||
RawContents []byte
|
||||
@ -66,15 +65,6 @@ func (t *Template) Raw() (*rawTemplate, error) {
|
||||
out.Variables[k] = v
|
||||
}
|
||||
|
||||
if t.Push.Name != "" {
|
||||
b, _ := json.Marshal(t.Push)
|
||||
|
||||
var m map[string]interface{}
|
||||
_ = json.Unmarshal(b, &m)
|
||||
|
||||
out.Push = m
|
||||
}
|
||||
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"push": {
|
||||
"name": "foo"
|
||||
}
|
||||
}
|
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
@ -1,15 +0,0 @@
|
||||
# This is the official list of cloud authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Google Inc.
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
Palm Stone Games, Inc.
|
||||
Paweł Knap <pawelknap88@gmail.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
40
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
40
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
@ -1,40 +0,0 @@
|
||||
# People who have agreed to one of the CLAs and can contribute patches.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# https://developers.google.com/open-source/cla/individual
|
||||
# https://developers.google.com/open-source/cla/corporate
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name <email address>
|
||||
|
||||
# Keep the list alphabetically sorted.
|
||||
|
||||
Alexis Hunt <lexer@google.com>
|
||||
Andreas Litt <andreas.litt@gmail.com>
|
||||
Andrew Gerrand <adg@golang.org>
|
||||
Brad Fitzpatrick <bradfitz@golang.org>
|
||||
Burcu Dogan <jbd@google.com>
|
||||
Dave Day <djd@golang.org>
|
||||
David Sansome <me@davidsansome.com>
|
||||
David Symonds <dsymonds@golang.org>
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Glenn Lewis <gmlewis@google.com>
|
||||
Ingo Oeser <nightlyone@googlemail.com>
|
||||
James Hall <james.hall@shopify.com>
|
||||
Johan Euphrosine <proppy@google.com>
|
||||
Jonathan Amsterdam <jba@google.com>
|
||||
Kunpei Sakai <namusyaka@gmail.com>
|
||||
Luna Duclos <luna.duclos@palmstonegames.com>
|
||||
Magnus Hiie <magnus.hiie@gmail.com>
|
||||
Mario Castro <mariocaster@gmail.com>
|
||||
Michael McGreevy <mcgreevy@golang.org>
|
||||
Omar Jarjur <ojarjur@google.com>
|
||||
Paweł Knap <pawelknap88@gmail.com>
|
||||
Péter Szilágyi <peterke@gmail.com>
|
||||
Sarah Adams <shadams@google.com>
|
||||
Thanatat Tamtan <acoshift@gmail.com>
|
||||
Toby Burress <kurin@google.com>
|
||||
Tuo Shan <shantuo@google.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
13
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
13
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
@ -227,6 +227,9 @@ func InternalIP() (string, error) { return defaultClient.InternalIP() }
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
|
||||
|
||||
// Email calls Client.Email on the default client.
|
||||
func Email(serviceAccount string) (string, error) { return defaultClient.Email(serviceAccount) }
|
||||
|
||||
// Hostname returns the instance's hostname. This will be of the form
|
||||
// "<instanceID>.c.<projID>.internal".
|
||||
func Hostname() (string, error) { return defaultClient.Hostname() }
|
||||
@ -367,6 +370,16 @@ func (c *Client) InternalIP() (string, error) {
|
||||
return c.getTrimmed("instance/network-interfaces/0/ip")
|
||||
}
|
||||
|
||||
// Email returns the email address associated with the service account.
|
||||
// The account may be empty or the string "default" to use the instance's
|
||||
// main account.
|
||||
func (c *Client) Email(serviceAccount string) (string, error) {
|
||||
if serviceAccount == "" {
|
||||
serviceAccount = "default"
|
||||
}
|
||||
return c.getTrimmed("instance/service-accounts/" + serviceAccount + "/email")
|
||||
}
|
||||
|
||||
// ExternalIP returns the instance's primary external (public) IP address.
|
||||
func (c *Client) ExternalIP() (string, error) {
|
||||
return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||
|
29
vendor/cloud.google.com/go/internal/trace/trace.go
generated
vendored
29
vendor/cloud.google.com/go/internal/trace/trace.go
generated
vendored
@ -16,6 +16,7 @@ package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
"google.golang.org/api/googleapi"
|
||||
@ -38,7 +39,7 @@ func EndSpan(ctx context.Context, err error) {
|
||||
span.End()
|
||||
}
|
||||
|
||||
// ToStatus interrogates an error and converts it to an appropriate
|
||||
// toStatus interrogates an error and converts it to an appropriate
|
||||
// OpenCensus status.
|
||||
func toStatus(err error) trace.Status {
|
||||
if err2, ok := err.(*googleapi.Error); ok {
|
||||
@ -50,7 +51,7 @@ func toStatus(err error) trace.Status {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (deklerk): switch to using OpenCensus function when it becomes available.
|
||||
// TODO(deklerk): switch to using OpenCensus function when it becomes available.
|
||||
// Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto
|
||||
func httpStatusCodeToOCCode(httpStatusCode int) int32 {
|
||||
switch httpStatusCode {
|
||||
@ -82,3 +83,27 @@ func httpStatusCodeToOCCode(httpStatusCode int) int32 {
|
||||
return int32(code.Code_UNKNOWN)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: (odeke-em): perhaps just pass around spans due to the cost
|
||||
// incurred from using trace.FromContext(ctx) yet we could avoid
|
||||
// throwing away the work done by ctx, span := trace.StartSpan.
|
||||
func TracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) {
|
||||
var attrs []trace.Attribute
|
||||
for k, v := range attrMap {
|
||||
var a trace.Attribute
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
a = trace.StringAttribute(k, v)
|
||||
case bool:
|
||||
a = trace.BoolAttribute(k, v)
|
||||
case int:
|
||||
a = trace.Int64Attribute(k, int64(v))
|
||||
case int64:
|
||||
a = trace.Int64Attribute(k, v)
|
||||
default:
|
||||
a = trace.StringAttribute(k, fmt.Sprintf("%#v", v))
|
||||
}
|
||||
attrs = append(attrs, a)
|
||||
}
|
||||
trace.FromContext(ctx).Annotatef(attrs, format, args...)
|
||||
}
|
||||
|
13
vendor/cloud.google.com/go/internal/version/update_version.sh
generated
vendored
13
vendor/cloud.google.com/go/internal/version/update_version.sh
generated
vendored
@ -1,4 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2019 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
today=$(date +%Y%m%d)
|
||||
|
||||
|
2
vendor/cloud.google.com/go/internal/version/version.go
generated
vendored
2
vendor/cloud.google.com/go/internal/version/version.go
generated
vendored
@ -26,7 +26,7 @@ import (
|
||||
|
||||
// Repo is the current version of the client libraries in this
|
||||
// repo. It should be a date in YYYYMMDD format.
|
||||
const Repo = "20180226"
|
||||
const Repo = "20190802"
|
||||
|
||||
// Go returns the Go runtime version. The returned string
|
||||
// has no whitespace.
|
||||
|
32
vendor/cloud.google.com/go/storage/README.md
generated
vendored
Normal file
32
vendor/cloud.google.com/go/storage/README.md
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
## Cloud Storage [](https://godoc.org/cloud.google.com/go/storage)
|
||||
|
||||
- [About Cloud Storage](https://cloud.google.com/storage/)
|
||||
- [API documentation](https://cloud.google.com/storage/docs)
|
||||
- [Go client documentation](https://godoc.org/cloud.google.com/go/storage)
|
||||
- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage)
|
||||
|
||||
### Example Usage
|
||||
|
||||
First create a `storage.Client` to use throughout your application:
|
||||
|
||||
[snip]:# (storage-1)
|
||||
```go
|
||||
client, err := storage.NewClient(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
[snip]:# (storage-2)
|
||||
```go
|
||||
// Read the object1 from bucket.
|
||||
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rc.Close()
|
||||
body, err := ioutil.ReadAll(rc)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
14
vendor/cloud.google.com/go/storage/bucket.go
generated
vendored
14
vendor/cloud.google.com/go/storage/bucket.go
generated
vendored
@ -272,6 +272,9 @@ type BucketAttrs struct {
|
||||
// "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which
|
||||
// is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on
|
||||
// the bucket's location settings.
|
||||
//
|
||||
// "DURABLE_REDUCED_AVAILABILITY", "MULTI_REGIONAL" and "REGIONAL"
|
||||
// are considered legacy storage classes.
|
||||
StorageClass string
|
||||
|
||||
// Created is the creation time of the bucket.
|
||||
@ -313,6 +316,15 @@ type BucketAttrs struct {
|
||||
|
||||
// The website configuration.
|
||||
Website *BucketWebsite
|
||||
|
||||
// Etag is the HTTP/1.1 Entity tag for the bucket.
|
||||
// This field is read-only.
|
||||
Etag string
|
||||
|
||||
// LocationType describes how data is stored and replicated.
|
||||
// Typical values are "multi-region", "region" and "dual-region".
|
||||
// This field is read-only.
|
||||
LocationType string
|
||||
}
|
||||
|
||||
// BucketPolicyOnly configures access checks to use only bucket-level IAM
|
||||
@ -501,6 +513,8 @@ func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
|
||||
Logging: toBucketLogging(b.Logging),
|
||||
Website: toBucketWebsite(b.Website),
|
||||
BucketPolicyOnly: toBucketPolicyOnly(b.IamConfiguration),
|
||||
Etag: b.Etag,
|
||||
LocationType: b.LocationType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
330
vendor/cloud.google.com/go/storage/hmac.go
generated
vendored
Normal file
330
vendor/cloud.google.com/go/storage/hmac.go
generated
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"google.golang.org/api/iterator"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
)
|
||||
|
||||
// HMACState is the state of the HMAC key.
|
||||
type HMACState string
|
||||
|
||||
const (
|
||||
// Active is the status for an active key that can be used to sign
|
||||
// requests.
|
||||
Active HMACState = "ACTIVE"
|
||||
|
||||
// Inactive is the status for an inactive key thus requests signed by
|
||||
// this key will be denied.
|
||||
Inactive HMACState = "INACTIVE"
|
||||
|
||||
// Deleted is the status for a key that is deleted.
|
||||
// Once in this state the key cannot key cannot be recovered
|
||||
// and does not count towards key limits. Deleted keys will be cleaned
|
||||
// up later.
|
||||
Deleted HMACState = "DELETED"
|
||||
)
|
||||
|
||||
// HMACKey is the representation of a Google Cloud Storage HMAC key.
|
||||
//
|
||||
// HMAC keys are used to authenticate signed access to objects. To enable HMAC key
|
||||
// authentication, please visit https://cloud.google.com/storage/docs/migrating.
|
||||
//
|
||||
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||
type HMACKey struct {
|
||||
// The HMAC's secret key.
|
||||
Secret string
|
||||
|
||||
// AccessID is the ID of the HMAC key.
|
||||
AccessID string
|
||||
|
||||
// Etag is the HTTP/1.1 Entity tag.
|
||||
Etag string
|
||||
|
||||
// ID is the ID of the HMAC key, including the ProjectID and AccessID.
|
||||
ID string
|
||||
|
||||
// ProjectID is the ID of the project that owns the
|
||||
// service account to which the key authenticates.
|
||||
ProjectID string
|
||||
|
||||
// ServiceAccountEmail is the email address
|
||||
// of the key's associated service account.
|
||||
ServiceAccountEmail string
|
||||
|
||||
// CreatedTime is the creation time of the HMAC key.
|
||||
CreatedTime time.Time
|
||||
|
||||
// UpdatedTime is the last modification time of the HMAC key metadata.
|
||||
UpdatedTime time.Time
|
||||
|
||||
// State is the state of the HMAC key.
|
||||
// It can be one of StateActive, StateInactive or StateDeleted.
|
||||
State HMACState
|
||||
}
|
||||
|
||||
// HMACKeyHandle helps provide access and management for HMAC keys.
|
||||
//
|
||||
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||
type HMACKeyHandle struct {
|
||||
projectID string
|
||||
accessID string
|
||||
|
||||
raw *raw.ProjectsHmacKeysService
|
||||
}
|
||||
|
||||
// HMACKeyHandle creates a handle that will be used for HMACKey operations.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (c *Client) HMACKeyHandle(projectID, accessID string) *HMACKeyHandle {
|
||||
return &HMACKeyHandle{
|
||||
projectID: projectID,
|
||||
accessID: accessID,
|
||||
raw: raw.NewProjectsHmacKeysService(c.raw),
|
||||
}
|
||||
}
|
||||
|
||||
// Get invokes an RPC to retrieve the HMAC key referenced by the
|
||||
// HMACKeyHandle's accessID.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (hkh *HMACKeyHandle) Get(ctx context.Context) (*HMACKey, error) {
|
||||
call := hkh.raw.Get(hkh.projectID, hkh.accessID)
|
||||
setClientHeader(call.Header())
|
||||
|
||||
var metadata *raw.HmacKeyMetadata
|
||||
var err error
|
||||
err = runWithRetry(ctx, func() error {
|
||||
metadata, err = call.Context(ctx).Do()
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hkPb := &raw.HmacKey{
|
||||
Metadata: metadata,
|
||||
}
|
||||
return pbHmacKeyToHMACKey(hkPb, false)
|
||||
}
|
||||
|
||||
// Delete invokes an RPC to delete the key referenced by accessID, on Google Cloud Storage.
|
||||
// Only inactive HMAC keys can be deleted.
|
||||
// After deletion, a key cannot be used to authenticate requests.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (hkh *HMACKeyHandle) Delete(ctx context.Context) error {
|
||||
delCall := hkh.raw.Delete(hkh.projectID, hkh.accessID)
|
||||
setClientHeader(delCall.Header())
|
||||
|
||||
return runWithRetry(ctx, func() error {
|
||||
return delCall.Context(ctx).Do()
|
||||
})
|
||||
}
|
||||
|
||||
func pbHmacKeyToHMACKey(pb *raw.HmacKey, updatedTimeCanBeNil bool) (*HMACKey, error) {
|
||||
pbmd := pb.Metadata
|
||||
if pbmd == nil {
|
||||
return nil, errors.New("field Metadata cannot be nil")
|
||||
}
|
||||
createdTime, err := time.Parse(time.RFC3339, pbmd.TimeCreated)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field CreatedTime: %v", err)
|
||||
}
|
||||
updatedTime, err := time.Parse(time.RFC3339, pbmd.Updated)
|
||||
if err != nil && !updatedTimeCanBeNil {
|
||||
return nil, fmt.Errorf("field UpdatedTime: %v", err)
|
||||
}
|
||||
|
||||
hmk := &HMACKey{
|
||||
AccessID: pbmd.AccessId,
|
||||
Secret: pb.Secret,
|
||||
Etag: pbmd.Etag,
|
||||
ID: pbmd.Id,
|
||||
State: HMACState(pbmd.State),
|
||||
ProjectID: pbmd.ProjectId,
|
||||
CreatedTime: createdTime,
|
||||
UpdatedTime: updatedTime,
|
||||
|
||||
ServiceAccountEmail: pbmd.ServiceAccountEmail,
|
||||
}
|
||||
|
||||
return hmk, nil
|
||||
}
|
||||
|
||||
// CreateHMACKey invokes an RPC for Google Cloud Storage to create a new HMACKey.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (c *Client) CreateHMACKey(ctx context.Context, projectID, serviceAccountEmail string) (*HMACKey, error) {
|
||||
if projectID == "" {
|
||||
return nil, errors.New("storage: expecting a non-blank projectID")
|
||||
}
|
||||
if serviceAccountEmail == "" {
|
||||
return nil, errors.New("storage: expecting a non-blank service account email")
|
||||
}
|
||||
|
||||
svc := raw.NewProjectsHmacKeysService(c.raw)
|
||||
call := svc.Create(projectID, serviceAccountEmail)
|
||||
setClientHeader(call.Header())
|
||||
|
||||
var hkPb *raw.HmacKey
|
||||
var err error
|
||||
err = runWithRetry(ctx, func() error {
|
||||
hkPb, err = call.Context(ctx).Do()
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pbHmacKeyToHMACKey(hkPb, true)
|
||||
}
|
||||
|
||||
// HMACKeyAttrsToUpdate defines the attributes of an HMACKey that will be updated.
|
||||
//
|
||||
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||
type HMACKeyAttrsToUpdate struct {
|
||||
// State is required and must be either StateActive or StateInactive.
|
||||
State HMACState
|
||||
|
||||
// Etag is an optional field and it is the HTTP/1.1 Entity tag.
|
||||
Etag string
|
||||
}
|
||||
|
||||
// Update mutates the HMACKey referred to by accessID.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (h *HMACKeyHandle) Update(ctx context.Context, au HMACKeyAttrsToUpdate) (*HMACKey, error) {
|
||||
if au.State != Active && au.State != Inactive {
|
||||
return nil, fmt.Errorf("storage: invalid state %q for update, must be either %q or %q", au.State, Active, Inactive)
|
||||
}
|
||||
|
||||
call := h.raw.Update(h.projectID, h.accessID, &raw.HmacKeyMetadata{
|
||||
Etag: au.Etag,
|
||||
State: string(au.State),
|
||||
})
|
||||
setClientHeader(call.Header())
|
||||
|
||||
var metadata *raw.HmacKeyMetadata
|
||||
var err error
|
||||
err = runWithRetry(ctx, func() error {
|
||||
metadata, err = call.Context(ctx).Do()
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hkPb := &raw.HmacKey{
|
||||
Metadata: metadata,
|
||||
}
|
||||
return pbHmacKeyToHMACKey(hkPb, false)
|
||||
}
|
||||
|
||||
// An HMACKeysIterator is an iterator over HMACKeys.
|
||||
//
|
||||
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||
type HMACKeysIterator struct {
|
||||
ctx context.Context
|
||||
raw *raw.ProjectsHmacKeysService
|
||||
projectID string
|
||||
hmacKeys []*HMACKey
|
||||
pageInfo *iterator.PageInfo
|
||||
nextFunc func() error
|
||||
index int
|
||||
}
|
||||
|
||||
// ListHMACKeys returns an iterator for listing HMACKeys.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (c *Client) ListHMACKeys(ctx context.Context, projectID string) *HMACKeysIterator {
|
||||
it := &HMACKeysIterator{
|
||||
ctx: ctx,
|
||||
raw: raw.NewProjectsHmacKeysService(c.raw),
|
||||
projectID: projectID,
|
||||
}
|
||||
|
||||
it.pageInfo, it.nextFunc = iterator.NewPageInfo(
|
||||
it.fetch,
|
||||
func() int { return len(it.hmacKeys) - it.index },
|
||||
func() interface{} {
|
||||
prev := it.hmacKeys
|
||||
it.hmacKeys = it.hmacKeys[:0]
|
||||
it.index = 0
|
||||
return prev
|
||||
})
|
||||
return it
|
||||
}
|
||||
|
||||
// Next returns the next result. Its second return value is iterator.Done if
|
||||
// there are no more results. Once Next returns iterator.Done, all subsequent
|
||||
// calls will return iterator.Done.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (it *HMACKeysIterator) Next() (*HMACKey, error) {
|
||||
if err := it.nextFunc(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := it.hmacKeys[it.index]
|
||||
it.index++
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||
//
|
||||
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||
func (it *HMACKeysIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
|
||||
|
||||
func (it *HMACKeysIterator) fetch(pageSize int, pageToken string) (token string, err error) {
|
||||
call := it.raw.List(it.projectID)
|
||||
setClientHeader(call.Header())
|
||||
call = call.PageToken(pageToken)
|
||||
// By default we'll also show deleted keys and then
|
||||
// let users filter on their own.
|
||||
call = call.ShowDeletedKeys(true)
|
||||
if pageSize > 0 {
|
||||
call = call.MaxResults(int64(pageSize))
|
||||
}
|
||||
|
||||
ctx := it.ctx
|
||||
var resp *raw.HmacKeysMetadata
|
||||
err = runWithRetry(it.ctx, func() error {
|
||||
resp, err = call.Context(ctx).Do()
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, metadata := range resp.Items {
|
||||
hkPb := &raw.HmacKey{
|
||||
Metadata: metadata,
|
||||
}
|
||||
hkey, err := pbHmacKeyToHMACKey(hkPb, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
it.hmacKeys = append(it.hmacKeys, hkey)
|
||||
}
|
||||
return resp.NextPageToken, nil
|
||||
}
|
38
vendor/cloud.google.com/go/storage/reader.go
generated
vendored
38
vendor/cloud.google.com/go/storage/reader.go
generated
vendored
@ -43,6 +43,11 @@ type ReaderObjectAttrs struct {
|
||||
// Size is the length of the object's content.
|
||||
Size int64
|
||||
|
||||
// StartOffset is the byte offset within the object
|
||||
// from which reading begins.
|
||||
// This value is only non-zero for range requests.
|
||||
StartOffset int64
|
||||
|
||||
// ContentType is the MIME type of the object's content.
|
||||
ContentType string
|
||||
|
||||
@ -78,7 +83,9 @@ func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) {
|
||||
|
||||
// NewRangeReader reads part of an object, reading at most length bytes
|
||||
// starting at the given offset. If length is negative, the object is read
|
||||
// until the end.
|
||||
// until the end. If offset is negative, the object is read abs(offset) bytes
|
||||
// from the end, and length must also be negative to indicate all remaining
|
||||
// bytes will be read.
|
||||
func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (r *Reader, err error) {
|
||||
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.NewRangeReader")
|
||||
defer func() { trace.EndSpan(ctx, err) }()
|
||||
@ -86,8 +93,8 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
||||
if err := o.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if offset < 0 {
|
||||
return nil, fmt.Errorf("storage: invalid offset %d < 0", offset)
|
||||
if offset < 0 && length >= 0 {
|
||||
return nil, fmt.Errorf("storage: invalid offset %d < 0 requires negative length", offset)
|
||||
}
|
||||
if o.conds != nil {
|
||||
if err := o.conds.validate("NewRangeReader"); err != nil {
|
||||
@ -95,8 +102,8 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
||||
}
|
||||
}
|
||||
u := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "storage.googleapis.com",
|
||||
Scheme: o.c.scheme,
|
||||
Host: o.c.readHost,
|
||||
Path: fmt.Sprintf("/%s/%s", o.bucket, o.object),
|
||||
}
|
||||
verb := "GET"
|
||||
@ -124,7 +131,9 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
||||
// have already read seen bytes.
|
||||
reopen := func(seen int64) (*http.Response, error) {
|
||||
start := offset + seen
|
||||
if length < 0 && start > 0 {
|
||||
if length < 0 && start < 0 {
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d", start))
|
||||
} else if length < 0 && start > 0 {
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", start))
|
||||
} else if length > 0 {
|
||||
// The end character isn't affected by how many bytes we've seen.
|
||||
@ -177,20 +186,28 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
size int64 // total size of object, even if a range was requested.
|
||||
checkCRC bool
|
||||
crc uint32
|
||||
size int64 // total size of object, even if a range was requested.
|
||||
checkCRC bool
|
||||
crc uint32
|
||||
startOffset int64 // non-zero if range request.
|
||||
)
|
||||
if res.StatusCode == http.StatusPartialContent {
|
||||
cr := strings.TrimSpace(res.Header.Get("Content-Range"))
|
||||
if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") {
|
||||
|
||||
return nil, fmt.Errorf("storage: invalid Content-Range %q", cr)
|
||||
}
|
||||
size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("storage: invalid Content-Range %q", cr)
|
||||
}
|
||||
|
||||
dashIndex := strings.Index(cr, "-")
|
||||
if dashIndex >= 0 {
|
||||
startOffset, err = strconv.ParseInt(cr[len("bytes="):dashIndex], 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("storage: invalid Content-Range %q: %v", cr, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size = res.ContentLength
|
||||
// Check the CRC iff all of the following hold:
|
||||
@ -236,6 +253,7 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
||||
ContentEncoding: res.Header.Get("Content-Encoding"),
|
||||
CacheControl: res.Header.Get("Cache-Control"),
|
||||
LastModified: lm,
|
||||
StartOffset: startOffset,
|
||||
Generation: gen,
|
||||
Metageneration: metaGen,
|
||||
}
|
||||
|
314
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
314
vendor/cloud.google.com/go/storage/storage.go
generated
vendored
@ -23,11 +23,13 @@ import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
@ -81,6 +83,12 @@ func setClientHeader(headers http.Header) {
|
||||
type Client struct {
|
||||
hc *http.Client
|
||||
raw *raw.Service
|
||||
// Scheme describes the scheme under the current host.
|
||||
scheme string
|
||||
// EnvHost is the host set on the STORAGE_EMULATOR_HOST variable.
|
||||
envHost string
|
||||
// ReadHost is the default host used on the reader.
|
||||
readHost string
|
||||
}
|
||||
|
||||
// NewClient creates a new Google Cloud Storage client.
|
||||
@ -102,9 +110,20 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
||||
if ep != "" {
|
||||
rawService.BasePath = ep
|
||||
}
|
||||
scheme := "https"
|
||||
var host, readHost string
|
||||
if host = os.Getenv("STORAGE_EMULATOR_HOST"); host != "" {
|
||||
scheme = "http"
|
||||
readHost = host
|
||||
} else {
|
||||
readHost = "storage.googleapis.com"
|
||||
}
|
||||
return &Client{
|
||||
hc: hc,
|
||||
raw: rawService,
|
||||
hc: hc,
|
||||
raw: rawService,
|
||||
scheme: scheme,
|
||||
envHost: host,
|
||||
readHost: readHost,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -118,6 +137,20 @@ func (c *Client) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SigningScheme determines the API version to use when signing URLs.
|
||||
type SigningScheme int
|
||||
|
||||
const (
|
||||
// SigningSchemeDefault is presently V2 and will change to V4 in the future.
|
||||
SigningSchemeDefault SigningScheme = iota
|
||||
|
||||
// SigningSchemeV2 uses the V2 scheme to sign URLs.
|
||||
SigningSchemeV2
|
||||
|
||||
// SigningSchemeV4 uses the V4 scheme to sign URLs.
|
||||
SigningSchemeV4
|
||||
)
|
||||
|
||||
// SignedURLOptions allows you to restrict the access to the signed URL.
|
||||
type SignedURLOptions struct {
|
||||
// GoogleAccessID represents the authorizer of the signed URL generation.
|
||||
@ -140,8 +173,9 @@ type SignedURLOptions struct {
|
||||
// Exactly one of PrivateKey or SignBytes must be non-nil.
|
||||
PrivateKey []byte
|
||||
|
||||
// SignBytes is a function for implementing custom signing.
|
||||
// If your application is running on Google App Engine, you can use appengine's internal signing function:
|
||||
// SignBytes is a function for implementing custom signing. For example, if
|
||||
// your application is running on Google App Engine, you can use
|
||||
// appengine's internal signing function:
|
||||
// ctx := appengine.NewContext(request)
|
||||
// acc, _ := appengine.ServiceAccount(ctx)
|
||||
// url, err := SignedURL("bucket", "object", &SignedURLOptions{
|
||||
@ -162,7 +196,8 @@ type SignedURLOptions struct {
|
||||
Method string
|
||||
|
||||
// Expires is the expiration time on the signed URL. It must be
|
||||
// a datetime in the future.
|
||||
// a datetime in the future. For SigningSchemeV4, the expiration may be no
|
||||
// more than seven days in the future.
|
||||
// Required.
|
||||
Expires time.Time
|
||||
|
||||
@ -181,9 +216,17 @@ type SignedURLOptions struct {
|
||||
// header in order to use the signed URL.
|
||||
// Optional.
|
||||
MD5 string
|
||||
|
||||
// Scheme determines the version of URL signing to use. Default is
|
||||
// SigningSchemeV2.
|
||||
Scheme SigningScheme
|
||||
}
|
||||
|
||||
var (
|
||||
tabRegex = regexp.MustCompile(`[\t]+`)
|
||||
// I was tempted to call this spacex. :)
|
||||
spaceRegex = regexp.MustCompile(` +`)
|
||||
|
||||
canonicalHeaderRegexp = regexp.MustCompile(`(?i)^(x-goog-[^:]+):(.*)?$`)
|
||||
excludedCanonicalHeaders = map[string]bool{
|
||||
"x-goog-encryption-key": true,
|
||||
@ -191,26 +234,31 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// sanitizeHeaders applies the specifications for canonical extension headers at
|
||||
// v2SanitizeHeaders applies the specifications for canonical extension headers at
|
||||
// https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers.
|
||||
func sanitizeHeaders(hdrs []string) []string {
|
||||
func v2SanitizeHeaders(hdrs []string) []string {
|
||||
headerMap := map[string][]string{}
|
||||
for _, hdr := range hdrs {
|
||||
// No leading or trailing whitespaces.
|
||||
sanitizedHeader := strings.TrimSpace(hdr)
|
||||
|
||||
var header, value string
|
||||
// Only keep canonical headers, discard any others.
|
||||
headerMatches := canonicalHeaderRegexp.FindStringSubmatch(sanitizedHeader)
|
||||
if len(headerMatches) == 0 {
|
||||
continue
|
||||
}
|
||||
header = headerMatches[1]
|
||||
value = headerMatches[2]
|
||||
|
||||
header := strings.ToLower(strings.TrimSpace(headerMatches[1]))
|
||||
if excludedCanonicalHeaders[headerMatches[1]] {
|
||||
header = strings.ToLower(strings.TrimSpace(header))
|
||||
value = strings.TrimSpace(value)
|
||||
|
||||
if excludedCanonicalHeaders[header] {
|
||||
// Do not keep any deliberately excluded canonical headers when signing.
|
||||
continue
|
||||
}
|
||||
value := strings.TrimSpace(headerMatches[2])
|
||||
|
||||
if len(value) > 0 {
|
||||
// Remove duplicate headers by appending the values of duplicates
|
||||
// in their order of appearance.
|
||||
@ -220,51 +268,256 @@ func sanitizeHeaders(hdrs []string) []string {
|
||||
|
||||
var sanitizedHeaders []string
|
||||
for header, values := range headerMap {
|
||||
// There should be no spaces around the colon separating the
|
||||
// header name from the header value or around the values
|
||||
// themselves. The values should be separated by commas.
|
||||
// There should be no spaces around the colon separating the header name
|
||||
// from the header value or around the values themselves. The values
|
||||
// should be separated by commas.
|
||||
//
|
||||
// NOTE: The semantics for headers without a value are not clear.
|
||||
// However from specifications these should be edge-cases
|
||||
// anyway and we should assume that there will be no
|
||||
// canonical headers using empty values. Any such headers
|
||||
// are discarded at the regexp stage above.
|
||||
sanitizedHeaders = append(
|
||||
sanitizedHeaders,
|
||||
fmt.Sprintf("%s:%s", header, strings.Join(values, ",")),
|
||||
)
|
||||
// However from specifications these should be edge-cases anyway and we
|
||||
// should assume that there will be no canonical headers using empty
|
||||
// values. Any such headers are discarded at the regexp stage above.
|
||||
sanitizedHeaders = append(sanitizedHeaders, fmt.Sprintf("%s:%s", header, strings.Join(values, ",")))
|
||||
}
|
||||
sort.Strings(sanitizedHeaders)
|
||||
return sanitizedHeaders
|
||||
}
|
||||
|
||||
// v4SanitizeHeaders applies the specifications for canonical extension headers
|
||||
// at https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers.
|
||||
//
|
||||
// V4 does a couple things differently from V2:
|
||||
// - Headers get sorted by key, instead of by key:value. We do this in
|
||||
// signedURLV4.
|
||||
// - There's no canonical regexp: we simply split headers on :.
|
||||
// - We don't exclude canonical headers.
|
||||
// - We replace leading and trailing spaces in header values, like v2, but also
|
||||
// all intermediate space duplicates get stripped. That is, there's only ever
|
||||
// a single consecutive space.
|
||||
func v4SanitizeHeaders(hdrs []string) []string {
|
||||
headerMap := map[string][]string{}
|
||||
for _, hdr := range hdrs {
|
||||
// No leading or trailing whitespaces.
|
||||
sanitizedHeader := strings.TrimSpace(hdr)
|
||||
|
||||
var key, value string
|
||||
headerMatches := strings.Split(sanitizedHeader, ":")
|
||||
if len(headerMatches) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
key = headerMatches[0]
|
||||
value = headerMatches[1]
|
||||
|
||||
key = strings.ToLower(strings.TrimSpace(key))
|
||||
value = strings.TrimSpace(value)
|
||||
value = string(spaceRegex.ReplaceAll([]byte(value), []byte(" ")))
|
||||
value = string(tabRegex.ReplaceAll([]byte(value), []byte("\t")))
|
||||
|
||||
if len(value) > 0 {
|
||||
// Remove duplicate headers by appending the values of duplicates
|
||||
// in their order of appearance.
|
||||
headerMap[key] = append(headerMap[key], value)
|
||||
}
|
||||
}
|
||||
|
||||
var sanitizedHeaders []string
|
||||
for header, values := range headerMap {
|
||||
// There should be no spaces around the colon separating the header name
|
||||
// from the header value or around the values themselves. The values
|
||||
// should be separated by commas.
|
||||
//
|
||||
// NOTE: The semantics for headers without a value are not clear.
|
||||
// However from specifications these should be edge-cases anyway and we
|
||||
// should assume that there will be no canonical headers using empty
|
||||
// values. Any such headers are discarded at the regexp stage above.
|
||||
sanitizedHeaders = append(sanitizedHeaders, fmt.Sprintf("%s:%s", header, strings.Join(values, ",")))
|
||||
}
|
||||
return sanitizedHeaders
|
||||
}
|
||||
|
||||
// SignedURL returns a URL for the specified object. Signed URLs allow
|
||||
// the users access to a restricted resource for a limited time without having a
|
||||
// Google account or signing in. For more information about the signed
|
||||
// URLs, see https://cloud.google.com/storage/docs/accesscontrol#Signed-URLs.
|
||||
func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) {
|
||||
now := utcNow()
|
||||
if err := validateOptions(opts, now); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch opts.Scheme {
|
||||
case SigningSchemeV2:
|
||||
opts.Headers = v2SanitizeHeaders(opts.Headers)
|
||||
return signedURLV2(bucket, name, opts)
|
||||
case SigningSchemeV4:
|
||||
opts.Headers = v4SanitizeHeaders(opts.Headers)
|
||||
return signedURLV4(bucket, name, opts, now)
|
||||
default: // SigningSchemeDefault
|
||||
opts.Headers = v2SanitizeHeaders(opts.Headers)
|
||||
return signedURLV2(bucket, name, opts)
|
||||
}
|
||||
}
|
||||
|
||||
func validateOptions(opts *SignedURLOptions, now time.Time) error {
|
||||
if opts == nil {
|
||||
return "", errors.New("storage: missing required SignedURLOptions")
|
||||
return errors.New("storage: missing required SignedURLOptions")
|
||||
}
|
||||
if opts.GoogleAccessID == "" {
|
||||
return "", errors.New("storage: missing required GoogleAccessID")
|
||||
return errors.New("storage: missing required GoogleAccessID")
|
||||
}
|
||||
if (opts.PrivateKey == nil) == (opts.SignBytes == nil) {
|
||||
return "", errors.New("storage: exactly one of PrivateKey or SignedBytes must be set")
|
||||
return errors.New("storage: exactly one of PrivateKey or SignedBytes must be set")
|
||||
}
|
||||
if opts.Method == "" {
|
||||
return "", errors.New("storage: missing required method option")
|
||||
return errors.New("storage: missing required method option")
|
||||
}
|
||||
if opts.Expires.IsZero() {
|
||||
return "", errors.New("storage: missing required expires option")
|
||||
return errors.New("storage: missing required expires option")
|
||||
}
|
||||
if opts.MD5 != "" {
|
||||
md5, err := base64.StdEncoding.DecodeString(opts.MD5)
|
||||
if err != nil || len(md5) != 16 {
|
||||
return "", errors.New("storage: invalid MD5 checksum")
|
||||
return errors.New("storage: invalid MD5 checksum")
|
||||
}
|
||||
}
|
||||
opts.Headers = sanitizeHeaders(opts.Headers)
|
||||
if opts.Scheme == SigningSchemeV4 {
|
||||
cutoff := now.Add(604801 * time.Second) // 7 days + 1 second
|
||||
if !opts.Expires.Before(cutoff) {
|
||||
return errors.New("storage: expires must be within seven days from now")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
iso8601 = "20060102T150405Z"
|
||||
yearMonthDay = "20060102"
|
||||
)
|
||||
|
||||
// utcNow returns the current time in UTC and is a variable to allow for
|
||||
// reassignment in tests to provide deterministic signed URL values.
|
||||
var utcNow = func() time.Time {
|
||||
return time.Now().UTC()
|
||||
}
|
||||
|
||||
// extractHeaderNames takes in a series of key:value headers and returns the
|
||||
// header names only.
|
||||
func extractHeaderNames(kvs []string) []string {
|
||||
var res []string
|
||||
for _, header := range kvs {
|
||||
nameValue := strings.Split(header, ":")
|
||||
res = append(res, nameValue[0])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// signedURLV4 creates a signed URL using the sigV4 algorithm.
|
||||
func signedURLV4(bucket, name string, opts *SignedURLOptions, now time.Time) (string, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
fmt.Fprintf(buf, "%s\n", opts.Method)
|
||||
u := &url.URL{Path: bucket}
|
||||
if name != "" {
|
||||
u.Path += "/" + name
|
||||
}
|
||||
|
||||
// Note: we have to add a / here because GCS does so auto-magically, despite
|
||||
// Go's EscapedPath not doing so (and we have to exactly match their
|
||||
// canonical query).
|
||||
fmt.Fprintf(buf, "/%s\n", u.EscapedPath())
|
||||
|
||||
headerNames := append(extractHeaderNames(opts.Headers), "host")
|
||||
if opts.ContentType != "" {
|
||||
headerNames = append(headerNames, "content-type")
|
||||
}
|
||||
if opts.MD5 != "" {
|
||||
headerNames = append(headerNames, "content-md5")
|
||||
}
|
||||
sort.Strings(headerNames)
|
||||
signedHeaders := strings.Join(headerNames, ";")
|
||||
timestamp := now.Format(iso8601)
|
||||
credentialScope := fmt.Sprintf("%s/auto/storage/goog4_request", now.Format(yearMonthDay))
|
||||
canonicalQueryString := url.Values{
|
||||
"X-Goog-Algorithm": {"GOOG4-RSA-SHA256"},
|
||||
"X-Goog-Credential": {fmt.Sprintf("%s/%s", opts.GoogleAccessID, credentialScope)},
|
||||
"X-Goog-Date": {timestamp},
|
||||
"X-Goog-Expires": {fmt.Sprintf("%d", int(opts.Expires.Sub(now).Seconds()))},
|
||||
"X-Goog-SignedHeaders": {signedHeaders},
|
||||
}
|
||||
fmt.Fprintf(buf, "%s\n", canonicalQueryString.Encode())
|
||||
|
||||
u.Host = "storage.googleapis.com"
|
||||
|
||||
var headersWithValue []string
|
||||
headersWithValue = append(headersWithValue, "host:"+u.Host)
|
||||
headersWithValue = append(headersWithValue, opts.Headers...)
|
||||
if opts.ContentType != "" {
|
||||
headersWithValue = append(headersWithValue, "content-type:"+strings.TrimSpace(opts.ContentType))
|
||||
}
|
||||
if opts.MD5 != "" {
|
||||
headersWithValue = append(headersWithValue, "content-md5:"+strings.TrimSpace(opts.MD5))
|
||||
}
|
||||
canonicalHeaders := strings.Join(sortHeadersByKey(headersWithValue), "\n")
|
||||
fmt.Fprintf(buf, "%s\n\n", canonicalHeaders)
|
||||
fmt.Fprintf(buf, "%s\n", signedHeaders)
|
||||
fmt.Fprint(buf, "UNSIGNED-PAYLOAD")
|
||||
|
||||
sum := sha256.Sum256(buf.Bytes())
|
||||
hexDigest := hex.EncodeToString(sum[:])
|
||||
signBuf := &bytes.Buffer{}
|
||||
fmt.Fprint(signBuf, "GOOG4-RSA-SHA256\n")
|
||||
fmt.Fprintf(signBuf, "%s\n", timestamp)
|
||||
fmt.Fprintf(signBuf, "%s\n", credentialScope)
|
||||
fmt.Fprintf(signBuf, "%s", hexDigest)
|
||||
|
||||
signBytes := opts.SignBytes
|
||||
if opts.PrivateKey != nil {
|
||||
key, err := parseKey(opts.PrivateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signBytes = func(b []byte) ([]byte, error) {
|
||||
sum := sha256.Sum256(b)
|
||||
return rsa.SignPKCS1v15(
|
||||
rand.Reader,
|
||||
key,
|
||||
crypto.SHA256,
|
||||
sum[:],
|
||||
)
|
||||
}
|
||||
}
|
||||
b, err := signBytes(signBuf.Bytes())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
signature := hex.EncodeToString(b)
|
||||
canonicalQueryString.Set("X-Goog-Signature", string(signature))
|
||||
u.Scheme = "https"
|
||||
u.RawQuery = canonicalQueryString.Encode()
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// takes a list of headerKey:headervalue1,headervalue2,etc and sorts by header
|
||||
// key.
|
||||
func sortHeadersByKey(hdrs []string) []string {
|
||||
headersMap := map[string]string{}
|
||||
var headersKeys []string
|
||||
for _, h := range hdrs {
|
||||
parts := strings.Split(h, ":")
|
||||
k := parts[0]
|
||||
v := parts[1]
|
||||
headersMap[k] = v
|
||||
headersKeys = append(headersKeys, k)
|
||||
}
|
||||
sort.Strings(headersKeys)
|
||||
var sorted []string
|
||||
for _, k := range headersKeys {
|
||||
v := headersMap[k]
|
||||
sorted = append(sorted, fmt.Sprintf("%s:%s", k, v))
|
||||
}
|
||||
return sorted
|
||||
}
|
||||
|
||||
func signedURLV2(bucket, name string, opts *SignedURLOptions) (string, error) {
|
||||
signBytes := opts.SignBytes
|
||||
if opts.PrivateKey != nil {
|
||||
key, err := parseKey(opts.PrivateKey)
|
||||
@ -777,6 +1030,10 @@ type ObjectAttrs struct {
|
||||
// ObjectIterator.Next. When set, no other fields in ObjectAttrs will be
|
||||
// populated.
|
||||
Prefix string
|
||||
|
||||
// Etag is the HTTP/1.1 Entity tag for the object.
|
||||
// This field is read-only.
|
||||
Etag string
|
||||
}
|
||||
|
||||
// convertTime converts a time in RFC3339 format to time.Time.
|
||||
@ -829,6 +1086,7 @@ func newObject(o *raw.Object) *ObjectAttrs {
|
||||
Created: convertTime(o.TimeCreated),
|
||||
Deleted: convertTime(o.TimeDeleted),
|
||||
Updated: convertTime(o.Updated),
|
||||
Etag: o.Etag,
|
||||
}
|
||||
}
|
||||
|
||||
|
16406
vendor/cloud.google.com/go/storage/storage.replay
generated
vendored
16406
vendor/cloud.google.com/go/storage/storage.replay
generated
vendored
File diff suppressed because one or more lines are too long
31
vendor/cloud.google.com/go/storage/writer.go
generated
vendored
31
vendor/cloud.google.com/go/storage/writer.go
generated
vendored
@ -117,10 +117,14 @@ func (w *Writer) open() error {
|
||||
if w.MD5 != nil {
|
||||
rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5)
|
||||
}
|
||||
if w.o.c.envHost != "" {
|
||||
w.o.c.raw.BasePath = fmt.Sprintf("%s://%s", w.o.c.scheme, w.o.c.envHost)
|
||||
}
|
||||
call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj).
|
||||
Media(pr, mediaOpts...).
|
||||
Projection("full").
|
||||
Context(w.ctx)
|
||||
|
||||
if w.ProgressFunc != nil {
|
||||
call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) })
|
||||
}
|
||||
@ -144,21 +148,16 @@ func (w *Writer) open() error {
|
||||
call.UserProject(w.o.userProject)
|
||||
}
|
||||
setClientHeader(call.Header())
|
||||
// If the chunk size is zero, then no chunking is done on the Reader,
|
||||
// which means we cannot retry: the first call will read the data, and if
|
||||
// it fails, there is no way to re-read.
|
||||
if w.ChunkSize == 0 {
|
||||
resp, err = call.Do()
|
||||
} else {
|
||||
// We will only retry here if the initial POST, which obtains a URI for
|
||||
// the resumable upload, fails with a retryable error. The upload itself
|
||||
// has its own retry logic.
|
||||
err = runWithRetry(w.ctx, func() error {
|
||||
var err2 error
|
||||
resp, err2 = call.Do()
|
||||
return err2
|
||||
})
|
||||
}
|
||||
|
||||
// The internals that perform call.Do automatically retry
|
||||
// uploading chunks, hence no need to add retries here.
|
||||
// See issue https://github.com/googleapis/google-cloud-go/issues/1507.
|
||||
//
|
||||
// However, since this whole call's internals involve making the initial
|
||||
// resumable upload session, the first HTTP request is not retried.
|
||||
// TODO: Follow-up with google.golang.org/gensupport to solve
|
||||
// https://github.com/googleapis/google-api-go-client/issues/392.
|
||||
resp, err = call.Do()
|
||||
}
|
||||
if err != nil {
|
||||
w.mu.Lock()
|
||||
@ -227,7 +226,7 @@ func (w *Writer) Close() error {
|
||||
}
|
||||
|
||||
// monitorCancel is intended to be used as a background goroutine. It monitors the
|
||||
// the context, and when it observes that the context has been canceled, it manually
|
||||
// context, and when it observes that the context has been canceled, it manually
|
||||
// closes things that do not take a context.
|
||||
func (w *Writer) monitorCancel() {
|
||||
select {
|
||||
|
90
vendor/github.com/Telmate/proxmox-api-go/proxmox/client.go
generated
vendored
90
vendor/github.com/Telmate/proxmox-api-go/proxmox/client.go
generated
vendored
@ -31,6 +31,7 @@ type Client struct {
|
||||
ApiUrl string
|
||||
Username string
|
||||
Password string
|
||||
Otp string
|
||||
}
|
||||
|
||||
// VmRef - virtual machine ref parts
|
||||
@ -38,6 +39,7 @@ type Client struct {
|
||||
type VmRef struct {
|
||||
vmId int
|
||||
node string
|
||||
pool string
|
||||
vmType string
|
||||
}
|
||||
|
||||
@ -46,11 +48,19 @@ func (vmr *VmRef) SetNode(node string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (vmr *VmRef) SetPool(pool string) {
|
||||
vmr.pool = pool
|
||||
}
|
||||
|
||||
func (vmr *VmRef) SetVmType(vmType string) {
|
||||
vmr.vmType = vmType
|
||||
return
|
||||
}
|
||||
|
||||
func (vmr *VmRef) GetVmType() (string) {
|
||||
return vmr.vmType
|
||||
}
|
||||
|
||||
func (vmr *VmRef) VmId() int {
|
||||
return vmr.vmId
|
||||
}
|
||||
@ -59,6 +69,10 @@ func (vmr *VmRef) Node() string {
|
||||
return vmr.node
|
||||
}
|
||||
|
||||
func (vmr *VmRef) Pool() string {
|
||||
return vmr.pool
|
||||
}
|
||||
|
||||
func NewVmRef(vmId int) (vmr *VmRef) {
|
||||
vmr = &VmRef{vmId: vmId, node: "", vmType: ""}
|
||||
return
|
||||
@ -73,10 +87,11 @@ func NewClient(apiUrl string, hclient *http.Client, tls *tls.Config) (client *Cl
|
||||
return client, err
|
||||
}
|
||||
|
||||
func (c *Client) Login(username string, password string) (err error) {
|
||||
func (c *Client) Login(username string, password string, otp string) (err error) {
|
||||
c.Username = username
|
||||
c.Password = password
|
||||
return c.session.Login(username, password)
|
||||
c.Otp = otp
|
||||
return c.session.Login(username, password, otp)
|
||||
}
|
||||
|
||||
func (c *Client) GetJsonRetryable(url string, data *map[string]interface{}, tries int) error {
|
||||
@ -275,10 +290,26 @@ func (c *Client) MonitorCmd(vmr *VmRef, command string) (monitorRes map[string]i
|
||||
reqbody := ParamsToBody(map[string]interface{}{"command": command})
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/monitor", vmr.node, vmr.vmType, vmr.vmId)
|
||||
resp, err := c.session.Post(url, nil, nil, &reqbody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
monitorRes, err = ResponseJSON(resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) Sendkey(vmr *VmRef, qmKey string) error {
|
||||
err := c.CheckVmRef(vmr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reqbody := ParamsToBody(map[string]interface{}{"key": qmKey})
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/sendkey", vmr.node, vmr.vmType, vmr.vmId)
|
||||
// No return, even for errors: https://bugzilla.proxmox.com/show_bug.cgi?id=2275
|
||||
_, err = c.session.Put(url, nil, nil, &reqbody)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitForCompletion - poll the API for task completion
|
||||
func (c *Client) WaitForCompletion(taskResponse map[string]interface{}) (waitExitStatus string, err error) {
|
||||
if taskResponse["errors"] != nil {
|
||||
@ -416,6 +447,29 @@ func (c *Client) CreateQemuVm(node string, vmParams map[string]interface{}) (exi
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) CreateLxcContainer(node string, vmParams map[string]interface{}) (exitStatus string, err error) {
|
||||
reqbody := ParamsToBody(vmParams)
|
||||
url := fmt.Sprintf("/nodes/%s/lxc", node)
|
||||
var resp *http.Response
|
||||
resp, err = c.session.Post(url, nil, nil, &reqbody)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
// This might not work if we never got a body. We'll ignore errors in trying to read,
|
||||
// but extract the body if possible to give any error information back in the exitStatus
|
||||
b, _ := ioutil.ReadAll(resp.Body)
|
||||
exitStatus = string(b)
|
||||
return exitStatus, err
|
||||
}
|
||||
|
||||
taskResponse, err := ResponseJSON(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
exitStatus, err = c.WaitForCompletion(taskResponse)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) CloneQemuVm(vmr *VmRef, vmParams map[string]interface{}) (exitStatus string, err error) {
|
||||
reqbody := ParamsToBody(vmParams)
|
||||
url := fmt.Sprintf("/nodes/%s/qemu/%d/clone", vmr.node, vmr.vmId)
|
||||
@ -457,6 +511,21 @@ func (c *Client) SetVmConfig(vmr *VmRef, vmParams map[string]interface{}) (exitS
|
||||
return
|
||||
}
|
||||
|
||||
// SetLxcConfig - send config options
|
||||
func (c *Client) SetLxcConfig(vmr *VmRef, vmParams map[string]interface{}) (exitStatus interface{}, err error) {
|
||||
reqbody := ParamsToBody(vmParams)
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/config", vmr.node, vmr.vmType, vmr.vmId)
|
||||
resp, err := c.session.Put(url, nil, nil, &reqbody)
|
||||
if err == nil {
|
||||
taskResponse, err := ResponseJSON(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exitStatus, err = c.WaitForCompletion(taskResponse)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitStatus interface{}, err error) {
|
||||
// PUT
|
||||
//disk:virtio0
|
||||
@ -478,6 +547,23 @@ func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitSt
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) MoveQemuDisk(vmr *VmRef, disk string, storage string) (exitStatus interface{}, err error) {
|
||||
if disk == "" {
|
||||
disk = "virtio0"
|
||||
}
|
||||
reqbody := ParamsToBody(map[string]interface{}{"disk": disk, "storage": storage, "delete": true})
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/move_disk", vmr.node, vmr.vmType, vmr.vmId)
|
||||
resp, err := c.session.Post(url, nil, nil, &reqbody)
|
||||
if err == nil {
|
||||
taskResponse, err := ResponseJSON(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exitStatus, err = c.WaitForCompletion(taskResponse)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetNextID - Get next free VMID
|
||||
func (c *Client) GetNextID(currentID int) (nextID int, err error) {
|
||||
var data map[string]interface{}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user