Merge pull request #7270 from hashicorp/go_mod_vendor

make go mod manage deps
This commit is contained in:
Megan Marsh 2019-04-11 09:42:50 -07:00 committed by GitHub
commit 09d2418552
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
990 changed files with 18105 additions and 64577 deletions

View File

@ -10,3 +10,16 @@ jobs:
steps:
- checkout
- run: make ci
check-vendor-vs-mod:
docker:
- image: circleci/golang:1.12
working_directory: /go/src/github.com/hashicorp/packer
steps:
- checkout
- run: make check-vendor-vs-mod
workflows:
version: 2
build_and_check_vendor_vs_module:
jobs:
- build
- check-vendor-vs-mod

View File

@ -212,22 +212,22 @@ project. After following the steps in "Setting up Go to work on Packer":
This way you can push to your fork to create a PR, but the code on disk still
lives in the spot where the go cli tools are expecting to find it.
#### Govendor
#### Go modules & go vendor
If you are submitting a change that requires new or updated dependencies, please
include them in `vendor/vendor.json` and in the `vendor/` folder. This helps
everything get tested properly in CI.
If you are submitting a change that requires new or updated dependencies,
please include them in `go.mod`/`go.sum` and in the `vendor/` folder. This
helps everything get tested properly in CI.
Note that you will need to use [govendor](https://github.com/kardianos/govendor)
to do this. This step is recommended but not required; if you don't use govendor
please indicate in your PR which dependencies have changed and to what versions.
Note that you will need to use [go
mod](https://github.com/golang/go/wiki/Modules) to do this. This step is
recommended but not required.
Use `govendor fetch <project>` to add dependencies to the project. See
[govendor quick start](https://github.com/kardianos/govendor#quick-start-also-see-the-faq)
for examples.
Use `go get <project>` to add dependencies to the project and `go mod vendor`
to make vendored copy of dependencies. See [go mod quick
start](https://github.com/golang/go/wiki/Modules#quick-start) for examples.
Please only apply the minimal vendor changes to get your PR to work. Packer does
not attempt to track the latest version for each dependency.
Please only apply the minimal vendor changes to get your PR to work. Packer
does not attempt to track the latest version for each dependency.
#### Running Unit Tests

View File

@ -1,5 +1,5 @@
env:
- USER=travis
- USER=travis GO111MODULE=off
os:
- windows

View File

@ -32,7 +32,7 @@ release: deps test releasebin package ## Build a release build
bin: deps ## Build debug/test build
@go get github.com/mitchellh/gox
@echo "WARN: 'make bin' is for debug / test builds only. Use 'make release' for release builds."
@sh -c "$(CURDIR)/scripts/build.sh"
@GO111MODULE=off sh -c "$(CURDIR)/scripts/build.sh"
releasebin: deps
@go get github.com/mitchellh/gox
@ -40,7 +40,7 @@ releasebin: deps
echo "ERROR: You must remove prerelease tags from version/version.go prior to release."; \
exit 1; \
fi
@sh -c "$(CURDIR)/scripts/build.sh"
@GO111MODULE=off sh -c "$(CURDIR)/scripts/build.sh"
package:
$(if $(VERSION),,@echo 'VERSION= needed to release; Use make package skip compilation'; exit 1)
@ -50,7 +50,6 @@ deps:
@go get golang.org/x/tools/cmd/goimports
@go get golang.org/x/tools/cmd/stringer
@go get -u github.com/mna/pigeon
@go get github.com/kardianos/govendor
dev: deps ## Build and install a development build
@grep 'const VersionPrerelease = ""' version/version.go > /dev/null ; if [ $$? -eq 0 ]; then \
@ -110,10 +109,17 @@ testacc: deps generate ## Run acceptance tests
PACKER_ACC=1 go test -v $(TEST) $(TESTARGS) -timeout=45m
testrace: fmt-check mode-check vet ## Test with race detection enabled
@go test -race $(TEST) $(TESTARGS) -timeout=3m -p=8
@GO111MODULE=off go test -race $(TEST) $(TESTARGS) -timeout=3m -p=8
check-vendor-vs-mod:
@GO111MODULE=on go mod vendor
@git diff --exit-code --ignore-space-change --ignore-space-at-eol -- vendor ; if [ $$? -eq 1 ]; then \
echo "ERROR: vendor dir is not on par with go modules definition." && \
exit 1; \
fi
updatedeps:
@echo "INFO: Packer deps are managed by govendor. See .github/CONTRIBUTING.md"
@echo "INFO: Packer deps are managed by go modules. See .github/CONTRIBUTING.md"
vet: ## Vet Go code
@go vet $(VET) ; if [ $$? -eq 1 ]; then \

View File

@ -16,6 +16,7 @@ environment:
clone_folder: c:\gopath\src\github.com\hashicorp\packer
install:
- set GO111MODULE=off
- echo %Path%
- go version
- go env

View File

@ -102,7 +102,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
// set default copy file if we're not giving our own
if b.config.CopyFiles == nil {
b.config.CopyFiles = make([]string, 0)
if !b.config.FromScratch {
b.config.CopyFiles = []string{"/etc/resolv.conf"}
}

View File

@ -159,7 +159,8 @@ func TestBuilderPrepare_CopyFilesNoDefault(t *testing.T) {
}
if len(b.config.CopyFiles) > 0 {
t.Errorf("Was expecting no default value for copy_files.")
t.Errorf("Was expecting no default value for copy_files. Found %v",
b.config.CopyFiles)
}
}

View File

@ -10,8 +10,8 @@ import (
"sync"
"syscall"
"github.com/hashicorp/packer/common/iochan"
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/iochan"
)
func runAndStream(cmd *exec.Cmd, ui packer.Ui) error {
@ -40,8 +40,8 @@ func runAndStream(cmd *exec.Cmd, ui packer.Ui) error {
// Create the channels we'll use for data
exitCh := make(chan int, 1)
stdoutCh := iochan.DelimReader(stdout_r, '\n')
stderrCh := iochan.DelimReader(stderr_r, '\n')
stdoutCh := iochan.LineReader(stdout_r)
stderrCh := iochan.LineReader(stderr_r)
// Start the goroutine to watch for the exit
go func() {

View File

@ -1,44 +0,0 @@
package proxmox
import (
"fmt"
"log"
"strconv"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/packer"
)
type Artifact struct {
templateID int
proxmoxClient *proxmox.Client
}
// Artifact implements packer.Artifact
var _ packer.Artifact = &Artifact{}
func (*Artifact) BuilderId() string {
return BuilderId
}
func (*Artifact) Files() []string {
return nil
}
func (a *Artifact) Id() string {
return strconv.Itoa(a.templateID)
}
func (a *Artifact) String() string {
return fmt.Sprintf("A template was created: %d", a.templateID)
}
func (a *Artifact) State(name string) interface{} {
return nil
}
func (a *Artifact) Destroy() error {
log.Printf("Destroying template: %d", a.templateID)
_, err := a.proxmoxClient.DeleteVm(proxmox.NewVmRef(a.templateID))
return err
}

View File

@ -1,117 +0,0 @@
package proxmox
import (
"fmt"
"time"
"unicode"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/common/bootcommand"
)
type proxmoxDriver struct {
client commandTyper
vmRef *proxmox.VmRef
specialMap map[string]string
runeMap map[rune]string
interval time.Duration
}
func NewProxmoxDriver(c commandTyper, vmRef *proxmox.VmRef, interval time.Duration) *proxmoxDriver {
// Mappings for packer shorthand to qemu qkeycodes
sMap := map[string]string{
"spacebar": "spc",
"bs": "backspace",
"del": "delete",
"return": "ret",
"enter": "ret",
"pageUp": "pgup",
"pageDown": "pgdn",
}
// Mappings for runes that need to be translated to special qkeycodes
// Taken from https://github.com/qemu/qemu/blob/master/pc-bios/keymaps/en-us
rMap := map[rune]string{
// Clean mappings
' ': "spc",
'.': "dot",
',': "comma",
';': "semicolon",
'*': "asterisk",
'-': "minus",
'[': "bracket_left",
']': "bracket_right",
'=': "equal",
'\'': "apostrophe",
'`': "grave_accent",
'/': "slash",
'\\': "backslash",
'!': "shift-1", // "exclam"
'@': "shift-2", // "at"
'#': "shift-3", // "numbersign"
'$': "shift-4", // "dollar"
'%': "shift-5", // "percent"
'^': "shift-6", // "asciicircum"
'&': "shift-7", // "ampersand"
'(': "shift-9", // "parenleft"
')': "shift-0", // "parenright"
'{': "shift-bracket_left", // "braceleft"
'}': "shift-bracket_right", // "braceright"
'"': "shift-apostrophe", // "quotedbl"
'+': "shift-equal", // "plus"
'_': "shift-minus", // "underscore"
':': "shift-semicolon", // "colon"
'<': "shift-comma", // "less" is recognized, but seem to map to '/'?
'>': "shift-dot", // "greater"
'~': "shift-grave_accent", // "asciitilde"
'?': "shift-slash", // "question"
'|': "shift-backslash", // "bar"
}
return &proxmoxDriver{
client: c,
vmRef: vmRef,
specialMap: sMap,
runeMap: rMap,
interval: interval,
}
}
func (p *proxmoxDriver) SendKey(key rune, action bootcommand.KeyAction) error {
if special, ok := p.runeMap[key]; ok {
return p.send(special)
}
var keys string
if unicode.IsUpper(key) {
keys = fmt.Sprintf("shift-%c", unicode.ToLower(key))
} else {
keys = fmt.Sprintf("%c", key)
}
return p.send(keys)
}
func (p *proxmoxDriver) SendSpecial(special string, action bootcommand.KeyAction) error {
keys := special
if replacement, ok := p.specialMap[special]; ok {
keys = replacement
}
return p.send(keys)
}
func (p *proxmoxDriver) send(keys string) error {
res, err := p.client.MonitorCmd(p.vmRef, "sendkey "+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
}
func (p *proxmoxDriver) Flush() error { return nil }

View File

@ -1,122 +0,0 @@
package proxmox
import (
"context"
"crypto/tls"
"fmt"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// The unique id for the builder
const BuilderId = "proxmox.builder"
type Builder struct {
config Config
runner multistep.Runner
proxmoxClient *proxmox.Client
}
// Builder implements packer.Builder
var _ packer.Builder = &Builder{}
var pluginVersion = "1.0.0"
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
config, warnings, errs := NewConfig(raws...)
if errs != nil {
return warnings, errs
}
b.config = *config
return nil, nil
}
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
var err error
tlsConfig := &tls.Config{
InsecureSkipVerify: b.config.SkipCertValidation,
}
b.proxmoxClient, err = proxmox.NewClient(b.config.ProxmoxURL.String(), nil, tlsConfig)
if err != nil {
return nil, err
}
err = b.proxmoxClient.Login(b.config.Username, b.config.Password)
if err != nil {
return nil, err
}
// Set up the state
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("proxmoxClient", b.proxmoxClient)
state.Put("hook", hook)
state.Put("ui", ui)
// Build the steps
steps := []multistep.Step{
&stepStartVM{},
&common.StepHTTPServer{
HTTPDir: b.config.HTTPDir,
HTTPPortMin: b.config.HTTPPortMin,
HTTPPortMax: b.config.HTTPPortMax,
},
&stepTypeBootCommand{
BootConfig: b.config.BootConfig,
Ctx: b.config.ctx,
},
&communicator.StepConnect{
Config: &b.config.Comm,
Host: getVMIP,
SSHConfig: b.config.Comm.SSHConfigFunc(),
},
&common.StepProvision{},
&common.StepCleanupTempKeys{
Comm: &b.config.Comm,
},
&stepConvertToTemplate{},
&stepFinalizeTemplateConfig{},
&stepSuccess{},
}
// Run the steps
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
b.runner.Run(ctx, state)
// If there was an error, return that
if rawErr, ok := state.GetOk("error"); ok {
return nil, rawErr.(error)
}
artifact := &Artifact{
templateID: state.Get("template_id").(int),
proxmoxClient: b.proxmoxClient,
}
return artifact, nil
}
func getVMIP(state multistep.StateBag) (string, error) {
c := state.Get("proxmoxClient").(*proxmox.Client)
vmRef := state.Get("vmRef").(*proxmox.VmRef)
ifs, err := c.GetVmAgentNetworkInterfaces(vmRef)
if err != nil {
return "", err
}
// TODO: Do something smarter here? Allow specifying interface? Or address family?
// For now, just go for first non-loopback
for _, iface := range ifs {
for _, addr := range iface.IPAddresses {
if addr.IsLoopback() {
continue
}
return addr.String(), nil
}
}
return "", fmt.Errorf("Found no IP addresses on VM")
}

View File

@ -1,196 +0,0 @@
package proxmox
import (
"errors"
"fmt"
"log"
"net/url"
"os"
"time"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/bootcommand"
"github.com/hashicorp/packer/common/uuid"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
"github.com/mitchellh/mapstructure"
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
common.HTTPConfig `mapstructure:",squash"`
bootcommand.BootConfig `mapstructure:",squash"`
RawBootKeyInterval string `mapstructure:"boot_key_interval"`
BootKeyInterval time.Duration ``
Comm communicator.Config `mapstructure:",squash"`
ProxmoxURLRaw string `mapstructure:"proxmox_url"`
ProxmoxURL *url.URL
SkipCertValidation bool `mapstructure:"insecure_skip_tls_verify"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
Node string `mapstructure:"node"`
VMName string `mapstructure:"vm_name"`
VMID int `mapstructure:"vm_id"`
Memory int `mapstructure:"memory"`
Cores int `mapstructure:"cores"`
Sockets int `mapstructure:"sockets"`
OS string `mapstructure:"os"`
NICs []nicConfig `mapstructure:"network_adapters"`
Disks []diskConfig `mapstructure:"disks"`
ISOFile string `mapstructure:"iso_file"`
TemplateName string `mapstructure:"template_name"`
TemplateDescription string `mapstructure:"template_description"`
UnmountISO bool `mapstructure:"unmount_iso"`
ctx interpolate.Context
}
type nicConfig struct {
Model string `mapstructure:"model"`
MACAddress string `mapstructure:"mac_address"`
Bridge string `mapstructure:"bridge"`
VLANTag string `mapstructure:"vlan_tag"`
}
type diskConfig struct {
Type string `mapstructure:"type"`
StoragePool string `mapstructure:"storage_pool"`
StoragePoolType string `mapstructure:"storage_pool_type"`
Size string `mapstructure:"disk_size"`
CacheMode string `mapstructure:"cache_mode"`
DiskFormat string `mapstructure:"format"`
}
func NewConfig(raws ...interface{}) (*Config, []string, error) {
c := new(Config)
var md mapstructure.Metadata
err := config.Decode(c, &config.DecodeOpts{
Metadata: &md,
Interpolate: true,
InterpolateContext: &c.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"boot_command",
},
},
}, raws...)
if err != nil {
return nil, nil, err
}
var errs *packer.MultiError
// Defaults
if c.ProxmoxURLRaw == "" {
c.ProxmoxURLRaw = os.Getenv("PROXMOX_URL")
}
if c.Username == "" {
c.Username = os.Getenv("PROXMOX_USERNAME")
}
if c.Password == "" {
c.Password = os.Getenv("PROXMOX_PASSWORD")
}
if c.RawBootKeyInterval == "" {
c.RawBootKeyInterval = os.Getenv(common.PackerKeyEnv)
}
if c.RawBootKeyInterval == "" {
c.BootKeyInterval = common.PackerKeyDefault
} else {
if interval, err := time.ParseDuration(c.RawBootKeyInterval); err == nil {
c.BootKeyInterval = interval
} else {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Could not parse boot_key_interval: %v", err))
}
}
if c.VMName == "" {
// Default to packer-[time-ordered-uuid]
c.VMName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
if c.Memory < 16 {
log.Printf("Memory %d is too small, using default: 512", c.Memory)
c.Memory = 512
}
if c.Cores < 1 {
log.Printf("Number of cores %d is too small, using default: 1", c.Cores)
c.Cores = 1
}
if c.Sockets < 1 {
log.Printf("Number of sockets %d is too small, using default: 1", c.Sockets)
c.Sockets = 1
}
if c.OS == "" {
log.Printf("OS not set, using default 'other'")
c.OS = "other"
}
for idx := range c.NICs {
if c.NICs[idx].Model == "" {
log.Printf("NIC %d model not set, using default 'e1000'", idx)
c.NICs[idx].Model = "e1000"
}
}
for idx := range c.Disks {
if c.Disks[idx].Type == "" {
log.Printf("Disk %d type not set, using default 'scsi'", idx)
c.Disks[idx].Type = "scsi"
}
if c.Disks[idx].Size == "" {
log.Printf("Disk %d size not set, using default '20G'", idx)
c.Disks[idx].Size = "20G"
}
if c.Disks[idx].CacheMode == "" {
log.Printf("Disk %d cache mode not set, using default 'none'", idx)
c.Disks[idx].CacheMode = "none"
}
}
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...)
// Required configurations that will display errors if not set
if c.Username == "" {
errs = packer.MultiErrorAppend(errs, errors.New("username must be specified"))
}
if c.Password == "" {
errs = packer.MultiErrorAppend(errs, errors.New("password must be specified"))
}
if c.ProxmoxURLRaw == "" {
errs = packer.MultiErrorAppend(errs, errors.New("proxmox_url must be specified"))
}
if c.ProxmoxURL, err = url.Parse(c.ProxmoxURLRaw); err != nil {
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("Could not parse proxmox_url: %s", err)))
}
if c.ISOFile == "" {
errs = packer.MultiErrorAppend(errs, errors.New("iso_file must be specified"))
}
if c.Node == "" {
errs = packer.MultiErrorAppend(errs, errors.New("node must be specified"))
}
for idx := range c.NICs {
if c.NICs[idx].Bridge == "" {
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("network_adapters[%d].bridge must be specified", idx)))
}
}
for idx := range c.Disks {
if c.Disks[idx].StoragePool == "" {
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("disks[%d].storage_pool must be specified", idx)))
}
if c.Disks[idx].StoragePoolType == "" {
errs = packer.MultiErrorAppend(errs, errors.New(fmt.Sprintf("disks[%d].storage_pool_type must be specified", idx)))
}
}
if errs != nil && len(errs.Errors) > 0 {
return nil, nil, errs
}
packer.LogSecretFilter.Set(c.Password)
return c, nil, nil
}

View File

@ -1,115 +0,0 @@
package proxmox
import (
"strings"
"testing"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template"
)
func TestRequiredParameters(t *testing.T) {
_, _, err := NewConfig(make(map[string]interface{}))
if err == nil {
t.Fatal("Expected empty configuration to fail")
}
errs, ok := err.(*packer.MultiError)
if !ok {
t.Fatal("Expected errors to be packer.MultiError")
}
required := []string{"username", "password", "proxmox_url", "iso_file", "node", "ssh_username"}
for _, param := range required {
found := false
for _, err := range errs.Errors {
if strings.Contains(err.Error(), param) {
found = true
break
}
}
if !found {
t.Errorf("Expected error about missing parameter %q", required)
}
}
}
func TestBasicExampleFromDocsIsValid(t *testing.T) {
const config = `{
"builders": [
{
"type": "proxmox",
"proxmox_url": "https://my-proxmox.my-domain:8006/api2/json",
"insecure_skip_tls_verify": true,
"username": "apiuser@pve",
"password": "supersecret",
"node": "my-proxmox",
"network_adapters": [
{
"bridge": "vmbr0"
}
],
"disks": [
{
"type": "scsi",
"disk_size": "5G",
"storage_pool": "local-lvm",
"storage_pool_type": "lvm"
}
],
"iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso",
"http_directory":"config",
"boot_wait": "10s",
"boot_command": [
"<up><tab> ip=dhcp inst.cmdline inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/ks.cfg<enter>"
],
"ssh_username": "root",
"ssh_timeout": "15m",
"ssh_password": "packer",
"unmount_iso": true,
"template_name": "fedora-29",
"template_description": "Fedora 29-1.2, generated on {{ isotime \"2006-01-02T15:04:05Z\" }}"
}
]
}`
tpl, err := template.Parse(strings.NewReader(config))
if err != nil {
t.Fatal(err)
}
b := &Builder{}
warn, err := b.Prepare(tpl.Builders["proxmox"].Config)
if err != nil {
t.Fatal(err, warn)
}
// The example config does not set a number of optional fields. Validate that:
// Memory 0 is too small, using default: 512
// Number of cores 0 is too small, using default: 1
// Number of sockets 0 is too small, using default: 1
// OS not set, using default 'other'
// NIC 0 model not set, using default 'e1000'
// Disk 0 cache mode not set, using default 'none'
if b.config.Memory != 512 {
t.Errorf("Expected Memory to be 512, got %d", b.config.Memory)
}
if b.config.Cores != 1 {
t.Errorf("Expected Cores to be 1, got %d", b.config.Cores)
}
if b.config.Sockets != 1 {
t.Errorf("Expected Sockets to be 1, got %d", b.config.Sockets)
}
if b.config.OS != "other" {
t.Errorf("Expected OS to be 'other', got %s", b.config.OS)
}
if b.config.NICs[0].Model != "e1000" {
t.Errorf("Expected NIC model to be 'e1000', got %s", b.config.NICs[0].Model)
}
if b.config.Disks[0].CacheMode != "none" {
t.Errorf("Expected disk cache mode to be 'none', got %s", b.config.Disks[0].CacheMode)
}
}

View File

@ -1,53 +0,0 @@
package proxmox
import (
"context"
"fmt"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// stepConvertToTemplate takes the running VM configured in earlier steps, stops it, and
// converts it into a Proxmox template.
//
// It sets the template_id state which is used for Artifact lookup.
type stepConvertToTemplate struct{}
type templateConverter interface {
ShutdownVm(*proxmox.VmRef) (string, error)
CreateTemplate(*proxmox.VmRef) error
}
var _ templateConverter = &proxmox.Client{}
func (s *stepConvertToTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
client := state.Get("proxmoxClient").(templateConverter)
vmRef := state.Get("vmRef").(*proxmox.VmRef)
ui.Say("Stopping VM")
_, err := client.ShutdownVm(vmRef)
if err != nil {
err := fmt.Errorf("Error converting VM to template, could not stop: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
ui.Say("Converting VM to template")
err = client.CreateTemplate(vmRef)
if err != nil {
err := fmt.Errorf("Error converting VM to template: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
state.Put("template_id", vmRef.VmId())
return multistep.ActionContinue
}
func (s *stepConvertToTemplate) Cleanup(state multistep.StateBag) {}

View File

@ -1,103 +0,0 @@
package proxmox
import (
"context"
"fmt"
"testing"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type converterMock struct {
shutdownVm func(*proxmox.VmRef) (string, error)
createTemplate func(*proxmox.VmRef) error
}
func (m converterMock) ShutdownVm(r *proxmox.VmRef) (string, error) {
return m.shutdownVm(r)
}
func (m converterMock) CreateTemplate(r *proxmox.VmRef) error {
return m.createTemplate(r)
}
var _ templateConverter = converterMock{}
func TestConvertToTemplate(t *testing.T) {
cs := []struct {
name string
shutdownErr error
expectCallCreateTemplate bool
createTemplateErr error
expectedAction multistep.StepAction
expectTemplateIdSet bool
}{
{
name: "no errors returns continue and sets template id",
expectCallCreateTemplate: true,
expectedAction: multistep.ActionContinue,
expectTemplateIdSet: true,
},
{
name: "when shutdown fails, don't try to create template and halt",
shutdownErr: fmt.Errorf("failed to stop vm"),
expectCallCreateTemplate: false,
expectedAction: multistep.ActionHalt,
expectTemplateIdSet: false,
},
{
name: "when create template fails, halt",
expectCallCreateTemplate: true,
createTemplateErr: fmt.Errorf("failed to stop vm"),
expectedAction: multistep.ActionHalt,
expectTemplateIdSet: false,
},
}
const vmid = 123
for _, c := range cs {
t.Run(c.name, func(t *testing.T) {
converter := converterMock{
shutdownVm: func(r *proxmox.VmRef) (string, error) {
if r.VmId() != vmid {
t.Errorf("ShutdownVm called with unexpected id, expected %d, got %d", vmid, r.VmId())
}
return "", c.shutdownErr
},
createTemplate: func(r *proxmox.VmRef) error {
if r.VmId() != vmid {
t.Errorf("CreateTemplate called with unexpected id, expected %d, got %d", vmid, r.VmId())
}
if !c.expectCallCreateTemplate {
t.Error("Did not expect CreateTemplate to be called")
}
return c.createTemplateErr
},
}
state := new(multistep.BasicStateBag)
state.Put("ui", packer.TestUi(t))
state.Put("vmRef", proxmox.NewVmRef(vmid))
state.Put("proxmoxClient", converter)
step := stepConvertToTemplate{}
action := step.Run(context.TODO(), state)
if action != c.expectedAction {
t.Errorf("Expected action to be %v, got %v", c.expectedAction, action)
}
id, wasSet := state.GetOk("template_id")
if c.expectTemplateIdSet != wasSet {
t.Errorf("Expected template_id state present=%v was present=%v", c.expectTemplateIdSet, wasSet)
}
if c.expectTemplateIdSet && id != vmid {
t.Errorf("Expected template_id state to be set to %d, got %v", vmid, id)
}
})
}
}

View File

@ -1,72 +0,0 @@
package proxmox
import (
"context"
"fmt"
"strings"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// stepFinalizeTemplateConfig does any required modifications to the configuration _after_
// the VM has been converted into a template, such as updating name and description, or
// unmounting the installation ISO.
type stepFinalizeTemplateConfig struct{}
type templateFinalizer interface {
GetVmConfig(*proxmox.VmRef) (map[string]interface{}, error)
SetVmConfig(*proxmox.VmRef, map[string]interface{}) (interface{}, error)
}
var _ templateFinalizer = &proxmox.Client{}
func (s *stepFinalizeTemplateConfig) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
client := state.Get("proxmoxClient").(templateFinalizer)
c := state.Get("config").(*Config)
vmRef := state.Get("vmRef").(*proxmox.VmRef)
changes := make(map[string]interface{})
if c.TemplateName != "" {
changes["name"] = c.TemplateName
}
// During build, the description is "Packer ephemeral build VM", so if no description is
// set, we need to clear it
changes["description"] = c.TemplateDescription
if c.UnmountISO {
vmParams, err := client.GetVmConfig(vmRef)
if err != nil {
err := fmt.Errorf("Error fetching template config: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if vmParams["ide2"] == nil || !strings.HasSuffix(vmParams["ide2"].(string), "media=cdrom") {
err := fmt.Errorf("Cannot eject ISO from cdrom drive, ide2 is not present, or not a cdrom media")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
changes["ide2"] = "none,media=cdrom"
}
if len(changes) > 0 {
_, err := client.SetVmConfig(vmRef, changes)
if err != nil {
err := fmt.Errorf("Error updating template: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
return multistep.ActionContinue
}
func (s *stepFinalizeTemplateConfig) Cleanup(state multistep.StateBag) {}

View File

@ -1,151 +0,0 @@
package proxmox
import (
"context"
"fmt"
"testing"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type finalizerMock struct {
getConfig func() (map[string]interface{}, error)
setConfig func(map[string]interface{}) (string, error)
}
func (m finalizerMock) GetVmConfig(*proxmox.VmRef) (map[string]interface{}, error) {
return m.getConfig()
}
func (m finalizerMock) SetVmConfig(vmref *proxmox.VmRef, c map[string]interface{}) (interface{}, error) {
return m.setConfig(c)
}
var _ templateFinalizer = finalizerMock{}
func TestTemplateFinalize(t *testing.T) {
cs := []struct {
name string
builderConfig *Config
initialVMConfig map[string]interface{}
getConfigErr error
expectCallSetConfig bool
expectedVMConfig map[string]interface{}
setConfigErr error
expectedAction multistep.StepAction
}{
{
name: "empty config changes only description",
builderConfig: &Config{},
initialVMConfig: map[string]interface{}{
"name": "dummy",
"description": "Packer ephemeral build VM",
"ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom",
},
expectCallSetConfig: true,
expectedVMConfig: map[string]interface{}{
"name": nil,
"description": "",
"ide2": nil,
},
expectedAction: multistep.ActionContinue,
},
{
name: "all options",
builderConfig: &Config{
TemplateName: "my-template",
TemplateDescription: "some-description",
UnmountISO: true,
},
initialVMConfig: map[string]interface{}{
"name": "dummy",
"description": "Packer ephemeral build VM",
"ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom",
},
expectCallSetConfig: true,
expectedVMConfig: map[string]interface{}{
"name": "my-template",
"description": "some-description",
"ide2": "none,media=cdrom",
},
expectedAction: multistep.ActionContinue,
},
{
name: "no cd-drive with unmount=true should returns halt",
builderConfig: &Config{
TemplateName: "my-template",
TemplateDescription: "some-description",
UnmountISO: true,
},
initialVMConfig: map[string]interface{}{
"name": "dummy",
"description": "Packer ephemeral build VM",
"ide1": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom",
},
expectCallSetConfig: false,
expectedAction: multistep.ActionHalt,
},
{
name: "GetVmConfig error should return halt",
builderConfig: &Config{
TemplateName: "my-template",
TemplateDescription: "some-description",
UnmountISO: true,
},
getConfigErr: fmt.Errorf("some error"),
expectCallSetConfig: false,
expectedAction: multistep.ActionHalt,
},
{
name: "SetVmConfig error should return halt",
builderConfig: &Config{
TemplateName: "my-template",
TemplateDescription: "some-description",
UnmountISO: true,
},
initialVMConfig: map[string]interface{}{
"name": "dummy",
"description": "Packer ephemeral build VM",
"ide2": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso,media=cdrom",
},
expectCallSetConfig: true,
setConfigErr: fmt.Errorf("some error"),
expectedAction: multistep.ActionHalt,
},
}
for _, c := range cs {
t.Run(c.name, func(t *testing.T) {
finalizer := finalizerMock{
getConfig: func() (map[string]interface{}, error) {
return c.initialVMConfig, c.getConfigErr
},
setConfig: func(cfg map[string]interface{}) (string, error) {
if !c.expectCallSetConfig {
t.Error("Did not expect SetVmConfig to be called")
}
for key, val := range c.expectedVMConfig {
if cfg[key] != val {
t.Errorf("Expected %q to be %q, got %q", key, val, cfg[key])
}
}
return "", c.setConfigErr
},
}
state := new(multistep.BasicStateBag)
state.Put("ui", packer.TestUi(t))
state.Put("config", c.builderConfig)
state.Put("vmRef", proxmox.NewVmRef(1))
state.Put("proxmoxClient", finalizer)
step := stepFinalizeTemplateConfig{}
action := step.Run(context.TODO(), state)
if action != c.expectedAction {
t.Errorf("Expected action to be %v, got %v", c.expectedAction, action)
}
})
}
}

View File

@ -1,150 +0,0 @@
package proxmox
import (
"context"
"fmt"
"log"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
// stepStartVM takes the given configuration and starts a VM on the given Proxmox node.
//
// It sets the vmRef state which is used throughout the later steps to reference the VM
// in API calls.
type stepStartVM struct{}
func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
client := state.Get("proxmoxClient").(*proxmox.Client)
c := state.Get("config").(*Config)
ui.Say("Creating VM")
config := proxmox.ConfigQemu{
Name: c.VMName,
Agent: "1",
Description: "Packer ephemeral build VM",
Memory: c.Memory,
QemuCores: c.Cores,
QemuSockets: c.Sockets,
QemuOs: c.OS,
QemuIso: c.ISOFile,
QemuNetworks: generateProxmoxNetworkAdapters(c.NICs),
QemuDisks: generateProxmoxDisks(c.Disks),
}
if c.VMID == 0 {
ui.Say("No VM ID given, getting next free from Proxmox")
for n := 0; n < 5; n++ {
id, err := proxmox.MaxVmId(client)
if err != nil {
log.Printf("Error getting max used VM ID: %v (attempt %d/5)", err, n+1)
continue
}
c.VMID = id + 1
break
}
if c.VMID == 0 {
err := fmt.Errorf("Failed to get free VM ID")
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
vmRef := proxmox.NewVmRef(c.VMID)
vmRef.SetNode(c.Node)
err := config.CreateVm(vmRef, client)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// Store the vm id for later
state.Put("vmRef", vmRef)
ui.Say("Starting VM")
_, err = client.StartVm(vmRef)
if err != nil {
err := fmt.Errorf("Error starting VM: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func generateProxmoxNetworkAdapters(nics []nicConfig) proxmox.QemuDevices {
devs := make(proxmox.QemuDevices)
for idx := range nics {
devs[idx] = make(proxmox.QemuDevice)
setDeviceParamIfDefined(devs[idx], "model", nics[idx].Model)
setDeviceParamIfDefined(devs[idx], "macaddr", nics[idx].MACAddress)
setDeviceParamIfDefined(devs[idx], "bridge", nics[idx].Bridge)
setDeviceParamIfDefined(devs[idx], "tag", nics[idx].VLANTag)
}
return devs
}
func generateProxmoxDisks(disks []diskConfig) proxmox.QemuDevices {
devs := make(proxmox.QemuDevices)
for idx := range disks {
devs[idx] = make(proxmox.QemuDevice)
setDeviceParamIfDefined(devs[idx], "type", disks[idx].Type)
setDeviceParamIfDefined(devs[idx], "size", disks[idx].Size)
setDeviceParamIfDefined(devs[idx], "storage", disks[idx].StoragePool)
setDeviceParamIfDefined(devs[idx], "storage_type", disks[idx].StoragePoolType)
setDeviceParamIfDefined(devs[idx], "cache", disks[idx].CacheMode)
setDeviceParamIfDefined(devs[idx], "format", disks[idx].DiskFormat)
}
return devs
}
func setDeviceParamIfDefined(dev proxmox.QemuDevice, key, value string) {
if value != "" {
dev[key] = value
}
}
type startedVMCleaner interface {
StopVm(*proxmox.VmRef) (string, error)
DeleteVm(*proxmox.VmRef) (string, error)
}
var _ startedVMCleaner = &proxmox.Client{}
func (s *stepStartVM) Cleanup(state multistep.StateBag) {
vmRefUntyped, ok := state.GetOk("vmRef")
// If not ok, we probably errored out before creating the VM
if !ok {
return
}
vmRef := vmRefUntyped.(*proxmox.VmRef)
// The vmRef will actually refer to the created template if everything
// finished successfully, so in that case we shouldn't cleanup
if _, ok := state.GetOk("success"); ok {
return
}
client := state.Get("proxmoxClient").(startedVMCleaner)
ui := state.Get("ui").(packer.Ui)
// Destroy the server we just created
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))
return
}
ui.Say("Deleting VM")
_, err = client.DeleteVm(vmRef)
if err != nil {
ui.Error(fmt.Sprintf("Error deleting VM. Please delete it manually: %s", err))
return
}
}

View File

@ -1,108 +0,0 @@
package proxmox
import (
"fmt"
"testing"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type startedVMCleanerMock struct {
stopVm func() (string, error)
deleteVm func() (string, error)
}
func (m startedVMCleanerMock) StopVm(*proxmox.VmRef) (string, error) {
return m.stopVm()
}
func (m startedVMCleanerMock) DeleteVm(*proxmox.VmRef) (string, error) {
return m.deleteVm()
}
var _ startedVMCleaner = &startedVMCleanerMock{}
func TestCleanupStartVM(t *testing.T) {
cs := []struct {
name string
setVmRef bool
setSuccess bool
stopVMErr error
expectCallStopVM bool
deleteVMErr error
expectCallDeleteVM bool
}{
{
name: "when vmRef state is not set, nothing should happen",
setVmRef: false,
expectCallStopVM: false,
},
{
name: "when success state is set, nothing should happen",
setVmRef: true,
setSuccess: true,
expectCallStopVM: false,
},
{
name: "when not successful, vm should be stopped and deleted",
setVmRef: true,
setSuccess: false,
expectCallStopVM: true,
expectCallDeleteVM: true,
},
{
name: "if stopping fails, DeleteVm should not be called",
setVmRef: true,
setSuccess: false,
expectCallStopVM: true,
stopVMErr: fmt.Errorf("some error"),
expectCallDeleteVM: false,
},
}
for _, c := range cs {
t.Run(c.name, func(t *testing.T) {
var stopWasCalled, deleteWasCalled bool
cleaner := startedVMCleanerMock{
stopVm: func() (string, error) {
if !c.expectCallStopVM {
t.Error("Did not expect StopVm to be called")
}
stopWasCalled = true
return "", c.stopVMErr
},
deleteVm: func() (string, error) {
if !c.expectCallDeleteVM {
t.Error("Did not expect DeleteVm to be called")
}
deleteWasCalled = true
return "", c.deleteVMErr
},
}
state := new(multistep.BasicStateBag)
state.Put("ui", packer.TestUi(t))
state.Put("proxmoxClient", cleaner)
if c.setVmRef {
state.Put("vmRef", proxmox.NewVmRef(1))
}
if c.setSuccess {
state.Put("success", "true")
}
step := stepStartVM{}
step.Cleanup(state)
if c.expectCallStopVM && !stopWasCalled {
t.Error("Expected StopVm to be called, but it wasn't")
}
if c.expectCallDeleteVM && !deleteWasCalled {
t.Error("Expected DeleteVm to be called, but it wasn't")
}
})
}
}

View File

@ -1,22 +0,0 @@
package proxmox
import (
"context"
"github.com/hashicorp/packer/helper/multistep"
)
// stepSuccess runs after the full build has succeeded.
//
// It sets the success state, which ensures cleanup does not remove the finished template
type stepSuccess struct{}
func (s *stepSuccess) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
// We need to ensure stepStartVM.Cleanup doesn't delete the template (no
// difference between VMs and templates when deleting)
state.Put("success", true)
return multistep.ActionContinue
}
func (s *stepSuccess) Cleanup(state multistep.StateBag) {}

View File

@ -1,119 +0,0 @@
package proxmox
import (
"context"
"errors"
"fmt"
"log"
"net"
"time"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/common/bootcommand"
commonhelper "github.com/hashicorp/packer/helper/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
)
// stepTypeBootCommand takes the started VM, and sends the keystrokes required to start
// the installation process such that Packer can later reach the VM over SSH/WinRM
type stepTypeBootCommand struct {
bootcommand.BootConfig
Ctx interpolate.Context
}
type bootCommandTemplateData struct {
HTTPIP string
HTTPPort uint
}
type commandTyper interface {
MonitorCmd(*proxmox.VmRef, string) (map[string]interface{}, error)
}
var _ commandTyper = &proxmox.Client{}
func (s *stepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
c := state.Get("config").(*Config)
client := state.Get("proxmoxClient").(commandTyper)
vmRef := state.Get("vmRef").(*proxmox.VmRef)
if len(s.BootCommand) == 0 {
log.Println("No boot command given, skipping")
return multistep.ActionContinue
}
if int64(s.BootWait) > 0 {
ui.Say(fmt.Sprintf("Waiting %s for boot", s.BootWait.String()))
select {
case <-time.After(s.BootWait):
break
case <-ctx.Done():
return multistep.ActionHalt
}
}
httpIP, err := hostIP()
if err != nil {
err := fmt.Errorf("Failed to determine host IP: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
common.SetHTTPIP(httpIP)
s.Ctx.Data = &bootCommandTemplateData{
HTTPIP: httpIP,
HTTPPort: state.Get("http_port").(uint),
}
ui.Say("Typing the boot command")
d := NewProxmoxDriver(client, vmRef, c.BootKeyInterval)
command, err := interpolate.Render(s.FlatBootCommand(), &s.Ctx)
if err != nil {
err := fmt.Errorf("Error preparing boot command: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
seq, err := bootcommand.GenerateExpressionSequence(command)
if err != nil {
err := fmt.Errorf("Error generating boot command: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if err := seq.Do(ctx, d); err != nil {
err := fmt.Errorf("Error running boot command: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (*stepTypeBootCommand) Cleanup(multistep.StateBag) {
commonhelper.RemoveSharedStateFile("ip", "")
}
func hostIP() (string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return "", err
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
return ipnet.IP.String(), nil
}
}
}
return "", errors.New("No host IP found")
}

View File

@ -1,128 +0,0 @@
package proxmox
import (
"context"
"fmt"
"strings"
"testing"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer/common/bootcommand"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type commandTyperMock struct {
monitorCmd func(*proxmox.VmRef, string) (map[string]interface{}, error)
}
func (m commandTyperMock) MonitorCmd(ref *proxmox.VmRef, cmd string) (map[string]interface{}, error) {
return m.monitorCmd(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: "simple boot command is typed",
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"hello"}}},
expectCallMonitorCmd: 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: "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: "without boot command monitorcmd should not be called",
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{}}},
expectCallMonitorCmd: false,
expectedAction: multistep.ActionContinue,
},
{
name: "invalid boot command template function",
builderConfig: &Config{BootConfig: bootcommand.BootConfig{BootCommand: []string{"{{ foo }}"}}},
expectCallMonitorCmd: 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: "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,
},
}
for _, c := range cs {
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)
}
accumulator.WriteString(strings.TrimPrefix(cmd, "sendkey "))
return c.monitorCmdRet, c.monitorCmdErr
},
}
state := new(multistep.BasicStateBag)
state.Put("ui", packer.TestUi(t))
state.Put("config", c.builderConfig)
state.Put("http_port", uint(0))
state.Put("vmRef", proxmox.NewVmRef(1))
state.Put("proxmoxClient", typer)
step := stepTypeBootCommand{
c.builderConfig.BootConfig,
c.builderConfig.ctx,
}
action := step.Run(context.TODO(), state)
step.Cleanup(state)
if action != c.expectedAction {
t.Errorf("Expected action to be %v, got %v", c.expectedAction, action)
}
if c.expectedKeysSent != accumulator.String() {
t.Errorf("Expected keystrokes to be %q, got %q", c.expectedKeysSent, accumulator.String())
}
})
}
}

View File

@ -40,7 +40,6 @@ import (
parallelsisobuilder "github.com/hashicorp/packer/builder/parallels/iso"
parallelspvmbuilder "github.com/hashicorp/packer/builder/parallels/pvm"
profitbricksbuilder "github.com/hashicorp/packer/builder/profitbricks"
proxmoxbuilder "github.com/hashicorp/packer/builder/proxmox"
qemubuilder "github.com/hashicorp/packer/builder/qemu"
scalewaybuilder "github.com/hashicorp/packer/builder/scaleway"
tencentcloudcvmbuilder "github.com/hashicorp/packer/builder/tencentcloud/cvm"
@ -119,7 +118,6 @@ var Builders = map[string]packer.Builder{
"parallels-iso": new(parallelsisobuilder.Builder),
"parallels-pvm": new(parallelspvmbuilder.Builder),
"profitbricks": new(profitbricksbuilder.Builder),
"proxmox": new(proxmoxbuilder.Builder),
"qemu": new(qemubuilder.Builder),
"scaleway": new(scalewaybuilder.Builder),
"tencentcloud-cvm": new(tencentcloudcvmbuilder.Builder),

28
common/iochan/iochan.go Normal file
View File

@ -0,0 +1,28 @@
package iochan
import (
"bufio"
"io"
)
// LineReader takes an io.Reader and produces the contents of the reader on the
// returned channel. Internally bufio.NewScanner is used, io.ScanLines parses
// lines and returns them without carriage return. Scan can panic if the split
// function returns too many empty tokens without advancing the input.
//
// The channel will be closed either by reaching the end of the input or an
// error.
func LineReader(r io.Reader) <-chan string {
ch := make(chan string)
go func() {
scanner := bufio.NewScanner(r)
defer close(ch)
for scanner.Scan() {
ch <- scanner.Text()
}
}()
return ch
}

View File

@ -0,0 +1,28 @@
package iochan
import (
"bytes"
"reflect"
"strings"
"testing"
)
func TestLineReader(t *testing.T) {
data := []string{"foo", "bar", "baz"}
buf := new(bytes.Buffer)
buf.WriteString(strings.Join(data, "\n") + "\n")
ch := LineReader(buf)
var result []string
expected := data
for v := range ch {
result = append(result, v)
}
if !reflect.DeepEqual(result, expected) {
t.Fatalf("unexpected results: %#v", result)
}
}

115
go.mod
View File

@ -3,117 +3,74 @@ module github.com/hashicorp/packer
require (
github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1
github.com/Azure/azure-sdk-for-go v17.3.1+incompatible
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Azure/go-autorest v10.12.0+incompatible
github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4 // indirect
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895 // indirect
github.com/Jeffail/gabs v1.1.1 // indirect
github.com/Microsoft/go-winio v0.4.11 // indirect
github.com/NYTimes/gziphandler v1.0.1 // indirect
github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/SAP/go-hdb v0.13.1 // indirect
github.com/SermoDigital/jose v0.9.1 // indirect
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af // indirect
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f
github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd // indirect
github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607 // indirect
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6 // indirect
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43
github.com/armon/go-metrics v0.0.0-20180713145231-3c58d8115a78 // indirect
github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7 // indirect
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/aws/aws-sdk-go v1.16.24
github.com/bgentry/speakeasy v0.0.0-20150902231413-36e9cfdd6909 // indirect
github.com/biogo/hts v0.0.0-20160420073057-50da7d4131a3
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 // indirect
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/cenkalti/backoff v2.1.0+incompatible // indirect
github.com/cheggaaa/pb v1.0.27
github.com/circonus-labs/circonus-gometrics v2.2.5+incompatible // indirect
github.com/circonus-labs/circonusllhist v0.1.3 // indirect
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 // indirect
github.com/creack/goselect v0.0.0-20180210034346-528c74964609 // indirect
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f // indirect
github.com/denverdino/aliyungo v0.0.0-20190220033614-36e2ae938978
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/digitalocean/godo v1.7.3
github.com/digitalocean/godo v1.11.1
github.com/dnaeon/go-vcr v1.0.0 // indirect
github.com/docker/docker v0.0.0-20170406124027-fa3e2d5ab9b5 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.3.3 // indirect
github.com/duosecurity/duo_api_golang v0.0.0-20181210160733-61e0defebf22 // indirect
github.com/docker/docker v0.0.0-20180422163414-57142e89befe // indirect
github.com/dylanmei/iso8601 v0.1.0 // indirect
github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08
github.com/elazarl/go-bindata-assetfs v1.0.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/go-ini/ini v1.25.4
github.com/go-ldap/ldap v2.5.1+incompatible // indirect
github.com/go-sql-driver/mysql v1.4.1 // indirect
github.com/go-test/deep v1.0.1 // indirect
github.com/gocql/gocql v0.0.0-20181124151448-70385f88b28b // indirect
github.com/gofrs/flock v0.7.0
github.com/gogo/protobuf v1.2.0 // indirect
github.com/gofrs/flock v0.7.1
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/google/go-cmp v0.2.0
github.com/google/shlex v0.0.0-20150127133951-6f45313302b9
github.com/google/uuid v0.0.0-20171129191014-dec09d789f3d
github.com/google/uuid v1.0.0
github.com/gophercloud/gophercloud v0.0.0-20180903124057-ea7289ebdf06
github.com/gophercloud/utils v0.0.0-20190124192022-a5c25e7a53a6
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
github.com/gorilla/websocket v0.0.0-20170319172727-a91eba7f9777 // indirect
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
github.com/hashicorp/consul v0.0.0-20180807174550-3e6313bebbf0
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce
github.com/hashicorp/consul v1.4.0
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.2.0
github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f // indirect
github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa // indirect
github.com/hashicorp/go-memdb v0.0.0-20181108192425-032f93b25bec // indirect
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect
github.com/hashicorp/go-multierror v0.0.0-20150916205742-d30f09973e19
github.com/hashicorp/go-multierror v1.0.0
github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79
github.com/hashicorp/go-plugin v0.0.0-20181030172320-54b6ff97d818 // indirect
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 // indirect
github.com/hashicorp/go-retryablehttp v0.5.2 // indirect
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 // indirect
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 // indirect
github.com/hashicorp/go-uuid v0.0.0-20160329185618-73d19cdc2bf0
github.com/hashicorp/go-uuid v1.0.1
github.com/hashicorp/go-version v1.1.0
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47 // indirect
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce // indirect
github.com/hashicorp/memberlist v0.1.0 // indirect
github.com/hashicorp/serf v0.0.0-20180530155958-984a73625de3 // indirect
github.com/hashicorp/vault v0.0.0-20180724215049-b9adaf9c6959
github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20181106190520-2236f141171e // indirect
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/serf v0.8.2 // indirect
github.com/hashicorp/vault v1.1.0
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d
github.com/hetznercloud/hcloud-go v1.12.0
github.com/hyperonecom/h1-client-go v0.0.0-20190122232013-cf38e8387775
github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee // indirect
github.com/joyent/triton-go v0.0.0-20180116165742-545edbe0d564
github.com/jtolds/gls v4.2.1+incompatible // indirect
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1
github.com/keybase/go-crypto v0.0.0-20181127160227-255a5089e85a // indirect
github.com/klauspost/compress v0.0.0-20160131094358-f86d2e6d8a77 // indirect
github.com/klauspost/cpuid v0.0.0-20160106104451-349c67577817 // indirect
github.com/klauspost/crc32 v0.0.0-20160114101742-999f3125931f // indirect
github.com/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec
github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 // indirect
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 // indirect
github.com/lib/pq v1.0.0 // indirect
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c // indirect
github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c // indirect
github.com/masterzen/simplexml v0.0.0-20140219194429-95ba30457eb1 // indirect
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
github.com/masterzen/winrm v0.0.0-20180224160350-7e40f93ae939
github.com/mattn/go-tty v0.0.0-20190402035014-76a2065f1a95
github.com/mattn/go-tty v0.0.0-20190407112021-83fae09cc007
github.com/miekg/dns v1.1.1 // indirect
github.com/mitchellh/cli v0.0.0-20170908181043-65fcae5817c8
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/cli v1.0.0
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/iochan v1.0.1-0.20190408094311-e9f5309a3061
github.com/mitchellh/mapstructure v0.0.0-20180111000720-b4575eea38cc
github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784
@ -125,52 +82,36 @@ require (
github.com/olekukonko/tablewriter v0.0.0-20180105111133-96aac992fc8b
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.4.3 // indirect
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/opencontainers/runc v0.1.1 // indirect
github.com/oracle/oci-go-sdk v1.8.0
github.com/ory/dockertest v3.3.2+incompatible // indirect
github.com/packer-community/winrmcp v0.0.0-20180921204643-0fd363d6159a
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pierrec/lz4 v0.0.0-20160112163551-383c0d87b5dd
github.com/pierrec/xxHash v0.0.0-20160112165351-5a004441f897 // indirect
github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e
github.com/pierrec/lz4 v2.0.5+incompatible
github.com/pkg/errors v0.8.0
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca
github.com/posener/complete v0.0.0-20170908125245-88e59760adad
github.com/posener/complete v1.1.1
github.com/profitbricks/profitbricks-sdk-go v4.0.2+incompatible
github.com/prometheus/client_golang v0.9.2 // indirect
github.com/renstrom/fuzzysearch v0.0.0-20160331204855-2d205ac6ec17 // indirect
github.com/rwtodd/Go.Sed v0.0.0-20170507045331-d6d5d585814e
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735 // indirect
github.com/satori/go.uuid v0.0.0-20170321230731-5bf94b69c6b6 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/scaleway/scaleway-cli v0.0.0-20180921094345-7b12c9699d70
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
github.com/sirupsen/logrus v0.0.0-20180315010703-90150a8ed11b // indirect
github.com/sirupsen/logrus v1.2.0 // indirect
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect
github.com/stretchr/testify v1.2.2
github.com/stretchr/testify v1.3.0
github.com/tencentcloud/tencentcloud-sdk-go v0.0.0-20181220135002-f1744d40d346
github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9 // indirect
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 // indirect
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1
github.com/ulikunitz/xz v0.5.5
github.com/vmware/govmomi v0.0.0-20170707011325-c2105a174311
github.com/xanzy/go-cloudstack v2.4.1+incompatible
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6
google.golang.org/api v0.1.0
google.golang.org/appengine v1.4.0 // indirect
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/h2non/gock.v1 v1.0.12 // indirect
gopkg.in/jarcoal/httpmock.v1 v1.0.0-20181117152235-275e9df93516 // indirect
gopkg.in/ldap.v2 v2.5.1 // indirect
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect
gotest.tools v2.2.0+incompatible // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
)

284
go.sum
View File

@ -1,4 +1,3 @@
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
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.36.0 h1:+aCSj7tOo2LODWVEuZDZeGCckdt6MlSF+X/rB3wUiS8=
@ -12,8 +11,6 @@ github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1 h1:RMTyvS5bjvSWiUcfqfr/E2px
github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1/go.mod h1:61apmbkVJH4kg+38ftT+/l0XxdUCVnHggqcOTqZRSEE=
github.com/Azure/azure-sdk-for-go v17.3.1+incompatible h1:9Nzge8xxnYm5lVRkvTpG1odiDN0fYDorQwVEaVfg1+g=
github.com/Azure/azure-sdk-for-go v17.3.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v10.12.0+incompatible h1:6YphwUK+oXbzvCc1fd5VrnxCekwzDkpA7gUEbci2MvI=
github.com/Azure/go-autorest v10.12.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4 h1:pSm8mp0T2OH2CPmPDPtwHPr3VAQaOwVF/JbllOPP4xA=
@ -21,22 +18,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzS
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895 h1:dmc/C8bpE5VkQn65PNbbyACDC8xw8Hpp/NEurdPmQDQ=
github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E=
github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/NYTimes/gziphandler v1.0.1 h1:iLrQrdwjDd52kHDA5op2UBJFjmOb9g+7scBan4RN8F0=
github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
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/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/SAP/go-hdb v0.13.1 h1:BuZlUZtqbF/oVSQ8Vp+/+wOtcBLh55zwMV7XnvYcz8g=
github.com/SAP/go-hdb v0.13.1/go.mod h1:etBT+FAi1t5k3K3tf5vQTnosgYmhDkRi8jEnQqCnxF0=
github.com/SermoDigital/jose v0.9.1 h1:atYaHPD3lPICcbK1owly3aPm0iaJGSGPi0WD4vLznv8=
github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA=
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/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f h1:jI4DIE5Vf4oRaHfthB0oRhU+yuYuoOTurDzwAlskP00=
@ -50,74 +33,47 @@ github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6 h1:uZuxRZCz65cG1o
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43 h1:ePCAQPf5tUc5IMcUvu6euhSGna7jzs7eiXtJXHig6Zc=
github.com/approvals/go-approval-tests v0.0.0-20160714161514-ad96e53bea43/go.mod h1:S6puKjZ9ZeqUPBv2hEBnMZGcM2J6mOsDRQcmxkMAND0=
github.com/armon/go-metrics v0.0.0-20180713145231-3c58d8115a78 h1:mdRSArcFLfW0VoL34LZAKSz6LkkK4jFxVx2xYavACMg=
github.com/armon/go-metrics v0.0.0-20180713145231-3c58d8115a78/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7 h1:MBXhrxjNkjdqJysfNbKMMPFNXlz6EzpOnPcsoYBeD3E=
github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
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.24 h1:I/A3Hwbgs3IEAP6v1bFpHKXiT7wZDoToX9cb00nxZnM=
github.com/aws/aws-sdk-go v1.16.24/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
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.0.0-20150902231413-36e9cfdd6909 h1:mUVWHQ4tjVv86uJhxSbYqwdz4o+Imcl6HoZtoaqC3zM=
github.com/bgentry/speakeasy v0.0.0-20150902231413-36e9cfdd6909/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
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/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/cenkalti/backoff v2.1.0+incompatible h1:FIRvWBZrzS4YC7NT5cOuZjexzFvIr+Dbi6aD1cZaNBk=
github.com/cenkalti/backoff v2.1.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cheggaaa/pb v1.0.27 h1:wIkZHkNfC7R6GI5w7l/PdAdzXzlrbcI3p8OAlnkTsnc=
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/circonus-labs/circonus-gometrics v2.2.5+incompatible h1:KsuY3ogbxgVv3FNhbLUoT+SE9znoWEUIuChSIT4HukI=
github.com/circonus-labs/circonus-gometrics v2.2.5+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/goselect v0.0.0-20180210034346-528c74964609 h1:FSxXMd2wCHj6GqgBdo4UtVA9R2aieIDvSniepqyOppU=
github.com/creack/goselect v0.0.0-20180210034346-528c74964609/go.mod h1:gHrIcH/9UZDn2qgeTUeW5K9eZsVYCH6/60J/FHysWyE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f h1:WH0w/R4Yoey+04HhFxqZ6VX6I0d7RMyw5aXQ9UTvQPs=
github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/denverdino/aliyungo v0.0.0-20190220033614-36e2ae938978 h1:oyfbRmu7YnytN4bXhvJPY1HPgUL52j5AxtgGDU0bMVs=
github.com/denverdino/aliyungo v0.0.0-20190220033614-36e2ae938978/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/digitalocean/godo v1.7.3 h1:0tFPilFBDsVSiAKF8hyzj/MAmRYxNc5MGhAiYZYVrpo=
github.com/digitalocean/godo v1.7.3/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
github.com/digitalocean/godo v1.11.1 h1:OsTh37YFKk+g6DnAOrkXJ9oDArTkRx5UTkBJ2EWAO38=
github.com/digitalocean/godo v1.11.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU=
github.com/dnaeon/go-vcr v1.0.0 h1:1QZ+ahihvRvppcJnFvuoHAdnZTf1PqKjO4Ftr1cfQTo=
github.com/dnaeon/go-vcr v1.0.0/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/docker v0.0.0-20170406124027-fa3e2d5ab9b5 h1:DwY2bFs8p+xf2WaQewx2hnGdjYR5K4UAaxcNPyKkTek=
github.com/docker/docker v0.0.0-20170406124027-fa3e2d5ab9b5/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/duosecurity/duo_api_golang v0.0.0-20181210160733-61e0defebf22 h1:RqZJa9Ohzpyr5OADCKz/8t0vtdD2vczMdjqCbvTYz7o=
github.com/duosecurity/duo_api_golang v0.0.0-20181210160733-61e0defebf22/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo=
github.com/docker/docker v0.0.0-20180422163414-57142e89befe h1:VW8TnWi0CZgg7oCv0wH6evNwkzcJg/emnw4HrVIWws4=
github.com/docker/docker v0.0.0-20180422163414-57142e89befe/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI=
github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ=
github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 h1:0bp6/GrNOrTDtSXe9YYGCwf8jp5Fb/b+4a6MTRm4qzY=
github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08/go.mod h1:VBVDFSBXCIW8JaHQpI8lldSKfYaLMzP9oyq6IJ4fhzY=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
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=
@ -125,19 +81,9 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
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/go-ldap/ldap v2.5.1+incompatible h1:Opaoft5zMW8IU/VRULB0eGMBQ9P5buRvCW6sFTRmMn8=
github.com/go-ldap/ldap v2.5.1+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg=
github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gocql/gocql v0.0.0-20181124151448-70385f88b28b h1:dnUw9Ih14dCKzbtZxm+pwQRYIb+9ypiwtZgsCQN4zmg=
github.com/gocql/gocql v0.0.0-20181124151448-70385f88b28b/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
github.com/gofrs/flock v0.7.0 h1:pGFUjl501gafK9HBt1VGL1KCOd/YhIooID+xgyJCf3g=
github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
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=
@ -145,12 +91,11 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
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=
@ -158,8 +103,7 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/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 v0.0.0-20171129191014-dec09d789f3d h1:rXQlD9GXkjA/PQZhmEaF/8Pj/sJfdZJK7GJG0gkS8I0=
github.com/google/uuid v0.0.0-20171129191014-dec09d789f3d/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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=
@ -173,71 +117,55 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
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/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
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/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/consul v0.0.0-20180807174550-3e6313bebbf0 h1:vh/G7ew4mi/FcKNrRk4x1N1fWYzYB5/AaSHr9W+wrF4=
github.com/hashicorp/consul v0.0.0-20180807174550-3e6313bebbf0/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/consul v1.4.0 h1:PQTW4xCuAExEiSbhrsFsikzbW5gVBoi74BjUvYFyKHw=
github.com/hashicorp/consul v1.4.0/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de h1:XDCSythtg8aWSRSO29uwhgh7b127fWr+m5SemqjSUL8=
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.2.0 h1:E05bVPilzyh2yXgT6srn7WEkfMZaH+LuX9tDJw/4kaE=
github.com/hashicorp/go-getter v1.2.0/go.mod h1:/O1k/AizTN0QmfEKknCYGvICeyKUDqCYA8vvWtGWDeQ=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f h1:Yv9YzBlAETjy6AOX9eLBZ3nshNVRREgerT/3nvxlGho=
github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa h1:0nA8i+6Rwqaq9xlpmVxxTwk6rxiEhX+E6Wh4vPNHiS8=
github.com/hashicorp/go-immutable-radix v0.0.0-20180129170900-7f3cd4390caa/go.mod h1:6ij3Z20p+OhOkCSrA0gImAWoHYQRGbnlcuk6XYTiaRw=
github.com/hashicorp/go-memdb v0.0.0-20181108192425-032f93b25bec h1:A1nDk9UOKWPTQh5YcCnbwNbqj23e5pggf4HxGBulhr8=
github.com/hashicorp/go-memdb v0.0.0-20181108192425-032f93b25bec/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE=
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c h1:BTAbnbegUIMB6xmQCwWE8yRzbA4XSpnZY5hvRJC188I=
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20150916205742-d30f09973e19 h1:gb61U/o4ZJ6TRYvZqJUKYidIhJOEAvNyVMesryROxAY=
github.com/hashicorp/go-multierror v0.0.0-20150916205742-d30f09973e19/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
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=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79 h1:RKu7yAXZTaQsxj1K9GDsh+QVw0+Wu1SWHxtbFN0n+hE=
github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79/go.mod h1:09jT3Y/OIsjTjQ2+3bkVNPDKqWcGIYYvjB2BEKVUdvc=
github.com/hashicorp/go-plugin v0.0.0-20181030172320-54b6ff97d818 h1:wA1XRGBHMdpio0gcKUtnmkwSIlCAG1qzpsr+iPyi3Y8=
github.com/hashicorp/go-plugin v0.0.0-20181030172320-54b6ff97d818/go.mod h1:Ft7ju2vWzhO0ETMKUVo12XmXmII6eSUS4rsPTkY/siA=
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6 h1:qCv4319q2q7XKn0MQbi8p37hsJ+9Xo8e6yojA73JVxk=
github.com/hashicorp/go-retryablehttp v0.0.0-20180718195005-e651d75abec6/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM=
github.com/hashicorp/go-retryablehttp v0.5.2 h1:AoISa4P4IsW0/m4T6St8Yw38gTl5GtBAgfkhYh1xAz4=
github.com/hashicorp/go-retryablehttp v0.5.2/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90 h1:VBj0QYQ0u2MCJzBfeYXGexnAl17GsH1yidnoxCqqD9E=
github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90/go.mod h1:o4zcYY1e0GEZI6eSEr+43QDYmuGglw1qSO6qdHUHCgg=
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 h1:7YOlAIO2YWnJZkQp7B5eFykaIY7C9JndqAFQyVV5BhM=
github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-uuid v0.0.0-20160329185618-73d19cdc2bf0 h1:YnYV/qHLtjZmhFnWaSsNqVAUhxCuPKRe5wDGpOKYL/U=
github.com/hashicorp/go-uuid v0.0.0-20160329185618-73d19cdc2bf0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0=
github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
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.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47 h1:UnszMmmmm5vLwWzDjTFVIkfhvWF1NdrmChl8L2NUDCw=
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce h1:xdsDDbiBDQTKASoGEZ+pEmF1OnWuu8AQ9I8iNbHNeno=
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/memberlist v0.1.0 h1:qSsCiC0WYD39lbSitKNt40e30uorm2Ss/d4JGU1hzH8=
github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE=
github.com/hashicorp/serf v0.0.0-20180530155958-984a73625de3 h1:NUr1hG6WO9sI1x8ofSimmpqfJ+rEHiHP/PLEA33rcfQ=
github.com/hashicorp/serf v0.0.0-20180530155958-984a73625de3/go.mod h1:h/Ru6tmZazX7WO/GDmwdpS975F019L4t5ng5IgwbNrE=
github.com/hashicorp/vault v0.0.0-20180724215049-b9adaf9c6959 h1:PyVs2CB7Hxgl1kU0tWAVpagLK3N+MC0eeyKmG+L5VPI=
github.com/hashicorp/vault v0.0.0-20180724215049-b9adaf9c6959/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0=
github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20181106190520-2236f141171e h1:2Hwd2Yi0/qjAC6ujOu6WBVXAak9Snuw0LTYdZkqIdKM=
github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20181106190520-2236f141171e/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
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/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=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/vault v1.1.0 h1:v79NUgO5xCZnXVzUkIqFOXtP8YhpnHAi1fk3eo9cuOE=
github.com/hashicorp/vault v1.1.0/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hetznercloud/hcloud-go v1.12.0 h1:ugZO8a8ADekqSWi7xWlcs6pxr4QE0tw5VnyjXcL5n28=
github.com/hetznercloud/hcloud-go v1.12.0/go.mod h1:g5pff0YNAZywQaivY/CmhUYFVp7oP0nu3MiODC2W4Hw=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hyperonecom/h1-client-go v0.0.0-20190122232013-cf38e8387775 h1:MIteIoIQ5nFoOmwEHPDsqng8d0dtKj3lCnQCwGvtxXc=
github.com/hyperonecom/h1-client-go v0.0.0-20190122232013-cf38e8387775/go.mod h1:R9rU87RxxmcD3DkspW9JqGBXiJyg5MA+WNCtJrBtnXs=
github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee h1:AQ/QmCk6x8ECPpf2pkPtA4lyncEEBbs8VFnVXPYKhIs=
github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe8nyZB5ouIbJQPDSR+mH6oe7xHB9VZHSUzM=
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=
@ -248,8 +176,6 @@ github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpR
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/keybase/go-crypto v0.0.0-20181127160227-255a5089e85a h1:X/UFlwD2/UV0RCy+8ITi4DmxJwk83YUH7bXwkJIHHMo=
github.com/keybase/go-crypto v0.0.0-20181127160227-255a5089e85a/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
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=
@ -259,6 +185,8 @@ github.com/klauspost/crc32 v0.0.0-20160114101742-999f3125931f h1:UD9YLTi2aBhdOOT
github.com/klauspost/crc32 v0.0.0-20160114101742-999f3125931f/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
github.com/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec h1:PYqF3Tiz2W2Ag0ezyDhAobWDWlrFv7U+qct4spLeDBM=
github.com/klauspost/pgzip v0.0.0-20151221113845-47f36e165cec/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 h1:YUrU1/jxRqnt0PSrKj1Uj/wEjk/fjnE80QFfi2Zlj7Q=
github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169/go.mod h1:glhvuHOU9Hy7/8PwwdtnarXqLagOX0b/TbZx2zLMqEg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@ -269,46 +197,37 @@ 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=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c h1:N7uWGS2fTwH/4BwxbHiJZNAFTSJ5yPU0emHsQWvkxEY=
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c h1:FMUOnVGy8nWk1cvlMCAoftRItQGMxI0vzJ3dQjeZTCE=
github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE=
github.com/masterzen/simplexml v0.0.0-20140219194429-95ba30457eb1 h1:cLEbk5d4t8CDqmQtCMc2lk91cflxOrj31k9LTIabPoA=
github.com/masterzen/simplexml v0.0.0-20140219194429-95ba30457eb1/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc=
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 h1:2ZKn+w/BJeL43sCxI2jhPLRv73oVVOjEKZjKkflyqxg=
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc=
github.com/masterzen/winrm v0.0.0-20180224160350-7e40f93ae939 h1:cRFHA33ER97Xy5jmjS519OXCS/yE3AT3zdbQAg0Z53g=
github.com/masterzen/winrm v0.0.0-20180224160350-7e40f93ae939/go.mod h1:CfZSN7zwz5gJiFhZJz49Uzk7mEBHIceWmbFmYx7Hf7E=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-tty v0.0.0-20190402035014-76a2065f1a95 h1:zyW7ieMaS0tXk1KgXxFgQ+HAMmxYpwe7MiAzE4C/rkE=
github.com/mattn/go-tty v0.0.0-20190402035014-76a2065f1a95/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/mattn/go-tty v0.0.0-20190407112021-83fae09cc007 h1:xjZxmVDmDZoEsl2gV0qD0pyBH+wXmJIZd27wsNFphJk=
github.com/mattn/go-tty v0.0.0-20190407112021-83fae09cc007/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=
github.com/mitchellh/cli v0.0.0-20170908181043-65fcae5817c8 h1:ZPmOsqSxGDUqFp0ErYpJDIfaBRBGvQv0qDPr37kZBrk=
github.com/mitchellh/cli v0.0.0-20170908181043-65fcae5817c8/go.mod h1:oGumspjLm2kTyiT1QMGpFqRlmxnKHfCvhZEVnx+5UeE=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-fs v0.0.0-20180402234041-7b48fa161ea7 h1:PXPMDtfqV+rZJshQHOiwUFqlqErXaAcuWy+/ZmyRfNc=
github.com/mitchellh/go-fs v0.0.0-20180402234041-7b48fa161ea7/go.mod h1:g7SZj7ABpStq3tM4zqHiVEG5un/DZ1+qJJKO7qx1EvU=
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
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/iochan v0.0.0-20150529224432-87b45ffd0e95 h1:aHWVygBsLb+Kls/35B3tevL1hvDxZ0UklPA0BmhqTEk=
github.com/mitchellh/iochan v0.0.0-20150529224432-87b45ffd0e95/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/iochan v1.0.1-0.20190408094311-e9f5309a3061 h1:BSEloc+wp5WA/fu0jw5HBWOfoKLdvpqi38ZP22eNemg=
github.com/mitchellh/iochan v1.0.1-0.20190408094311-e9f5309a3061/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v0.0.0-20180111000720-b4575eea38cc h1:5T6hzGUO5OrL6MdYXYoLQtRWJDDgjdlOVBn9mIqGY1g=
github.com/mitchellh/mapstructure v0.0.0-20180111000720-b4575eea38cc/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/panicwrap v0.0.0-20170106182340-fce601fe5557 h1:w1QuuAA2km2Hax+EPamrq5ZRBeaNv2vsjvgB4an0zoU=
@ -327,8 +246,6 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE
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/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20180105111133-96aac992fc8b h1:LGItPaClbzopugAomw5VFKnG3h1dUr9QW5KOU+m8gu0=
github.com/olekukonko/tablewriter v0.0.0-20180105111133-96aac992fc8b/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -336,57 +253,36 @@ 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/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
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/ory/dockertest v3.3.2+incompatible h1:uO+NcwH6GuFof/Uz8yzjNi1g0sGT5SLAJbdBvD8bUYc=
github.com/ory/dockertest v3.3.2+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
github.com/packer-community/winrmcp v0.0.0-20180921204643-0fd363d6159a h1:A3QMuteviunoaY/8ex+RKFqwhcZJ/Cf3fCW3IwL2wx4=
github.com/packer-community/winrmcp v0.0.0-20180921204643-0fd363d6159a/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4 v0.0.0-20160112163551-383c0d87b5dd h1:0EXhZlgCFcAZjhD6f6yqIINBBBym9seHr6AkvAWUgN8=
github.com/pierrec/lz4 v0.0.0-20160112163551-383c0d87b5dd/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/xxHash v0.0.0-20160112165351-5a004441f897 h1:jp3jc/PyyTrTKjJJ6rWnhTbmo7tGgBFyG9AL5FIrO1I=
github.com/pierrec/xxHash v0.0.0-20160112165351-5a004441f897/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I=
github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e h1:+RHxT/gm0O3UF7nLJbdNzAmULvCFt4XfXHWzh3XI/zs=
github.com/pkg/errors v0.0.0-20171216070316-e881fd58d78e/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca h1:k8gsErq3rkcbAyCnpOycQsbw88NjCHk7L3KfBZKhQDQ=
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v0.0.0-20170908125245-88e59760adad h1:jTlrcNQXxCpT8NU0MG1aiUkfAiTlm+W6KPScysqjvdA=
github.com/posener/complete v0.0.0-20170908125245-88e59760adad/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
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_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
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/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/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/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=
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735 h1:7YvPJVmEeFHR1Tj9sZEYsmarJEQfMVYpd/Vyy/A8dqE=
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/satori/go.uuid v0.0.0-20170321230731-5bf94b69c6b6 h1:7PFDlUz5/yGp8w21PuZGgEfN7ZF7OXvgAIDjwih82Gs=
github.com/satori/go.uuid v0.0.0-20170321230731-5bf94b69c6b6/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/scaleway/scaleway-cli v0.0.0-20180921094345-7b12c9699d70 h1:DaqC32ZwOuO4ctgg9qAdKnlQxwFPkKmCOEqwSNwYy7c=
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=
@ -414,23 +310,24 @@ github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1l
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 v0.0.0-20180315010703-90150a8ed11b h1:m1cItYkpJSJ3ZKPEV/XKbZTcCaJHY1qF+R9GisLZ4kw=
github.com/sirupsen/logrus v0.0.0-20180315010703-90150a8ed11b/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.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=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
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 v0.0.0-20181220135002-f1744d40d346 h1:a014AaXz7AISMePv8xKRffUZZkr5z2XmSDf41gRV3+A=
github.com/tencentcloud/tencentcloud-sdk-go v0.0.0-20181220135002-f1744d40d346/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4=
github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9 h1:/Bsw4C+DEdqPjt8vAqaC9LAqpAQnaCQQqmolqq3S1T4=
github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1 h1:U6ufy3mLDgg9RYupntOvAF7xCmNNquyKaYaaVHo1Nnk=
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
@ -443,14 +340,19 @@ go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
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=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
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-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
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/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
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=
@ -458,21 +360,26 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsq
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
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/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
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=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
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-20181213200352-4d1cda033e06 h1:0oC8rFnE+74kEmuHZ46F6KHsMr5Gx2gUQPuNz28iQZM=
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6 h1:MXtOG7w2ND9qNCUZSDBGll/SpVIq7ftozR9I8/JGBHY=
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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=
@ -487,13 +394,11 @@ google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+
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=
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
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/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
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=
@ -504,36 +409,25 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
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=
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
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=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.27 h1:kJdccidYzt3CaHD1crCFTS1hxyhSi059NhOFUf03YFo=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
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 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/jarcoal/httpmock.v1 v1.0.0-20181117152235-275e9df93516 h1:H6trpavCIuipdInWrab8l34Mf+GGVfphniHostMdMaQ=
gopkg.in/jarcoal/httpmock.v1 v1.0.0-20181117152235-275e9df93516/go.mod h1:d3R+NllX3X5e0zlG1Rful3uLvsGC/Q3OHut5464DEQw=
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 h1:kb0VV7NuIojvRfzwslQeP3yArBqJHW9tOl4t38VS1jM=
gopkg.in/vmihailenco/msgpack.v2 v2.9.1/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -8,7 +8,7 @@ import (
"golang.org/x/sync/errgroup"
"github.com/mitchellh/iochan"
"github.com/hashicorp/packer/common/iochan"
)
// CmdDisconnect is a sentinel value to indicate a RemoteCmd

View File

@ -9,7 +9,7 @@ import (
"time"
"github.com/google/go-cmp/cmp"
"github.com/mitchellh/iochan"
"github.com/hashicorp/packer/common/iochan"
"golang.org/x/sync/errgroup"
)

View File

@ -3,7 +3,6 @@ package compress
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"context"
"fmt"
"io"
@ -273,8 +272,8 @@ func makeBGZFWriter(output io.WriteCloser, compressionLevel int) (io.WriteCloser
func makeLZ4Writer(output io.WriteCloser, compressionLevel int) (io.WriteCloser, error) {
lzwriter := lz4.NewWriter(output)
if compressionLevel > gzip.DefaultCompression {
lzwriter.Header.HighCompression = true
if compressionLevel > 0 {
lzwriter.Header.CompressionLevel = compressionLevel
}
return lzwriter, nil
}

View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@ -1,12 +0,0 @@
# go-ansiterm
This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
-----
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@ -1,188 +0,0 @@
package ansiterm
const LogEnv = "DEBUG_TERMINAL"
// ANSI constants
// References:
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
// -- http://vt100.net/emu/dec_ansi_parser
// -- http://vt100.net/emu/vt500_parser.svg
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
// -- http://www.inwap.com/pdp10/ansicode.txt
const (
// ECMA-48 Set Graphics Rendition
// Note:
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
ANSI_SGR_RESET = 0
ANSI_SGR_BOLD = 1
ANSI_SGR_DIM = 2
_ANSI_SGR_ITALIC = 3
ANSI_SGR_UNDERLINE = 4
_ANSI_SGR_BLINKSLOW = 5
_ANSI_SGR_BLINKFAST = 6
ANSI_SGR_REVERSE = 7
_ANSI_SGR_INVISIBLE = 8
_ANSI_SGR_LINETHROUGH = 9
_ANSI_SGR_FONT_00 = 10
_ANSI_SGR_FONT_01 = 11
_ANSI_SGR_FONT_02 = 12
_ANSI_SGR_FONT_03 = 13
_ANSI_SGR_FONT_04 = 14
_ANSI_SGR_FONT_05 = 15
_ANSI_SGR_FONT_06 = 16
_ANSI_SGR_FONT_07 = 17
_ANSI_SGR_FONT_08 = 18
_ANSI_SGR_FONT_09 = 19
_ANSI_SGR_FONT_10 = 20
_ANSI_SGR_DOUBLEUNDERLINE = 21
ANSI_SGR_BOLD_DIM_OFF = 22
_ANSI_SGR_ITALIC_OFF = 23
ANSI_SGR_UNDERLINE_OFF = 24
_ANSI_SGR_BLINK_OFF = 25
_ANSI_SGR_RESERVED_00 = 26
ANSI_SGR_REVERSE_OFF = 27
_ANSI_SGR_INVISIBLE_OFF = 28
_ANSI_SGR_LINETHROUGH_OFF = 29
ANSI_SGR_FOREGROUND_BLACK = 30
ANSI_SGR_FOREGROUND_RED = 31
ANSI_SGR_FOREGROUND_GREEN = 32
ANSI_SGR_FOREGROUND_YELLOW = 33
ANSI_SGR_FOREGROUND_BLUE = 34
ANSI_SGR_FOREGROUND_MAGENTA = 35
ANSI_SGR_FOREGROUND_CYAN = 36
ANSI_SGR_FOREGROUND_WHITE = 37
_ANSI_SGR_RESERVED_01 = 38
ANSI_SGR_FOREGROUND_DEFAULT = 39
ANSI_SGR_BACKGROUND_BLACK = 40
ANSI_SGR_BACKGROUND_RED = 41
ANSI_SGR_BACKGROUND_GREEN = 42
ANSI_SGR_BACKGROUND_YELLOW = 43
ANSI_SGR_BACKGROUND_BLUE = 44
ANSI_SGR_BACKGROUND_MAGENTA = 45
ANSI_SGR_BACKGROUND_CYAN = 46
ANSI_SGR_BACKGROUND_WHITE = 47
_ANSI_SGR_RESERVED_02 = 48
ANSI_SGR_BACKGROUND_DEFAULT = 49
// 50 - 65: Unsupported
ANSI_MAX_CMD_LENGTH = 4096
MAX_INPUT_EVENTS = 128
DEFAULT_WIDTH = 80
DEFAULT_HEIGHT = 24
ANSI_BEL = 0x07
ANSI_BACKSPACE = 0x08
ANSI_TAB = 0x09
ANSI_LINE_FEED = 0x0A
ANSI_VERTICAL_TAB = 0x0B
ANSI_FORM_FEED = 0x0C
ANSI_CARRIAGE_RETURN = 0x0D
ANSI_ESCAPE_PRIMARY = 0x1B
ANSI_ESCAPE_SECONDARY = 0x5B
ANSI_OSC_STRING_ENTRY = 0x5D
ANSI_COMMAND_FIRST = 0x40
ANSI_COMMAND_LAST = 0x7E
DCS_ENTRY = 0x90
CSI_ENTRY = 0x9B
OSC_STRING = 0x9D
ANSI_PARAMETER_SEP = ";"
ANSI_CMD_G0 = '('
ANSI_CMD_G1 = ')'
ANSI_CMD_G2 = '*'
ANSI_CMD_G3 = '+'
ANSI_CMD_DECPNM = '>'
ANSI_CMD_DECPAM = '='
ANSI_CMD_OSC = ']'
ANSI_CMD_STR_TERM = '\\'
KEY_CONTROL_PARAM_2 = ";2"
KEY_CONTROL_PARAM_3 = ";3"
KEY_CONTROL_PARAM_4 = ";4"
KEY_CONTROL_PARAM_5 = ";5"
KEY_CONTROL_PARAM_6 = ";6"
KEY_CONTROL_PARAM_7 = ";7"
KEY_CONTROL_PARAM_8 = ";8"
KEY_ESC_CSI = "\x1B["
KEY_ESC_N = "\x1BN"
KEY_ESC_O = "\x1BO"
FILL_CHARACTER = ' '
)
func getByteRange(start byte, end byte) []byte {
bytes := make([]byte, 0, 32)
for i := start; i <= end; i++ {
bytes = append(bytes, byte(i))
}
return bytes
}
var toGroundBytes = getToGroundBytes()
var executors = getExecuteBytes()
// SPACE 20+A0 hex Always and everywhere a blank space
// Intermediate 20-2F hex !"#$%&'()*+,-./
var intermeds = getByteRange(0x20, 0x2F)
// Parameters 30-3F hex 0123456789:;<=>?
// CSI Parameters 30-39, 3B hex 0123456789;
var csiParams = getByteRange(0x30, 0x3F)
var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
var upperCase = getByteRange(0x40, 0x5F)
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
var lowerCase = getByteRange(0x60, 0x7E)
// Alphabetics 40-7E hex (all of upper and lower case)
var alphabetics = append(upperCase, lowerCase...)
var printables = getByteRange(0x20, 0x7F)
var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
var escapeToGroundBytes = getEscapeToGroundBytes()
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
// byte ranges below
func getEscapeToGroundBytes() []byte {
escapeToGroundBytes := getByteRange(0x30, 0x4F)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
return escapeToGroundBytes
}
func getExecuteBytes() []byte {
executeBytes := getByteRange(0x00, 0x17)
executeBytes = append(executeBytes, 0x19)
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
return executeBytes
}
func getToGroundBytes() []byte {
groundBytes := []byte{0x18}
groundBytes = append(groundBytes, 0x1A)
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
groundBytes = append(groundBytes, 0x99)
groundBytes = append(groundBytes, 0x9A)
groundBytes = append(groundBytes, 0x9C)
return groundBytes
}
// Delete 7F hex Always and everywhere ignored
// C1 Control 80-9F hex 32 additional control characters
// G1 Displayable A1-FE hex 94 additional displayable characters
// Special A0+FF hex Same as SPACE and DELETE

View File

@ -1,7 +0,0 @@
package ansiterm
type ansiContext struct {
currentChar byte
paramBuffer []byte
interBuffer []byte
}

View File

@ -1,49 +0,0 @@
package ansiterm
type csiEntryState struct {
baseState
}
func (csiState csiEntryState) Handle(b byte) (s state, e error) {
csiState.parser.logf("CsiEntry::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
return csiState.parser.csiParam, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiEntryState) Transition(s state) error {
csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
case csiState.parser.csiParam:
switch {
case sliceContains(csiParams, csiState.parser.context.currentChar):
csiState.parser.collectParam()
case sliceContains(intermeds, csiState.parser.context.currentChar):
csiState.parser.collectInter()
}
}
return nil
}
func (csiState csiEntryState) Enter() error {
csiState.parser.clear()
return nil
}

View File

@ -1,38 +0,0 @@
package ansiterm
type csiParamState struct {
baseState
}
func (csiState csiParamState) Handle(b byte) (s state, e error) {
csiState.parser.logf("CsiParam::Handle %#x", b)
nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(alphabetics, b):
return csiState.parser.ground, nil
case sliceContains(csiCollectables, b):
csiState.parser.collectParam()
return csiState, nil
case sliceContains(executors, b):
return csiState, csiState.parser.execute()
}
return csiState, nil
}
func (csiState csiParamState) Transition(s state) error {
csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
csiState.baseState.Transition(s)
switch s {
case csiState.parser.ground:
return csiState.parser.csiDispatch()
}
return nil
}

View File

@ -1,36 +0,0 @@
package ansiterm
type escapeIntermediateState struct {
baseState
}
func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
escState.parser.logf("escapeIntermediateState::Handle %#x", b)
nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(intermeds, b):
return escState, escState.parser.collectInter()
case sliceContains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeIntermediateToGroundBytes, b):
return escState.parser.ground, nil
}
return escState, nil
}
func (escState escapeIntermediateState) Transition(s state) error {
escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
escState.baseState.Transition(s)
switch s {
case escState.parser.ground:
return escState.parser.escDispatch()
}
return nil
}

View File

@ -1,47 +0,0 @@
package ansiterm
type escapeState struct {
baseState
}
func (escState escapeState) Handle(b byte) (s state, e error) {
escState.parser.logf("escapeState::Handle %#x", b)
nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case b == ANSI_ESCAPE_SECONDARY:
return escState.parser.csiEntry, nil
case b == ANSI_OSC_STRING_ENTRY:
return escState.parser.oscString, nil
case sliceContains(executors, b):
return escState, escState.parser.execute()
case sliceContains(escapeToGroundBytes, b):
return escState.parser.ground, nil
case sliceContains(intermeds, b):
return escState.parser.escapeIntermediate, nil
}
return escState, nil
}
func (escState escapeState) Transition(s state) error {
escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name())
escState.baseState.Transition(s)
switch s {
case escState.parser.ground:
return escState.parser.escDispatch()
case escState.parser.escapeIntermediate:
return escState.parser.collectInter()
}
return nil
}
func (escState escapeState) Enter() error {
escState.parser.clear()
return nil
}

View File

@ -1,90 +0,0 @@
package ansiterm
type AnsiEventHandler interface {
// Print
Print(b byte) error
// Execute C0 commands
Execute(b byte) error
// CUrsor Up
CUU(int) error
// CUrsor Down
CUD(int) error
// CUrsor Forward
CUF(int) error
// CUrsor Backward
CUB(int) error
// Cursor to Next Line
CNL(int) error
// Cursor to Previous Line
CPL(int) error
// Cursor Horizontal position Absolute
CHA(int) error
// Vertical line Position Absolute
VPA(int) error
// CUrsor Position
CUP(int, int) error
// Horizontal and Vertical Position (depends on PUM)
HVP(int, int) error
// Text Cursor Enable Mode
DECTCEM(bool) error
// Origin Mode
DECOM(bool) error
// 132 Column Mode
DECCOLM(bool) error
// Erase in Display
ED(int) error
// Erase in Line
EL(int) error
// Insert Line
IL(int) error
// Delete Line
DL(int) error
// Insert Character
ICH(int) error
// Delete Character
DCH(int) error
// Set Graphics Rendition
SGR([]int) error
// Pan Down
SU(int) error
// Pan Up
SD(int) error
// Device Attributes
DA([]string) error
// Set Top and Bottom Margins
DECSTBM(int, int) error
// Index
IND() error
// Reverse Index
RI() error
// Flush updates from previous commands
Flush() error
}

View File

@ -1,24 +0,0 @@
package ansiterm
type groundState struct {
baseState
}
func (gs groundState) Handle(b byte) (s state, e error) {
gs.parser.context.currentChar = b
nextState, err := gs.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case sliceContains(printables, b):
return gs, gs.parser.print()
case sliceContains(executors, b):
return gs, gs.parser.execute()
}
return gs, nil
}

View File

@ -1,31 +0,0 @@
package ansiterm
type oscStringState struct {
baseState
}
func (oscState oscStringState) Handle(b byte) (s state, e error) {
oscState.parser.logf("OscString::Handle %#x", b)
nextState, err := oscState.baseState.Handle(b)
if nextState != nil || err != nil {
return nextState, err
}
switch {
case isOscStringTerminator(b):
return oscState.parser.ground, nil
}
return oscState, nil
}
// See below for OSC string terminators for linux
// http://man7.org/linux/man-pages/man4/console_codes.4.html
func isOscStringTerminator(b byte) bool {
if b == ANSI_BEL || b == 0x5C {
return true
}
return false
}

View File

@ -1,151 +0,0 @@
package ansiterm
import (
"errors"
"log"
"os"
)
type AnsiParser struct {
currState state
eventHandler AnsiEventHandler
context *ansiContext
csiEntry state
csiParam state
dcsEntry state
escape state
escapeIntermediate state
error state
ground state
oscString state
stateMap []state
logf func(string, ...interface{})
}
type Option func(*AnsiParser)
func WithLogf(f func(string, ...interface{})) Option {
return func(ap *AnsiParser) {
ap.logf = f
}
}
func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
ap := &AnsiParser{
eventHandler: evtHandler,
context: &ansiContext{},
}
for _, o := range opts {
o(ap)
}
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
logFile, _ := os.Create("ansiParser.log")
logger := log.New(logFile, "", log.LstdFlags)
if ap.logf != nil {
l := ap.logf
ap.logf = func(s string, v ...interface{}) {
l(s, v...)
logger.Printf(s, v...)
}
} else {
ap.logf = logger.Printf
}
}
if ap.logf == nil {
ap.logf = func(string, ...interface{}) {}
}
ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
ap.error = errorState{baseState{name: "Error", parser: ap}}
ap.ground = groundState{baseState{name: "Ground", parser: ap}}
ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
ap.stateMap = []state{
ap.csiEntry,
ap.csiParam,
ap.dcsEntry,
ap.escape,
ap.escapeIntermediate,
ap.error,
ap.ground,
ap.oscString,
}
ap.currState = getState(initialState, ap.stateMap)
ap.logf("CreateParser: parser %p", ap)
return ap
}
func getState(name string, states []state) state {
for _, el := range states {
if el.Name() == name {
return el
}
}
return nil
}
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
for i, b := range bytes {
if err := ap.handle(b); err != nil {
return i, err
}
}
return len(bytes), ap.eventHandler.Flush()
}
func (ap *AnsiParser) handle(b byte) error {
ap.context.currentChar = b
newState, err := ap.currState.Handle(b)
if err != nil {
return err
}
if newState == nil {
ap.logf("WARNING: newState is nil")
return errors.New("New state of 'nil' is invalid.")
}
if newState != ap.currState {
if err := ap.changeState(newState); err != nil {
return err
}
}
return nil
}
func (ap *AnsiParser) changeState(newState state) error {
ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
// Exit old state
if err := ap.currState.Exit(); err != nil {
ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
return err
}
// Perform transition action
if err := ap.currState.Transition(newState); err != nil {
ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
return err
}
// Enter new state
if err := newState.Enter(); err != nil {
ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
return err
}
ap.currState = newState
return nil
}

View File

@ -1,99 +0,0 @@
package ansiterm
import (
"strconv"
)
func parseParams(bytes []byte) ([]string, error) {
paramBuff := make([]byte, 0, 0)
params := []string{}
for _, v := range bytes {
if v == ';' {
if len(paramBuff) > 0 {
// Completed parameter, append it to the list
s := string(paramBuff)
params = append(params, s)
paramBuff = make([]byte, 0, 0)
}
} else {
paramBuff = append(paramBuff, v)
}
}
// Last parameter may not be terminated with ';'
if len(paramBuff) > 0 {
s := string(paramBuff)
params = append(params, s)
}
return params, nil
}
func parseCmd(context ansiContext) (string, error) {
return string(context.currentChar), nil
}
func getInt(params []string, dflt int) int {
i := getInts(params, 1, dflt)[0]
return i
}
func getInts(params []string, minCount int, dflt int) []int {
ints := []int{}
for _, v := range params {
i, _ := strconv.Atoi(v)
// Zero is mapped to the default value in VT100.
if i == 0 {
i = dflt
}
ints = append(ints, i)
}
if len(ints) < minCount {
remaining := minCount - len(ints)
for i := 0; i < remaining; i++ {
ints = append(ints, dflt)
}
}
return ints
}
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
switch param {
case "?3":
return ap.eventHandler.DECCOLM(set)
case "?6":
return ap.eventHandler.DECOM(set)
case "?25":
return ap.eventHandler.DECTCEM(set)
}
return nil
}
func (ap *AnsiParser) hDispatch(params []string) error {
if len(params) == 1 {
return ap.modeDispatch(params[0], true)
}
return nil
}
func (ap *AnsiParser) lDispatch(params []string) error {
if len(params) == 1 {
return ap.modeDispatch(params[0], false)
}
return nil
}
func getEraseParam(params []string) int {
param := getInt(params, 0)
if param < 0 || 3 < param {
param = 0
}
return param
}

View File

@ -1,119 +0,0 @@
package ansiterm
func (ap *AnsiParser) collectParam() error {
currChar := ap.context.currentChar
ap.logf("collectParam %#x", currChar)
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
return nil
}
func (ap *AnsiParser) collectInter() error {
currChar := ap.context.currentChar
ap.logf("collectInter %#x", currChar)
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
return nil
}
func (ap *AnsiParser) escDispatch() error {
cmd, _ := parseCmd(*ap.context)
intermeds := ap.context.interBuffer
ap.logf("escDispatch currentChar: %#x", ap.context.currentChar)
ap.logf("escDispatch: %v(%v)", cmd, intermeds)
switch cmd {
case "D": // IND
return ap.eventHandler.IND()
case "E": // NEL, equivalent to CRLF
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
if err == nil {
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
}
return err
case "M": // RI
return ap.eventHandler.RI()
}
return nil
}
func (ap *AnsiParser) csiDispatch() error {
cmd, _ := parseCmd(*ap.context)
params, _ := parseParams(ap.context.paramBuffer)
ap.logf("Parsed params: %v with length: %d", params, len(params))
ap.logf("csiDispatch: %v(%v)", cmd, params)
switch cmd {
case "@":
return ap.eventHandler.ICH(getInt(params, 1))
case "A":
return ap.eventHandler.CUU(getInt(params, 1))
case "B":
return ap.eventHandler.CUD(getInt(params, 1))
case "C":
return ap.eventHandler.CUF(getInt(params, 1))
case "D":
return ap.eventHandler.CUB(getInt(params, 1))
case "E":
return ap.eventHandler.CNL(getInt(params, 1))
case "F":
return ap.eventHandler.CPL(getInt(params, 1))
case "G":
return ap.eventHandler.CHA(getInt(params, 1))
case "H":
ints := getInts(params, 2, 1)
x, y := ints[0], ints[1]
return ap.eventHandler.CUP(x, y)
case "J":
param := getEraseParam(params)
return ap.eventHandler.ED(param)
case "K":
param := getEraseParam(params)
return ap.eventHandler.EL(param)
case "L":
return ap.eventHandler.IL(getInt(params, 1))
case "M":
return ap.eventHandler.DL(getInt(params, 1))
case "P":
return ap.eventHandler.DCH(getInt(params, 1))
case "S":
return ap.eventHandler.SU(getInt(params, 1))
case "T":
return ap.eventHandler.SD(getInt(params, 1))
case "c":
return ap.eventHandler.DA(params)
case "d":
return ap.eventHandler.VPA(getInt(params, 1))
case "f":
ints := getInts(params, 2, 1)
x, y := ints[0], ints[1]
return ap.eventHandler.HVP(x, y)
case "h":
return ap.hDispatch(params)
case "l":
return ap.lDispatch(params)
case "m":
return ap.eventHandler.SGR(getInts(params, 1, 0))
case "r":
ints := getInts(params, 2, 1)
top, bottom := ints[0], ints[1]
return ap.eventHandler.DECSTBM(top, bottom)
default:
ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context)
return nil
}
}
func (ap *AnsiParser) print() error {
return ap.eventHandler.Print(ap.context.currentChar)
}
func (ap *AnsiParser) clear() error {
ap.context = &ansiContext{}
return nil
}
func (ap *AnsiParser) execute() error {
return ap.eventHandler.Execute(ap.context.currentChar)
}

View File

@ -1,71 +0,0 @@
package ansiterm
type stateID int
type state interface {
Enter() error
Exit() error
Handle(byte) (state, error)
Name() string
Transition(state) error
}
type baseState struct {
name string
parser *AnsiParser
}
func (base baseState) Enter() error {
return nil
}
func (base baseState) Exit() error {
return nil
}
func (base baseState) Handle(b byte) (s state, e error) {
switch {
case b == CSI_ENTRY:
return base.parser.csiEntry, nil
case b == DCS_ENTRY:
return base.parser.dcsEntry, nil
case b == ANSI_ESCAPE_PRIMARY:
return base.parser.escape, nil
case b == OSC_STRING:
return base.parser.oscString, nil
case sliceContains(toGroundBytes, b):
return base.parser.ground, nil
}
return nil, nil
}
func (base baseState) Name() string {
return base.name
}
func (base baseState) Transition(s state) error {
if s == base.parser.ground {
execBytes := []byte{0x18}
execBytes = append(execBytes, 0x1A)
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
execBytes = append(execBytes, 0x99)
execBytes = append(execBytes, 0x9A)
if sliceContains(execBytes, base.parser.context.currentChar) {
return base.parser.execute()
}
}
return nil
}
type dcsEntryState struct {
baseState
}
type errorState struct {
baseState
}

View File

@ -1,21 +0,0 @@
package ansiterm
import (
"strconv"
)
func sliceContains(bytes []byte, b byte) bool {
for _, v := range bytes {
if v == b {
return true
}
}
return false
}
func convertBytesToInteger(bytes []byte) int {
s := string(bytes)
i, _ := strconv.Atoi(s)
return i
}

View File

@ -1,182 +0,0 @@
// +build windows
package winterm
import (
"fmt"
"os"
"strconv"
"strings"
"syscall"
"github.com/Azure/go-ansiterm"
)
// Windows keyboard constants
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
const (
VK_PRIOR = 0x21 // PAGE UP key
VK_NEXT = 0x22 // PAGE DOWN key
VK_END = 0x23 // END key
VK_HOME = 0x24 // HOME key
VK_LEFT = 0x25 // LEFT ARROW key
VK_UP = 0x26 // UP ARROW key
VK_RIGHT = 0x27 // RIGHT ARROW key
VK_DOWN = 0x28 // DOWN ARROW key
VK_SELECT = 0x29 // SELECT key
VK_PRINT = 0x2A // PRINT key
VK_EXECUTE = 0x2B // EXECUTE key
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
VK_INSERT = 0x2D // INS key
VK_DELETE = 0x2E // DEL key
VK_HELP = 0x2F // HELP key
VK_F1 = 0x70 // F1 key
VK_F2 = 0x71 // F2 key
VK_F3 = 0x72 // F3 key
VK_F4 = 0x73 // F4 key
VK_F5 = 0x74 // F5 key
VK_F6 = 0x75 // F6 key
VK_F7 = 0x76 // F7 key
VK_F8 = 0x77 // F8 key
VK_F9 = 0x78 // F9 key
VK_F10 = 0x79 // F10 key
VK_F11 = 0x7A // F11 key
VK_F12 = 0x7B // F12 key
RIGHT_ALT_PRESSED = 0x0001
LEFT_ALT_PRESSED = 0x0002
RIGHT_CTRL_PRESSED = 0x0004
LEFT_CTRL_PRESSED = 0x0008
SHIFT_PRESSED = 0x0010
NUMLOCK_ON = 0x0020
SCROLLLOCK_ON = 0x0040
CAPSLOCK_ON = 0x0080
ENHANCED_KEY = 0x0100
)
type ansiCommand struct {
CommandBytes []byte
Command string
Parameters []string
IsSpecial bool
}
func newAnsiCommand(command []byte) *ansiCommand {
if isCharacterSelectionCmdChar(command[1]) {
// Is Character Set Selection commands
return &ansiCommand{
CommandBytes: command,
Command: string(command),
IsSpecial: true,
}
}
// last char is command character
lastCharIndex := len(command) - 1
ac := &ansiCommand{
CommandBytes: command,
Command: string(command[lastCharIndex]),
IsSpecial: false,
}
// more than a single escape
if lastCharIndex != 0 {
start := 1
// skip if double char escape sequence
if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
start++
}
// convert this to GetNextParam method
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
}
return ac
}
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
if index < 0 || index >= len(ac.Parameters) {
return defaultValue
}
param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
if err != nil {
return defaultValue
}
return int16(param)
}
func (ac *ansiCommand) String() string {
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
bytesToHex(ac.CommandBytes),
ac.Command,
strings.Join(ac.Parameters, "\",\""))
}
// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
func isAnsiCommandChar(b byte) bool {
switch {
case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
return true
case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
// non-CSI escape sequence terminator
return true
case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
// String escape sequence terminator
return true
}
return false
}
func isXtermOscSequence(command []byte, current byte) bool {
return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
}
func isCharacterSelectionCmdChar(b byte) bool {
return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
}
// bytesToHex converts a slice of bytes to a human-readable string.
func bytesToHex(b []byte) string {
hex := make([]string, len(b))
for i, ch := range b {
hex[i] = fmt.Sprintf("%X", ch)
}
return strings.Join(hex, "")
}
// ensureInRange adjusts the passed value, if necessary, to ensure it is within
// the passed min / max range.
func ensureInRange(n int16, min int16, max int16) int16 {
if n < min {
return min
} else if n > max {
return max
} else {
return n
}
}
func GetStdFile(nFile int) (*os.File, uintptr) {
var file *os.File
switch nFile {
case syscall.STD_INPUT_HANDLE:
file = os.Stdin
case syscall.STD_OUTPUT_HANDLE:
file = os.Stdout
case syscall.STD_ERROR_HANDLE:
file = os.Stderr
default:
panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
}
fd, err := syscall.GetStdHandle(nFile)
if err != nil {
panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
}
return file, uintptr(fd)
}

View File

@ -1,327 +0,0 @@
// +build windows
package winterm
import (
"fmt"
"syscall"
"unsafe"
)
//===========================================================================================================
// IMPORTANT NOTE:
//
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
// variables) the pointers reference *before* the API completes.
//
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
// require unsafe pointers.
//
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
// the garbage collector the variables remain in use if:
//
// -- The value is not a pointer (e.g., int32, struct)
// -- The value is not referenced by the method after passing the pointer to Windows
//
// See http://golang.org/doc/go1.3.
//===========================================================================================================
var (
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
)
// Windows Console constants
const (
// Console modes
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_LINE_INPUT = 0x0002
ENABLE_ECHO_INPUT = 0x0004
ENABLE_WINDOW_INPUT = 0x0008
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_INSERT_MODE = 0x0020
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_EXTENDED_FLAGS = 0x0080
ENABLE_AUTO_POSITION = 0x0100
ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
DISABLE_NEWLINE_AUTO_RETURN = 0x0008
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
// Character attributes
// Note:
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
// Clearing all foreground or background colors results in black; setting all creates white.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
FOREGROUND_BLUE uint16 = 0x0001
FOREGROUND_GREEN uint16 = 0x0002
FOREGROUND_RED uint16 = 0x0004
FOREGROUND_INTENSITY uint16 = 0x0008
FOREGROUND_MASK uint16 = 0x000F
BACKGROUND_BLUE uint16 = 0x0010
BACKGROUND_GREEN uint16 = 0x0020
BACKGROUND_RED uint16 = 0x0040
BACKGROUND_INTENSITY uint16 = 0x0080
BACKGROUND_MASK uint16 = 0x00F0
COMMON_LVB_MASK uint16 = 0xFF00
COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
COMMON_LVB_UNDERSCORE uint16 = 0x8000
// Input event types
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
KEY_EVENT = 0x0001
MOUSE_EVENT = 0x0002
WINDOW_BUFFER_SIZE_EVENT = 0x0004
MENU_EVENT = 0x0008
FOCUS_EVENT = 0x0010
// WaitForSingleObject return codes
WAIT_ABANDONED = 0x00000080
WAIT_FAILED = 0xFFFFFFFF
WAIT_SIGNALED = 0x0000000
WAIT_TIMEOUT = 0x00000102
// WaitForSingleObject wait duration
WAIT_INFINITE = 0xFFFFFFFF
WAIT_ONE_SECOND = 1000
WAIT_HALF_SECOND = 500
WAIT_QUARTER_SECOND = 250
)
// Windows API Console types
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
type (
CHAR_INFO struct {
UnicodeChar uint16
Attributes uint16
}
CONSOLE_CURSOR_INFO struct {
Size uint32
Visible int32
}
CONSOLE_SCREEN_BUFFER_INFO struct {
Size COORD
CursorPosition COORD
Attributes uint16
Window SMALL_RECT
MaximumWindowSize COORD
}
COORD struct {
X int16
Y int16
}
SMALL_RECT struct {
Left int16
Top int16
Right int16
Bottom int16
}
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
INPUT_RECORD struct {
EventType uint16
KeyEvent KEY_EVENT_RECORD
}
KEY_EVENT_RECORD struct {
KeyDown int32
RepeatCount uint16
VirtualKeyCode uint16
VirtualScanCode uint16
UnicodeChar uint16
ControlKeyState uint32
}
WINDOW_BUFFER_SIZE struct {
Size COORD
}
)
// boolToBOOL converts a Go bool into a Windows int32.
func boolToBOOL(f bool) int32 {
if f {
return int32(1)
} else {
return int32(0)
}
}
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
return checkError(r1, r2, err)
}
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
return checkError(r1, r2, err)
}
// SetConsoleCursorPosition location of the console cursor.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
use(coord)
return checkError(r1, r2, err)
}
// GetConsoleMode gets the console mode for given file descriptor
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
return mode, err
}
// SetConsoleMode sets the console mode for given file descriptor
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
func SetConsoleMode(handle uintptr, mode uint32) error {
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
use(mode)
return checkError(r1, r2, err)
}
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
info := CONSOLE_SCREEN_BUFFER_INFO{}
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
if err != nil {
return nil, err
}
return &info, nil
}
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
use(scrollRect)
use(clipRect)
use(destOrigin)
use(char)
return checkError(r1, r2, err)
}
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
use(coord)
return checkError(r1, r2, err)
}
// SetConsoleTextAttribute sets the attributes of characters written to the
// console screen buffer by the WriteFile or WriteConsole function.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
use(attribute)
return checkError(r1, r2, err)
}
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
// Note that the size and location must be within and no larger than the backing console screen buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
use(isAbsolute)
use(rect)
return checkError(r1, r2, err)
}
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
use(buffer)
use(bufferSize)
use(bufferCoord)
return checkError(r1, r2, err)
}
// ReadConsoleInput reads (and removes) data from the console input buffer.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
use(buffer)
return checkError(r1, r2, err)
}
// WaitForSingleObject waits for the passed handle to be signaled.
// It returns true if the handle was signaled; false otherwise.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
switch r1 {
case WAIT_ABANDONED, WAIT_TIMEOUT:
return false, nil
case WAIT_SIGNALED:
return true, nil
}
use(msWait)
return false, err
}
// String helpers
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
}
func (coord COORD) String() string {
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
}
func (rect SMALL_RECT) String() string {
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
}
// checkError evaluates the results of a Windows API call and returns the error if it failed.
func checkError(r1, r2 uintptr, err error) error {
// Windows APIs return non-zero to indicate success
if r1 != 0 {
return nil
}
// Return the error if provided, otherwise default to EINVAL
if err != nil {
return err
}
return syscall.EINVAL
}
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
func coordToPointer(c COORD) uintptr {
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
return uintptr(*((*uint32)(unsafe.Pointer(&c))))
}
// use is a no-op, but the compiler cannot see that it is.
// Calling use(p) ensures that p is kept live until that point.
func use(p interface{}) {}

View File

@ -1,100 +0,0 @@
// +build windows
package winterm
import "github.com/Azure/go-ansiterm"
const (
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
)
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
// request represented by the passed ANSI mode.
func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
switch ansiMode {
// Mode styles
case ansiterm.ANSI_SGR_BOLD:
windowsMode = windowsMode | FOREGROUND_INTENSITY
case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
windowsMode &^= FOREGROUND_INTENSITY
case ansiterm.ANSI_SGR_UNDERLINE:
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
case ansiterm.ANSI_SGR_REVERSE:
inverted = true
case ansiterm.ANSI_SGR_REVERSE_OFF:
inverted = false
case ansiterm.ANSI_SGR_UNDERLINE_OFF:
windowsMode &^= COMMON_LVB_UNDERSCORE
// Foreground colors
case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
case ansiterm.ANSI_SGR_FOREGROUND_RED:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
// Background colors
case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
// Black with no intensity
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
case ansiterm.ANSI_SGR_BACKGROUND_RED:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
}
return windowsMode, inverted
}
// invertAttributes inverts the foreground and background colors of a Windows attributes value
func invertAttributes(windowsMode uint16) uint16 {
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
}

View File

@ -1,101 +0,0 @@
// +build windows
package winterm
const (
horizontal = iota
vertical
)
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
if h.originMode {
sr := h.effectiveSr(info.Window)
return SMALL_RECT{
Top: sr.top,
Bottom: sr.bottom,
Left: 0,
Right: info.Size.X - 1,
}
} else {
return SMALL_RECT{
Top: info.Window.Top,
Bottom: info.Window.Bottom,
Left: 0,
Right: info.Size.X - 1,
}
}
}
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
position.X = ensureInRange(position.X, window.Left, window.Right)
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
err := SetConsoleCursorPosition(h.fd, position)
if err != nil {
return err
}
h.logf("Cursor position set: (%d, %d)", position.X, position.Y)
return err
}
func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
return h.moveCursor(vertical, param)
}
func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
return h.moveCursor(horizontal, param)
}
func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
switch moveMode {
case horizontal:
position.X += int16(param)
case vertical:
position.Y += int16(param)
}
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
position.X = 0
position.Y += int16(param)
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
position := info.CursorPosition
position.X = int16(param) - 1
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err
}
return nil
}

View File

@ -1,84 +0,0 @@
// +build windows
package winterm
import "github.com/Azure/go-ansiterm"
func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
// Ignore an invalid (negative area) request
if toCoord.Y < fromCoord.Y {
return nil
}
var err error
var coordStart = COORD{}
var coordEnd = COORD{}
xCurrent, yCurrent := fromCoord.X, fromCoord.Y
xEnd, yEnd := toCoord.X, toCoord.Y
// Clear any partial initial line
if xCurrent > 0 {
coordStart.X, coordStart.Y = xCurrent, yCurrent
coordEnd.X, coordEnd.Y = xEnd, yCurrent
err = h.clearRect(attributes, coordStart, coordEnd)
if err != nil {
return err
}
xCurrent = 0
yCurrent += 1
}
// Clear intervening rectangular section
if yCurrent < yEnd {
coordStart.X, coordStart.Y = xCurrent, yCurrent
coordEnd.X, coordEnd.Y = xEnd, yEnd-1
err = h.clearRect(attributes, coordStart, coordEnd)
if err != nil {
return err
}
xCurrent = 0
yCurrent = yEnd
}
// Clear remaining partial ending line
coordStart.X, coordStart.Y = xCurrent, yCurrent
coordEnd.X, coordEnd.Y = xEnd, yEnd
err = h.clearRect(attributes, coordStart, coordEnd)
if err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
width := toCoord.X - fromCoord.X + 1
height := toCoord.Y - fromCoord.Y + 1
size := uint32(width) * uint32(height)
if size <= 0 {
return nil
}
buffer := make([]CHAR_INFO, size)
char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
for i := 0; i < int(size); i++ {
buffer[i] = char
}
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, &region)
if err != nil {
return err
}
return nil
}

View File

@ -1,118 +0,0 @@
// +build windows
package winterm
// effectiveSr gets the current effective scroll region in buffer coordinates
func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
if top >= bottom {
top = window.Top
bottom = window.Bottom
}
return scrollRegion{top: top, bottom: bottom}
}
func (h *windowsAnsiEventHandler) scrollUp(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
sr := h.effectiveSr(info.Window)
return h.scroll(param, sr, info)
}
func (h *windowsAnsiEventHandler) scrollDown(param int) error {
return h.scrollUp(-param)
}
func (h *windowsAnsiEventHandler) deleteLines(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
start := info.CursorPosition.Y
sr := h.effectiveSr(info.Window)
// Lines cannot be inserted or deleted outside the scrolling region.
if start >= sr.top && start <= sr.bottom {
sr.top = start
return h.scroll(param, sr, info)
} else {
return nil
}
}
func (h *windowsAnsiEventHandler) insertLines(param int) error {
return h.deleteLines(-param)
}
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
// Copy from and clip to the scroll region (full buffer width)
scrollRect := SMALL_RECT{
Top: sr.top,
Bottom: sr.bottom,
Left: 0,
Right: info.Size.X - 1,
}
// Origin to which area should be copied
destOrigin := COORD{
X: 0,
Y: sr.top - int16(param),
}
char := CHAR_INFO{
UnicodeChar: ' ',
Attributes: h.attributes,
}
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
return h.scrollLine(param, info.CursorPosition, info)
}
func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
return h.deleteCharacters(-param)
}
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
// Copy from and clip to the scroll region (full buffer width)
scrollRect := SMALL_RECT{
Top: position.Y,
Bottom: position.Y,
Left: position.X,
Right: info.Size.X - 1,
}
// Origin to which area should be copied
destOrigin := COORD{
X: position.X - int16(columns),
Y: position.Y,
}
char := CHAR_INFO{
UnicodeChar: ' ',
Attributes: h.attributes,
}
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
return err
}
return nil
}

View File

@ -1,9 +0,0 @@
// +build windows
package winterm
// AddInRange increments a value by the passed quantity while ensuring the values
// always remain within the supplied min / max range.
func addInRange(n int16, increment int16, min int16, max int16) int16 {
return ensureInRange(n+increment, min, max)
}

View File

@ -1,743 +0,0 @@
// +build windows
package winterm
import (
"bytes"
"log"
"os"
"strconv"
"github.com/Azure/go-ansiterm"
)
type windowsAnsiEventHandler struct {
fd uintptr
file *os.File
infoReset *CONSOLE_SCREEN_BUFFER_INFO
sr scrollRegion
buffer bytes.Buffer
attributes uint16
inverted bool
wrapNext bool
drewMarginByte bool
originMode bool
marginByte byte
curInfo *CONSOLE_SCREEN_BUFFER_INFO
curPos COORD
logf func(string, ...interface{})
}
type Option func(*windowsAnsiEventHandler)
func WithLogf(f func(string, ...interface{})) Option {
return func(w *windowsAnsiEventHandler) {
w.logf = f
}
}
func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
infoReset, err := GetConsoleScreenBufferInfo(fd)
if err != nil {
return nil
}
h := &windowsAnsiEventHandler{
fd: fd,
file: file,
infoReset: infoReset,
attributes: infoReset.Attributes,
}
for _, o := range opts {
o(h)
}
if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
logFile, _ := os.Create("winEventHandler.log")
logger := log.New(logFile, "", log.LstdFlags)
if h.logf != nil {
l := h.logf
h.logf = func(s string, v ...interface{}) {
l(s, v...)
logger.Printf(s, v...)
}
} else {
h.logf = logger.Printf
}
}
if h.logf == nil {
h.logf = func(string, ...interface{}) {}
}
return h
}
type scrollRegion struct {
top int16
bottom int16
}
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
// current cursor position and scroll region settings, in which case it returns
// true. If no special handling is necessary, then it does nothing and returns
// false.
//
// In the false case, the caller should ensure that a carriage return
// and line feed are inserted or that the text is otherwise wrapped.
func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
if h.wrapNext {
if err := h.Flush(); err != nil {
return false, err
}
h.clearWrap()
}
pos, info, err := h.getCurrentInfo()
if err != nil {
return false, err
}
sr := h.effectiveSr(info.Window)
if pos.Y == sr.bottom {
// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
// is the full window.
if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
if includeCR {
pos.X = 0
h.updatePos(pos)
}
return false, nil
}
// A custom scroll region is active. Scroll the window manually to simulate
// the LF.
if err := h.Flush(); err != nil {
return false, err
}
h.logf("Simulating LF inside scroll region")
if err := h.scrollUp(1); err != nil {
return false, err
}
if includeCR {
pos.X = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return false, err
}
}
return true, nil
} else if pos.Y < info.Window.Bottom {
// Let Windows handle the LF.
pos.Y++
if includeCR {
pos.X = 0
}
h.updatePos(pos)
return false, nil
} else {
// The cursor is at the bottom of the screen but outside the scroll
// region. Skip the LF.
h.logf("Simulating LF outside scroll region")
if includeCR {
if err := h.Flush(); err != nil {
return false, err
}
pos.X = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return false, err
}
}
return true, nil
}
}
// executeLF executes a LF without a CR.
func (h *windowsAnsiEventHandler) executeLF() error {
handled, err := h.simulateLF(false)
if err != nil {
return err
}
if !handled {
// Windows LF will reset the cursor column position. Write the LF
// and restore the cursor position.
pos, _, err := h.getCurrentInfo()
if err != nil {
return err
}
h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
if pos.X != 0 {
if err := h.Flush(); err != nil {
return err
}
h.logf("Resetting cursor position for LF without CR")
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
}
}
return nil
}
func (h *windowsAnsiEventHandler) Print(b byte) error {
if h.wrapNext {
h.buffer.WriteByte(h.marginByte)
h.clearWrap()
if _, err := h.simulateLF(true); err != nil {
return err
}
}
pos, info, err := h.getCurrentInfo()
if err != nil {
return err
}
if pos.X == info.Size.X-1 {
h.wrapNext = true
h.marginByte = b
} else {
pos.X++
h.updatePos(pos)
h.buffer.WriteByte(b)
}
return nil
}
func (h *windowsAnsiEventHandler) Execute(b byte) error {
switch b {
case ansiterm.ANSI_TAB:
h.logf("Execute(TAB)")
// Move to the next tab stop, but preserve auto-wrap if already set.
if !h.wrapNext {
pos, info, err := h.getCurrentInfo()
if err != nil {
return err
}
pos.X = (pos.X + 8) - pos.X%8
if pos.X >= info.Size.X {
pos.X = info.Size.X - 1
}
if err := h.Flush(); err != nil {
return err
}
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
}
return nil
case ansiterm.ANSI_BEL:
h.buffer.WriteByte(ansiterm.ANSI_BEL)
return nil
case ansiterm.ANSI_BACKSPACE:
if h.wrapNext {
if err := h.Flush(); err != nil {
return err
}
h.clearWrap()
}
pos, _, err := h.getCurrentInfo()
if err != nil {
return err
}
if pos.X > 0 {
pos.X--
h.updatePos(pos)
h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
}
return nil
case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
// Treat as true LF.
return h.executeLF()
case ansiterm.ANSI_LINE_FEED:
// Simulate a CR and LF for now since there is no way in go-ansiterm
// to tell if the LF should include CR (and more things break when it's
// missing than when it's incorrectly added).
handled, err := h.simulateLF(true)
if handled || err != nil {
return err
}
return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
case ansiterm.ANSI_CARRIAGE_RETURN:
if h.wrapNext {
if err := h.Flush(); err != nil {
return err
}
h.clearWrap()
}
pos, _, err := h.getCurrentInfo()
if err != nil {
return err
}
if pos.X != 0 {
pos.X = 0
h.updatePos(pos)
h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
}
return nil
default:
return nil
}
}
func (h *windowsAnsiEventHandler) CUU(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorVertical(-param)
}
func (h *windowsAnsiEventHandler) CUD(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorVertical(param)
}
func (h *windowsAnsiEventHandler) CUF(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorHorizontal(param)
}
func (h *windowsAnsiEventHandler) CUB(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorHorizontal(-param)
}
func (h *windowsAnsiEventHandler) CNL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorLine(param)
}
func (h *windowsAnsiEventHandler) CPL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorLine(-param)
}
func (h *windowsAnsiEventHandler) CHA(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.moveCursorColumn(param)
}
func (h *windowsAnsiEventHandler) VPA(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("VPA: [[%d]]", param)
h.clearWrap()
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
window := h.getCursorWindow(info)
position := info.CursorPosition
position.Y = window.Top + int16(param) - 1
return h.setCursorPosition(position, window)
}
func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("CUP: [[%d %d]]", row, col)
h.clearWrap()
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
window := h.getCursorWindow(info)
position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
return h.setCursorPosition(position, window)
}
func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("HVP: [[%d %d]]", row, col)
h.clearWrap()
return h.CUP(row, col)
}
func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
h.clearWrap()
return nil
}
func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
h.clearWrap()
h.originMode = enable
return h.CUP(1, 1)
}
func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
h.clearWrap()
if err := h.ED(2); err != nil {
return err
}
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
targetWidth := int16(80)
if use132 {
targetWidth = 132
}
if info.Size.X < targetWidth {
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
h.logf("set buffer failed: %v", err)
return err
}
}
window := info.Window
window.Left = 0
window.Right = targetWidth - 1
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
h.logf("set window failed: %v", err)
return err
}
if info.Size.X > targetWidth {
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
h.logf("set buffer failed: %v", err)
return err
}
}
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
}
func (h *windowsAnsiEventHandler) ED(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("ED: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
// [J -- Erases from the cursor to the end of the screen, including the cursor position.
// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
// [2J -- Erases the complete display. The cursor does not move.
// Notes:
// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
var start COORD
var end COORD
switch param {
case 0:
start = info.CursorPosition
end = COORD{info.Size.X - 1, info.Size.Y - 1}
case 1:
start = COORD{0, 0}
end = info.CursorPosition
case 2:
start = COORD{0, 0}
end = COORD{info.Size.X - 1, info.Size.Y - 1}
}
err = h.clearRange(h.attributes, start, end)
if err != nil {
return err
}
// If the whole buffer was cleared, move the window to the top while preserving
// the window-relative cursor position.
if param == 2 {
pos := info.CursorPosition
window := info.Window
pos.Y -= window.Top
window.Bottom -= window.Top
window.Top = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return err
}
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
return err
}
}
return nil
}
func (h *windowsAnsiEventHandler) EL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("EL: [%v]", strconv.Itoa(param))
h.clearWrap()
// [K -- Erases from the cursor to the end of the line, including the cursor position.
// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
// [2K -- Erases the complete line.
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
var start COORD
var end COORD
switch param {
case 0:
start = info.CursorPosition
end = COORD{info.Size.X, info.CursorPosition.Y}
case 1:
start = COORD{0, info.CursorPosition.Y}
end = info.CursorPosition
case 2:
start = COORD{0, info.CursorPosition.Y}
end = COORD{info.Size.X, info.CursorPosition.Y}
}
err = h.clearRange(h.attributes, start, end)
if err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) IL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("IL: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.insertLines(param)
}
func (h *windowsAnsiEventHandler) DL(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DL: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.deleteLines(param)
}
func (h *windowsAnsiEventHandler) ICH(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("ICH: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.insertCharacters(param)
}
func (h *windowsAnsiEventHandler) DCH(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DCH: [%v]", strconv.Itoa(param))
h.clearWrap()
return h.deleteCharacters(param)
}
func (h *windowsAnsiEventHandler) SGR(params []int) error {
if err := h.Flush(); err != nil {
return err
}
strings := []string{}
for _, v := range params {
strings = append(strings, strconv.Itoa(v))
}
h.logf("SGR: [%v]", strings)
if len(params) <= 0 {
h.attributes = h.infoReset.Attributes
h.inverted = false
} else {
for _, attr := range params {
if attr == ansiterm.ANSI_SGR_RESET {
h.attributes = h.infoReset.Attributes
h.inverted = false
continue
}
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
}
}
attributes := h.attributes
if h.inverted {
attributes = invertAttributes(attributes)
}
err := SetConsoleTextAttribute(h.fd, attributes)
if err != nil {
return err
}
return nil
}
func (h *windowsAnsiEventHandler) SU(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("SU: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.scrollUp(param)
}
func (h *windowsAnsiEventHandler) SD(param int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("SD: [%v]", []string{strconv.Itoa(param)})
h.clearWrap()
return h.scrollDown(param)
}
func (h *windowsAnsiEventHandler) DA(params []string) error {
h.logf("DA: [%v]", params)
// DA cannot be implemented because it must send data on the VT100 input stream,
// which is not available to go-ansiterm.
return nil
}
func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
if err := h.Flush(); err != nil {
return err
}
h.logf("DECSTBM: [%d, %d]", top, bottom)
// Windows is 0 indexed, Linux is 1 indexed
h.sr.top = int16(top - 1)
h.sr.bottom = int16(bottom - 1)
// This command also moves the cursor to the origin.
h.clearWrap()
return h.CUP(1, 1)
}
func (h *windowsAnsiEventHandler) RI() error {
if err := h.Flush(); err != nil {
return err
}
h.logf("RI: []")
h.clearWrap()
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
sr := h.effectiveSr(info.Window)
if info.CursorPosition.Y == sr.top {
return h.scrollDown(1)
}
return h.moveCursorVertical(-1)
}
func (h *windowsAnsiEventHandler) IND() error {
h.logf("IND: []")
return h.executeLF()
}
func (h *windowsAnsiEventHandler) Flush() error {
h.curInfo = nil
if h.buffer.Len() > 0 {
h.logf("Flush: [%s]", h.buffer.Bytes())
if _, err := h.buffer.WriteTo(h.file); err != nil {
return err
}
}
if h.wrapNext && !h.drewMarginByte {
h.logf("Flush: drawing margin byte '%c'", h.marginByte)
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return err
}
charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
size := COORD{1, 1}
position := COORD{0, 0}
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
if err := WriteConsoleOutput(h.fd, charInfo, size, position, &region); err != nil {
return err
}
h.drewMarginByte = true
}
return nil
}
// cacheConsoleInfo ensures that the current console screen information has been queried
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
if h.curInfo == nil {
info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil {
return COORD{}, nil, err
}
h.curInfo = info
h.curPos = info.CursorPosition
}
return h.curPos, h.curInfo, nil
}
func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
if h.curInfo == nil {
panic("failed to call getCurrentInfo before calling updatePos")
}
h.curPos = pos
}
// clearWrap clears the state where the cursor is in the margin
// waiting for the next character before wrapping the line. This must
// be done before most operations that act on the cursor.
func (h *windowsAnsiEventHandler) clearWrap() {
h.wrapNext = false
h.drewMarginByte = false
}

17
vendor/github.com/Azure/go-ntlmssp/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,17 @@
sudo: false
language: go
before_script:
- go get -u github.com/golang/lint/golint
go:
- 1.10.x
- master
script:
- test -z "$(gofmt -s -l . | tee /dev/stderr)"
- test -z "$(golint ./... | tee /dev/stderr)"
- go vet ./...
- go build -v ./...
- go test -v ./...

16
vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,16 @@
language: go
go:
- 1.6
before_install:
- go get -u github.com/ChrisTrenkamp/goxpath
- go get -u github.com/ChrisTrenkamp/goxpath/cmd/goxpath
- go get -u github.com/wadey/gocovmerge
script:
- go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}}' ./... | xargs -I {} bash -c {}
- gocovmerge `ls *.coverprofile` > coverage.txt
after_success:
- bash <(curl -s https://codecov.io/bash)

0
vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh generated vendored Executable file → Normal file
View File

View File

@ -1,597 +0,0 @@
package proxmox
// inspired by https://github.com/Telmate/vagrant-proxmox/blob/master/lib/vagrant-proxmox/proxmox/connection.rb
import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"regexp"
"strconv"
"strings"
"time"
)
// TaskTimeout - default async task call timeout in seconds
const TaskTimeout = 300
// TaskStatusCheckInterval - time between async checks in seconds
const TaskStatusCheckInterval = 2
const exitStatusSuccess = "OK"
// Client - URL, user and password to specifc Proxmox node
type Client struct {
session *Session
ApiUrl string
Username string
Password string
}
// VmRef - virtual machine ref parts
// map[type:qemu node:proxmox1-xx id:qemu/132 diskread:5.57424738e+08 disk:0 netin:5.9297450593e+10 mem:3.3235968e+09 uptime:1.4567097e+07 vmid:132 template:0 maxcpu:2 netout:6.053310416e+09 maxdisk:3.4359738368e+10 maxmem:8.592031744e+09 diskwrite:1.49663619584e+12 status:running cpu:0.00386980694947209 name:appt-app1-dev.xxx.xx]
type VmRef struct {
vmId int
node string
vmType string
}
func (vmr *VmRef) SetNode(node string) {
vmr.node = node
return
}
func (vmr *VmRef) SetVmType(vmType string) {
vmr.vmType = vmType
return
}
func (vmr *VmRef) VmId() int {
return vmr.vmId
}
func (vmr *VmRef) Node() string {
return vmr.node
}
func NewVmRef(vmId int) (vmr *VmRef) {
vmr = &VmRef{vmId: vmId, node: "", vmType: ""}
return
}
func NewClient(apiUrl string, hclient *http.Client, tls *tls.Config) (client *Client, err error) {
var sess *Session
sess, err = NewSession(apiUrl, hclient, tls)
if err == nil {
client = &Client{session: sess, ApiUrl: apiUrl}
}
return client, err
}
func (c *Client) Login(username string, password string) (err error) {
c.Username = username
c.Password = password
return c.session.Login(username, password)
}
func (c *Client) GetJsonRetryable(url string, data *map[string]interface{}, tries int) error {
var statErr error
for ii := 0; ii < tries; ii++ {
_, statErr = c.session.GetJSON(url, nil, nil, data)
if statErr == nil {
return nil
}
// if statErr != io.ErrUnexpectedEOF { // don't give up on ErrUnexpectedEOF
// return statErr
// }
time.Sleep(5 * time.Second)
}
return statErr
}
func (c *Client) GetNodeList() (list map[string]interface{}, err error) {
err = c.GetJsonRetryable("/nodes", &list, 3)
return
}
func (c *Client) GetVmList() (list map[string]interface{}, err error) {
err = c.GetJsonRetryable("/cluster/resources?type=vm", &list, 3)
return
}
func (c *Client) CheckVmRef(vmr *VmRef) (err error) {
if vmr.node == "" || vmr.vmType == "" {
_, err = c.GetVmInfo(vmr)
}
return
}
func (c *Client) GetVmInfo(vmr *VmRef) (vmInfo map[string]interface{}, err error) {
resp, err := c.GetVmList()
vms := resp["data"].([]interface{})
for vmii := range vms {
vm := vms[vmii].(map[string]interface{})
if int(vm["vmid"].(float64)) == vmr.vmId {
vmInfo = vm
vmr.node = vmInfo["node"].(string)
vmr.vmType = vmInfo["type"].(string)
return
}
}
return nil, errors.New(fmt.Sprintf("Vm '%d' not found", vmr.vmId))
}
func (c *Client) GetVmRefByName(vmName string) (vmr *VmRef, err error) {
resp, err := c.GetVmList()
vms := resp["data"].([]interface{})
for vmii := range vms {
vm := vms[vmii].(map[string]interface{})
if vm["name"] != nil && vm["name"].(string) == vmName {
vmr = NewVmRef(int(vm["vmid"].(float64)))
vmr.node = vm["node"].(string)
vmr.vmType = vm["type"].(string)
return
}
}
return nil, errors.New(fmt.Sprintf("Vm '%s' not found", vmName))
}
func (c *Client) GetVmState(vmr *VmRef) (vmState map[string]interface{}, err error) {
err = c.CheckVmRef(vmr)
if err != nil {
return nil, err
}
var data map[string]interface{}
url := fmt.Sprintf("/nodes/%s/%s/%d/status/current", vmr.node, vmr.vmType, vmr.vmId)
err = c.GetJsonRetryable(url, &data, 3)
if err != nil {
return nil, err
}
if data["data"] == nil {
return nil, errors.New("Vm STATE not readable")
}
vmState = data["data"].(map[string]interface{})
return
}
func (c *Client) GetVmConfig(vmr *VmRef) (vmConfig map[string]interface{}, err error) {
err = c.CheckVmRef(vmr)
if err != nil {
return nil, err
}
var data map[string]interface{}
url := fmt.Sprintf("/nodes/%s/%s/%d/config", vmr.node, vmr.vmType, vmr.vmId)
err = c.GetJsonRetryable(url, &data, 3)
if err != nil {
return nil, err
}
if data["data"] == nil {
return nil, errors.New("Vm CONFIG not readable")
}
vmConfig = data["data"].(map[string]interface{})
return
}
func (c *Client) GetVmSpiceProxy(vmr *VmRef) (vmSpiceProxy map[string]interface{}, err error) {
err = c.CheckVmRef(vmr)
if err != nil {
return nil, err
}
var data map[string]interface{}
url := fmt.Sprintf("/nodes/%s/%s/%d/spiceproxy", vmr.node, vmr.vmType, vmr.vmId)
_, err = c.session.PostJSON(url, nil, nil, nil, &data)
if err != nil {
return nil, err
}
if data["data"] == nil {
return nil, errors.New("Vm SpiceProxy not readable")
}
vmSpiceProxy = data["data"].(map[string]interface{})
return
}
type AgentNetworkInterface struct {
MACAddress string
IPAddresses []net.IP
Name string
Statistics map[string]int64
}
func (a *AgentNetworkInterface) UnmarshalJSON(b []byte) error {
var intermediate struct {
HardwareAddress string `json:"hardware-address"`
IPAddresses []struct {
IPAddress string `json:"ip-address"`
IPAddressType string `json:"ip-address-type"`
Prefix int `json:"prefix"`
} `json:"ip-addresses"`
Name string `json:"name"`
Statistics map[string]int64 `json:"statistics"`
}
err := json.Unmarshal(b, &intermediate)
if err != nil {
return err
}
a.IPAddresses = make([]net.IP, len(intermediate.IPAddresses))
for idx, ip := range intermediate.IPAddresses {
a.IPAddresses[idx] = net.ParseIP(ip.IPAddress)
if a.IPAddresses[idx] == nil {
return fmt.Errorf("Could not parse %s as IP", ip.IPAddress)
}
}
a.MACAddress = intermediate.HardwareAddress
a.Name = intermediate.Name
a.Statistics = intermediate.Statistics
return nil
}
func (c *Client) GetVmAgentNetworkInterfaces(vmr *VmRef) ([]AgentNetworkInterface, error) {
var ifs []AgentNetworkInterface
err := c.doAgentGet(vmr, "network-get-interfaces", &ifs)
return ifs, err
}
func (c *Client) doAgentGet(vmr *VmRef, command string, output interface{}) error {
err := c.CheckVmRef(vmr)
if err != nil {
return err
}
url := fmt.Sprintf("/nodes/%s/%s/%d/agent/%s", vmr.node, vmr.vmType, vmr.vmId, command)
resp, err := c.session.Get(url, nil, nil)
if err != nil {
return err
}
return TypedResponse(resp, output)
}
func (c *Client) CreateTemplate(vmr *VmRef) error {
err := c.CheckVmRef(vmr)
if err != nil {
return err
}
url := fmt.Sprintf("/nodes/%s/%s/%d/template", vmr.node, vmr.vmType, vmr.vmId)
_, err = c.session.Post(url, nil, nil, nil)
if err != nil {
return err
}
return nil
}
func (c *Client) MonitorCmd(vmr *VmRef, command string) (monitorRes map[string]interface{}, err error) {
err = c.CheckVmRef(vmr)
if err != nil {
return nil, err
}
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)
monitorRes, err = ResponseJSON(resp)
return
}
// WaitForCompletion - poll the API for task completion
func (c *Client) WaitForCompletion(taskResponse map[string]interface{}) (waitExitStatus string, err error) {
if taskResponse["errors"] != nil {
errJSON, _ := json.MarshalIndent(taskResponse["errors"], "", " ")
return string(errJSON), errors.New("Error reponse")
}
if taskResponse["data"] == nil {
return "", nil
}
waited := 0
taskUpid := taskResponse["data"].(string)
for waited < TaskTimeout {
exitStatus, statErr := c.GetTaskExitstatus(taskUpid)
if statErr != nil {
if statErr != io.ErrUnexpectedEOF { // don't give up on ErrUnexpectedEOF
return "", statErr
}
}
if exitStatus != nil {
waitExitStatus = exitStatus.(string)
return
}
time.Sleep(TaskStatusCheckInterval * time.Second)
waited = waited + TaskStatusCheckInterval
}
return "", errors.New("Wait timeout for:" + taskUpid)
}
var rxTaskNode = regexp.MustCompile("UPID:(.*?):")
func (c *Client) GetTaskExitstatus(taskUpid string) (exitStatus interface{}, err error) {
node := rxTaskNode.FindStringSubmatch(taskUpid)[1]
url := fmt.Sprintf("/nodes/%s/tasks/%s/status", node, taskUpid)
var data map[string]interface{}
_, err = c.session.GetJSON(url, nil, nil, &data)
if err == nil {
exitStatus = data["data"].(map[string]interface{})["exitstatus"]
}
if exitStatus != nil && exitStatus != exitStatusSuccess {
err = errors.New(exitStatus.(string))
}
return
}
func (c *Client) StatusChangeVm(vmr *VmRef, setStatus string) (exitStatus string, err error) {
err = c.CheckVmRef(vmr)
if err != nil {
return "", err
}
url := fmt.Sprintf("/nodes/%s/%s/%d/status/%s", vmr.node, vmr.vmType, vmr.vmId, setStatus)
var taskResponse map[string]interface{}
for i := 0; i < 3; i++ {
_, err = c.session.PostJSON(url, nil, nil, nil, &taskResponse)
exitStatus, err = c.WaitForCompletion(taskResponse)
if exitStatus == "" {
time.Sleep(TaskStatusCheckInterval * time.Second)
} else {
return
}
}
return
}
func (c *Client) StartVm(vmr *VmRef) (exitStatus string, err error) {
return c.StatusChangeVm(vmr, "start")
}
func (c *Client) StopVm(vmr *VmRef) (exitStatus string, err error) {
return c.StatusChangeVm(vmr, "stop")
}
func (c *Client) ShutdownVm(vmr *VmRef) (exitStatus string, err error) {
return c.StatusChangeVm(vmr, "shutdown")
}
func (c *Client) ResetVm(vmr *VmRef) (exitStatus string, err error) {
return c.StatusChangeVm(vmr, "reset")
}
func (c *Client) SuspendVm(vmr *VmRef) (exitStatus string, err error) {
return c.StatusChangeVm(vmr, "suspend")
}
func (c *Client) ResumeVm(vmr *VmRef) (exitStatus string, err error) {
return c.StatusChangeVm(vmr, "resume")
}
func (c *Client) DeleteVm(vmr *VmRef) (exitStatus string, err error) {
err = c.CheckVmRef(vmr)
if err != nil {
return "", err
}
url := fmt.Sprintf("/nodes/%s/%s/%d", vmr.node, vmr.vmType, vmr.vmId)
var taskResponse map[string]interface{}
_, err = c.session.RequestJSON("DELETE", url, nil, nil, nil, &taskResponse)
exitStatus, err = c.WaitForCompletion(taskResponse)
return
}
func (c *Client) CreateQemuVm(node string, vmParams map[string]interface{}) (exitStatus string, err error) {
// Create VM disks first to ensure disks names.
createdDisks, createdDisksErr := c.createVMDisks(node, vmParams)
if createdDisksErr != nil {
return "", createdDisksErr
}
// Then create the VM itself.
reqbody := ParamsToBody(vmParams)
url := fmt.Sprintf("/nodes/%s/qemu", node)
var resp *http.Response
resp, err = c.session.Post(url, nil, nil, &reqbody)
defer resp.Body.Close()
if err != nil {
b, _ := ioutil.ReadAll(resp.Body)
exitStatus = string(b)
return
}
taskResponse, err := ResponseJSON(resp)
if err != nil {
return
}
exitStatus, err = c.WaitForCompletion(taskResponse)
// Delete VM disks if the VM didn't create.
if exitStatus != "OK" {
deleteDisksErr := c.DeleteVMDisks(node, createdDisks)
if deleteDisksErr != nil {
return "", deleteDisksErr
}
}
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)
resp, err := c.session.Post(url, nil, nil, &reqbody)
if err == nil {
taskResponse, err := ResponseJSON(resp)
if err != nil {
return "", err
}
exitStatus, err = c.WaitForCompletion(taskResponse)
}
return
}
func (c *Client) RollbackQemuVm(vmr *VmRef, snapshot string) (exitStatus string, err error) {
err = c.CheckVmRef(vmr)
if err != nil {
return "", err
}
url := fmt.Sprintf("/nodes/%s/%s/%d/snapshot/%s/rollback", vmr.node, vmr.vmType, vmr.vmId, snapshot)
var taskResponse map[string]interface{}
_, err = c.session.PostJSON(url, nil, nil, nil, &taskResponse)
exitStatus, err = c.WaitForCompletion(taskResponse)
return
}
// SetVmConfig - send config options
func (c *Client) SetVmConfig(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.Post(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
//size:+2G
if disk == "" {
disk = "virtio0"
}
size := fmt.Sprintf("+%dG", moreSizeGB)
reqbody := ParamsToBody(map[string]interface{}{"disk": disk, "size": size})
url := fmt.Sprintf("/nodes/%s/%s/%d/resize", 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
}
// GetNextID - Get next free VMID
func (c *Client) GetNextID(currentID int) (nextID int, err error) {
var data map[string]interface{}
var url string
if currentID >= 100 {
url = fmt.Sprintf("/cluster/nextid?vmid=%d", currentID)
} else {
url = "/cluster/nextid"
}
_, err = c.session.GetJSON(url, nil, nil, &data)
if err == nil {
if data["errors"] != nil {
if currentID >= 100 {
return c.GetNextID(currentID + 1)
} else {
return -1, errors.New("error using /cluster/nextid")
}
}
nextID, err = strconv.Atoi(data["data"].(string))
}
return
}
// CreateVMDisk - Create single disk for VM on host node.
func (c *Client) CreateVMDisk(
nodeName string,
storageName string,
fullDiskName string,
diskParams map[string]interface{},
) error {
reqbody := ParamsToBody(diskParams)
url := fmt.Sprintf("/nodes/%s/storage/%s/content", nodeName, storageName)
resp, err := c.session.Post(url, nil, nil, &reqbody)
if err == nil {
taskResponse, err := ResponseJSON(resp)
if err != nil {
return err
}
if diskName, containsData := taskResponse["data"]; !containsData || diskName != fullDiskName {
return errors.New(fmt.Sprintf("Cannot create VM disk %s", fullDiskName))
}
} else {
return err
}
return nil
}
// createVMDisks - Make disks parameters and create all VM disks on host node.
func (c *Client) createVMDisks(
node string,
vmParams map[string]interface{},
) (disks []string, err error) {
var createdDisks []string
vmID := vmParams["vmid"].(int)
for deviceName, deviceConf := range vmParams {
rxStorageModels := `(ide|sata|scsi|virtio)\d+`
if matched, _ := regexp.MatchString(rxStorageModels, deviceName); matched {
deviceConfMap := ParseConf(deviceConf.(string), ",", "=")
// This if condition to differentiate between `disk` and `cdrom`.
if media, containsFile := deviceConfMap["media"]; containsFile && media == "disk" {
fullDiskName := deviceConfMap["file"].(string)
storageName, volumeName := getStorageAndVolumeName(fullDiskName, ":")
diskParams := map[string]interface{}{
"vmid": vmID,
"filename": volumeName,
"size": deviceConfMap["size"],
}
err := c.CreateVMDisk(node, storageName, fullDiskName, diskParams)
if err != nil {
return createdDisks, err
} else {
createdDisks = append(createdDisks, fullDiskName)
}
}
}
}
return createdDisks, nil
}
// DeleteVMDisks - Delete VM disks from host node.
// By default the VM disks are deteled when the VM is deleted,
// so mainly this is used to delete the disks in case VM creation didn't complete.
func (c *Client) DeleteVMDisks(
node string,
disks []string,
) error {
for _, fullDiskName := range disks {
storageName, volumeName := getStorageAndVolumeName(fullDiskName, ":")
url := fmt.Sprintf("/nodes/%s/storage/%s/content/%s", node, storageName, volumeName)
_, err := c.session.Post(url, nil, nil, nil)
if err != nil {
return err
}
}
return nil
}
// getStorageAndVolumeName - Extract disk storage and disk volume, since disk name is saved
// in Proxmox with its storage.
func getStorageAndVolumeName(
fullDiskName string,
separator string,
) (storageName string, diskName string) {
storageAndVolumeName := strings.Split(fullDiskName, separator)
storageName, volumeName := storageAndVolumeName[0], storageAndVolumeName[1]
// when disk type is dir, volumeName is `file=local:100/vm-100-disk-0.raw`
re := regexp.MustCompile(`\d+/(?P<filename>\S+.\S+)`)
match := re.FindStringSubmatch(volumeName)
if len(match) == 2 {
volumeName = match[1]
}
return storageName, volumeName
}

View File

@ -1,706 +0,0 @@
package proxmox
import (
"encoding/json"
"errors"
"fmt"
"io"
"log"
"math/rand"
"net"
"net/url"
"regexp"
"strconv"
"strings"
"time"
)
type (
QemuDevices map[int]map[string]interface{}
QemuDevice map[string]interface{}
QemuDeviceParam []string
)
// ConfigQemu - Proxmox API QEMU options
type ConfigQemu struct {
Name string `json:"name"`
Description string `json:"desc"`
Onboot bool `json:"onboot"`
Agent string `json:"agent"`
Memory int `json:"memory"`
QemuOs string `json:"os"`
QemuCores int `json:"cores"`
QemuSockets int `json:"sockets"`
QemuIso string `json:"iso"`
FullClone *int `json:"fullclone"`
QemuDisks QemuDevices `json:"disk"`
QemuNetworks QemuDevices `json:"network"`
// Deprecated single disk.
DiskSize float64 `json:"diskGB"`
Storage string `json:"storage"`
StorageType string `json:"storageType"` // virtio|scsi (cloud-init defaults to scsi)
// Deprecated single nic.
QemuNicModel string `json:"nic"`
QemuBrige string `json:"bridge"`
QemuVlanTag int `json:"vlan"`
QemuMacAddr string `json:"mac"`
// cloud-init options
CIuser string `json:"ciuser"`
CIpassword string `json:"cipassword"`
Searchdomain string `json:"searchdomain"`
Nameserver string `json:"nameserver"`
Sshkeys string `json:"sshkeys"`
// arrays are hard, support 2 interfaces for now
Ipconfig0 string `json:"ipconfig0"`
Ipconfig1 string `json:"ipconfig1"`
}
// CreateVm - Tell Proxmox API to make the VM
func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
if config.HasCloudInit() {
return errors.New("Cloud-init parameters only supported on clones or updates")
}
vmr.SetVmType("qemu")
params := map[string]interface{}{
"vmid": vmr.vmId,
"name": config.Name,
"onboot": config.Onboot,
"agent": config.Agent,
"ide2": config.QemuIso + ",media=cdrom",
"ostype": config.QemuOs,
"sockets": config.QemuSockets,
"cores": config.QemuCores,
"cpu": "host",
"memory": config.Memory,
"description": config.Description,
}
// Create disks config.
config.CreateQemuDisksParams(vmr.vmId, params, false)
// Create networks config.
config.CreateQemuNetworksParams(vmr.vmId, params)
exitStatus, err := client.CreateQemuVm(vmr.node, params)
if err != nil {
return fmt.Errorf("Error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params)
}
return
}
// HasCloudInit - are there cloud-init options?
func (config ConfigQemu) HasCloudInit() bool {
return config.CIuser != "" ||
config.CIpassword != "" ||
config.Searchdomain != "" ||
config.Nameserver != "" ||
config.Sshkeys != "" ||
config.Ipconfig0 != "" ||
config.Ipconfig1 != ""
}
/*
CloneVm
Example: Request
nodes/proxmox1-xx/qemu/1012/clone
newid:145
name:tf-clone1
target:proxmox1-xx
full:1
storage:xxx
*/
func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) (err error) {
vmr.SetVmType("qemu")
fullclone := "1"
if config.FullClone != nil {
fullclone = strconv.Itoa(*config.FullClone)
}
storage := config.Storage
if disk0Storage, ok := config.QemuDisks[0]["storage"].(string); ok && len(disk0Storage) > 0 {
storage = disk0Storage
}
params := map[string]interface{}{
"newid": vmr.vmId,
"target": vmr.node,
"name": config.Name,
"storage": storage,
"full": fullclone,
}
_, err = client.CloneQemuVm(sourceVmr, params)
if err != nil {
return
}
return config.UpdateConfig(vmr, client)
}
func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
configParams := map[string]interface{}{
"name": config.Name,
"description": config.Description,
"onboot": config.Onboot,
"agent": config.Agent,
"sockets": config.QemuSockets,
"cores": config.QemuCores,
"memory": config.Memory,
}
// Create disks config.
config.CreateQemuDisksParams(vmr.vmId, configParams, true)
// Create networks config.
config.CreateQemuNetworksParams(vmr.vmId, configParams)
// cloud-init options
if config.CIuser != "" {
configParams["ciuser"] = config.CIuser
}
if config.CIpassword != "" {
configParams["cipassword"] = config.CIpassword
}
if config.Searchdomain != "" {
configParams["searchdomain"] = config.Searchdomain
}
if config.Nameserver != "" {
configParams["nameserver"] = config.Nameserver
}
if config.Sshkeys != "" {
sshkeyEnc := url.PathEscape(config.Sshkeys + "\n")
sshkeyEnc = strings.Replace(sshkeyEnc, "+", "%2B", -1)
sshkeyEnc = strings.Replace(sshkeyEnc, "@", "%40", -1)
sshkeyEnc = strings.Replace(sshkeyEnc, "=", "%3D", -1)
configParams["sshkeys"] = sshkeyEnc
}
if config.Ipconfig0 != "" {
configParams["ipconfig0"] = config.Ipconfig0
}
if config.Ipconfig1 != "" {
configParams["ipconfig1"] = config.Ipconfig1
}
_, err = client.SetVmConfig(vmr, configParams)
return err
}
func NewConfigQemuFromJson(io io.Reader) (config *ConfigQemu, err error) {
config = &ConfigQemu{QemuVlanTag: -1}
err = json.NewDecoder(io).Decode(config)
if err != nil {
log.Fatal(err)
return nil, err
}
log.Println(config)
return
}
var (
rxIso = regexp.MustCompile(`(.*?),media`)
rxDeviceID = regexp.MustCompile(`\d+`)
rxDiskName = regexp.MustCompile(`(virtio|scsi)\d+`)
rxDiskType = regexp.MustCompile(`\D+`)
rxNicName = regexp.MustCompile(`net\d+`)
)
func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err error) {
var vmConfig map[string]interface{}
for ii := 0; ii < 3; ii++ {
vmConfig, err = client.GetVmConfig(vmr)
if err != nil {
log.Fatal(err)
return nil, err
}
// this can happen:
// {"data":{"lock":"clone","digest":"eb54fb9d9f120ba0c3bdf694f73b10002c375c38","description":" qmclone temporary file\n"}})
if vmConfig["lock"] == nil {
break
} else {
time.Sleep(8 * time.Second)
}
}
if vmConfig["lock"] != nil {
return nil, errors.New("vm locked, could not obtain config")
}
// vmConfig Sample: map[ cpu:host
// net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0
// ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048
// smbios1:uuid=8b3bf833-aad8-4545-xxx-xxxxxxx digest:aa6ce5xxxxx1b9ce33e4aaeff564d4 sockets:1
// name:terraform-ubuntu1404-template bootdisk:virtio0
// virtio0:ProxmoxxxxISCSI:vm-1014-disk-2,size=4G
// description:Base image
// cores:2 ostype:l26
name := ""
if _, isSet := vmConfig["name"]; isSet {
name = vmConfig["name"].(string)
}
description := ""
if _, isSet := vmConfig["description"]; isSet {
description = vmConfig["description"].(string)
}
onboot := true
if _, isSet := vmConfig["onboot"]; isSet {
onboot = Itob(int(vmConfig["onboot"].(float64)))
}
agent := "1"
if _, isSet := vmConfig["agent"]; isSet {
agent = vmConfig["agent"].(string)
}
ostype := "other"
if _, isSet := vmConfig["ostype"]; isSet {
ostype = vmConfig["ostype"].(string)
}
memory := 0.0
if _, isSet := vmConfig["memory"]; isSet {
memory = vmConfig["memory"].(float64)
}
cores := 1.0
if _, isSet := vmConfig["cores"]; isSet {
cores = vmConfig["cores"].(float64)
}
sockets := 1.0
if _, isSet := vmConfig["sockets"]; isSet {
sockets = vmConfig["sockets"].(float64)
}
config = &ConfigQemu{
Name: name,
Description: strings.TrimSpace(description),
Onboot: onboot,
Agent: agent,
QemuOs: ostype,
Memory: int(memory),
QemuCores: int(cores),
QemuSockets: int(sockets),
QemuVlanTag: -1,
QemuDisks: QemuDevices{},
QemuNetworks: QemuDevices{},
}
if vmConfig["ide2"] != nil {
isoMatch := rxIso.FindStringSubmatch(vmConfig["ide2"].(string))
config.QemuIso = isoMatch[1]
}
if _, isSet := vmConfig["ciuser"]; isSet {
config.CIuser = vmConfig["ciuser"].(string)
}
if _, isSet := vmConfig["cipassword"]; isSet {
config.CIpassword = vmConfig["cipassword"].(string)
}
if _, isSet := vmConfig["searchdomain"]; isSet {
config.Searchdomain = vmConfig["searchdomain"].(string)
}
if _, isSet := vmConfig["sshkeys"]; isSet {
config.Sshkeys, _ = url.PathUnescape(vmConfig["sshkeys"].(string))
}
if _, isSet := vmConfig["ipconfig0"]; isSet {
config.Ipconfig0 = vmConfig["ipconfig0"].(string)
}
if _, isSet := vmConfig["ipconfig1"]; isSet {
config.Ipconfig1 = vmConfig["ipconfig1"].(string)
}
// Add disks.
diskNames := []string{}
for k, _ := range vmConfig {
if diskName := rxDiskName.FindStringSubmatch(k); len(diskName) > 0 {
diskNames = append(diskNames, diskName[0])
}
}
for _, diskName := range diskNames {
diskConfStr := vmConfig[diskName]
diskConfList := strings.Split(diskConfStr.(string), ",")
//
id := rxDeviceID.FindStringSubmatch(diskName)
diskID, _ := strconv.Atoi(id[0])
diskType := rxDiskType.FindStringSubmatch(diskName)[0]
storageName, fileName := ParseSubConf(diskConfList[0], ":")
//
diskConfMap := QemuDevice{
"type": diskType,
"storage": storageName,
"file": fileName,
}
// Add rest of device config.
diskConfMap.readDeviceConfig(diskConfList[1:])
// And device config to disks map.
if len(diskConfMap) > 0 {
config.QemuDisks[diskID] = diskConfMap
}
}
// Add networks.
nicNameRe := regexp.MustCompile(`net\d+`)
nicNames := []string{}
for k, _ := range vmConfig {
if nicName := nicNameRe.FindStringSubmatch(k); len(nicName) > 0 {
nicNames = append(nicNames, nicName[0])
}
}
for _, nicName := range nicNames {
nicConfStr := vmConfig[nicName]
nicConfList := strings.Split(nicConfStr.(string), ",")
//
id := rxDeviceID.FindStringSubmatch(nicName)
nicID, _ := strconv.Atoi(id[0])
model, macaddr := ParseSubConf(nicConfList[0], "=")
// Add model and MAC address.
nicConfMap := QemuDevice{
"model": model,
"macaddr": macaddr,
}
// Add rest of device config.
nicConfMap.readDeviceConfig(nicConfList[1:])
// And device config to networks.
if len(nicConfMap) > 0 {
config.QemuNetworks[nicID] = nicConfMap
}
}
return
}
// Useful waiting for ISO install to complete
func WaitForShutdown(vmr *VmRef, client *Client) (err error) {
for ii := 0; ii < 100; ii++ {
vmState, err := client.GetVmState(vmr)
if err != nil {
log.Print("Wait error:")
log.Println(err)
} else if vmState["status"] == "stopped" {
return nil
}
time.Sleep(5 * time.Second)
}
return errors.New("Not shutdown within wait time")
}
// This is because proxmox create/config API won't let us make usernet devices
func SshForwardUsernet(vmr *VmRef, client *Client) (sshPort string, err error) {
vmState, err := client.GetVmState(vmr)
if err != nil {
return "", err
}
if vmState["status"] == "stopped" {
return "", errors.New("VM must be running first")
}
sshPort = strconv.Itoa(vmr.VmId() + 22000)
_, err = client.MonitorCmd(vmr, "netdev_add user,id=net1,hostfwd=tcp::"+sshPort+"-:22")
if err != nil {
return "", err
}
_, err = client.MonitorCmd(vmr, "device_add virtio-net-pci,id=net1,netdev=net1,addr=0x13")
if err != nil {
return "", err
}
return
}
// device_del net1
// netdev_del net1
func RemoveSshForwardUsernet(vmr *VmRef, client *Client) (err error) {
vmState, err := client.GetVmState(vmr)
if err != nil {
return err
}
if vmState["status"] == "stopped" {
return errors.New("VM must be running first")
}
_, err = client.MonitorCmd(vmr, "device_del net1")
if err != nil {
return err
}
_, err = client.MonitorCmd(vmr, "netdev_del net1")
if err != nil {
return err
}
return nil
}
func MaxVmId(client *Client) (max int, err error) {
resp, err := client.GetVmList()
vms := resp["data"].([]interface{})
max = 0
for vmii := range vms {
vm := vms[vmii].(map[string]interface{})
vmid := int(vm["vmid"].(float64))
if vmid > max {
max = vmid
}
}
return
}
func SendKeysString(vmr *VmRef, client *Client, keys string) (err error) {
vmState, err := client.GetVmState(vmr)
if err != nil {
return err
}
if vmState["status"] == "stopped" {
return errors.New("VM must be running first")
}
for _, r := range keys {
c := string(r)
lower := strings.ToLower(c)
if c != lower {
c = "shift-" + lower
} else {
switch c {
case "!":
c = "shift-1"
case "@":
c = "shift-2"
case "#":
c = "shift-3"
case "$":
c = "shift-4"
case "%%":
c = "shift-5"
case "^":
c = "shift-6"
case "&":
c = "shift-7"
case "*":
c = "shift-8"
case "(":
c = "shift-9"
case ")":
c = "shift-0"
case "_":
c = "shift-minus"
case "+":
c = "shift-equal"
case " ":
c = "spc"
case "/":
c = "slash"
case "\\":
c = "backslash"
case ",":
c = "comma"
case "-":
c = "minus"
case "=":
c = "equal"
case ".":
c = "dot"
case "?":
c = "shift-slash"
}
}
_, err = client.MonitorCmd(vmr, "sendkey "+c)
if err != nil {
return err
}
time.Sleep(100)
}
return nil
}
// Create parameters for each Nic device.
func (c ConfigQemu) CreateQemuNetworksParams(vmID int, params map[string]interface{}) error {
// For backward compatibility.
if len(c.QemuNetworks) == 0 && len(c.QemuNicModel) > 0 {
deprecatedStyleMap := QemuDevice{
"model": c.QemuNicModel,
"bridge": c.QemuBrige,
"macaddr": c.QemuMacAddr,
}
if c.QemuVlanTag > 0 {
deprecatedStyleMap["tag"] = strconv.Itoa(c.QemuVlanTag)
}
c.QemuNetworks[0] = deprecatedStyleMap
}
// For new style with multi net device.
for nicID, nicConfMap := range c.QemuNetworks {
nicConfParam := QemuDeviceParam{}
// Set Nic name.
qemuNicName := "net" + strconv.Itoa(nicID)
// Set Mac address.
if nicConfMap["macaddr"] == nil || nicConfMap["macaddr"].(string) == "" {
// Generate Mac based on VmID and NicID so it will be the same always.
macaddr := make(net.HardwareAddr, 6)
rand.Seed(time.Now().UnixNano())
rand.Read(macaddr)
macaddr[0] = (macaddr[0] | 2) & 0xfe // fix from github issue #18
macAddrUppr := strings.ToUpper(fmt.Sprintf("%v", macaddr))
// use model=mac format for older proxmox compatability
macAddr := fmt.Sprintf("%v=%v", nicConfMap["model"], macAddrUppr)
// Add Mac to source map so it will be returned. (useful for some use case like Terraform)
nicConfMap["macaddr"] = macAddrUppr
// and also add it to the parameters which will be sent to Proxmox API.
nicConfParam = append(nicConfParam, macAddr)
} else {
macAddr := fmt.Sprintf("%v=%v", nicConfMap["model"], nicConfMap["macaddr"].(string))
nicConfParam = append(nicConfParam, macAddr)
}
// Set bridge if not nat.
if nicConfMap["bridge"].(string) != "nat" {
bridge := fmt.Sprintf("bridge=%v", nicConfMap["bridge"])
nicConfParam = append(nicConfParam, bridge)
}
// Keys that are not used as real/direct conf.
ignoredKeys := []string{"id", "bridge", "macaddr", "model"}
// Rest of config.
nicConfParam = nicConfParam.createDeviceParam(nicConfMap, ignoredKeys)
// Add nic to Qemu prams.
params[qemuNicName] = strings.Join(nicConfParam, ",")
}
return nil
}
// Create parameters for each disk.
func (c ConfigQemu) CreateQemuDisksParams(
vmID int,
params map[string]interface{},
cloned bool,
) error {
// For backward compatibility.
if len(c.QemuDisks) == 0 && len(c.Storage) > 0 {
dType := c.StorageType
if dType == "" {
if c.HasCloudInit() {
dType = "scsi"
} else {
dType = "virtio"
}
}
deprecatedStyleMap := QemuDevice{
"type": dType,
"storage": c.Storage,
"size": c.DiskSize,
"storage_type": "lvm", // default old style
"cache": "none", // default old value
}
c.QemuDisks[0] = deprecatedStyleMap
}
// For new style with multi disk device.
for diskID, diskConfMap := range c.QemuDisks {
// skip the first disk for clones (may not always be right, but a template probably has at least 1 disk)
if diskID == 0 && cloned {
continue
}
diskConfParam := QemuDeviceParam{
"media=disk",
}
// Device name.
deviceType := diskConfMap["type"].(string)
qemuDiskName := deviceType + strconv.Itoa(diskID)
// Set disk storage.
// Disk size.
diskSizeGB := fmt.Sprintf("size=%v", diskConfMap["size"])
diskConfParam = append(diskConfParam, diskSizeGB)
// Disk name.
var diskFile string
// Currently ZFS local, LVM, and Directory are considered.
// Other formats are not verified, but could be added if they're needed.
rxStorageTypes := `(zfspool|lvm)`
storageType := diskConfMap["storage_type"].(string)
if matched, _ := regexp.MatchString(rxStorageTypes, storageType); matched {
diskFile = fmt.Sprintf("file=%v:vm-%v-disk-%v", diskConfMap["storage"], vmID, diskID)
} else {
diskFile = fmt.Sprintf("file=%v:%v/vm-%v-disk-%v.%v", diskConfMap["storage"], vmID, vmID, diskID, diskConfMap["format"])
}
diskConfParam = append(diskConfParam, diskFile)
// Set cache if not none (default).
if diskConfMap["cache"].(string) != "none" {
diskCache := fmt.Sprintf("cache=%v", diskConfMap["cache"])
diskConfParam = append(diskConfParam, diskCache)
}
// Keys that are not used as real/direct conf.
ignoredKeys := []string{"id", "type", "storage", "storage_type", "size", "cache"}
// Rest of config.
diskConfParam = diskConfParam.createDeviceParam(diskConfMap, ignoredKeys)
// Add back to Qemu prams.
params[qemuDiskName] = strings.Join(diskConfParam, ",")
}
return nil
}
// Create the parameters for each device that will be sent to Proxmox API.
func (p QemuDeviceParam) createDeviceParam(
deviceConfMap QemuDevice,
ignoredKeys []string,
) QemuDeviceParam {
for key, value := range deviceConfMap {
if ignored := inArray(ignoredKeys, key); !ignored {
var confValue interface{}
if bValue, ok := value.(bool); ok && bValue {
confValue = "1"
} else if sValue, ok := value.(string); ok && len(sValue) > 0 {
confValue = sValue
} else if iValue, ok := value.(int); ok && iValue > 0 {
confValue = iValue
}
if confValue != nil {
deviceConf := fmt.Sprintf("%v=%v", key, confValue)
p = append(p, deviceConf)
}
}
}
return p
}
// readDeviceConfig - get standard sub-conf strings where `key=value` and update conf map.
func (confMap QemuDevice) readDeviceConfig(confList []string) error {
// Add device config.
for _, conf := range confList {
key, value := ParseSubConf(conf, "=")
confMap[key] = value
}
return nil
}
func (c ConfigQemu) String() string {
jsConf, _ := json.Marshal(c)
return string(jsConf)
}

View File

@ -1,319 +0,0 @@
package proxmox
// inspired by https://github.com/openstack/golang-client/blob/master/openstack/session.go
import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"net/url"
)
var Debug = new(bool)
type Response struct {
Resp *http.Response
Body []byte
}
type Session struct {
httpClient *http.Client
ApiUrl string
AuthTicket string
CsrfToken string
Headers http.Header
}
func NewSession(apiUrl string, hclient *http.Client, tls *tls.Config) (session *Session, err error) {
if hclient == nil {
// Only build a transport if we're also building the client
tr := &http.Transport{
TLSClientConfig: tls,
DisableCompression: true,
}
hclient = &http.Client{Transport: tr}
}
session = &Session{
httpClient: hclient,
ApiUrl: apiUrl,
AuthTicket: "",
CsrfToken: "",
Headers: http.Header{},
}
return session, nil
}
func ParamsToBody(params map[string]interface{}) (body []byte) {
vals := url.Values{}
for k, intrV := range params {
var v string
switch intrV.(type) {
// Convert true/false bool to 1/0 string where Proxmox API can understand it.
case bool:
if intrV.(bool) {
v = "1"
} else {
v = "0"
}
default:
v = fmt.Sprintf("%v", intrV)
}
vals.Set(k, v)
}
body = bytes.NewBufferString(vals.Encode()).Bytes()
return
}
func decodeResponse(resp *http.Response, v interface{}) error {
if resp.Body == nil {
return nil
}
rbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("error reading response body: %s", err)
}
if err = json.Unmarshal(rbody, &v); err != nil {
return err
}
return nil
}
func ResponseJSON(resp *http.Response) (jbody map[string]interface{}, err error) {
err = decodeResponse(resp, &jbody)
return jbody, err
}
func TypedResponse(resp *http.Response, v interface{}) error {
var intermediate struct {
Data struct {
Result json.RawMessage `json:"result"`
} `json:"data"`
}
err := decodeResponse(resp, &intermediate)
if err != nil {
return fmt.Errorf("error reading response envelope: %v", err)
}
if err = json.Unmarshal(intermediate.Data.Result, v); err != nil {
return fmt.Errorf("error unmarshalling result %v", err)
}
return nil
}
func (s *Session) Login(username string, password string) (err error) {
reqbody := ParamsToBody(map[string]interface{}{"username": username, "password": password})
olddebug := *Debug
*Debug = false // don't share passwords in debug log
resp, err := s.Post("/access/ticket", nil, nil, &reqbody)
*Debug = olddebug
if err != nil {
return err
}
if resp == nil {
return errors.New("Login error reading response")
}
dr, _ := httputil.DumpResponse(resp, true)
jbody, err := ResponseJSON(resp)
if err != nil {
return err
}
if jbody == nil || jbody["data"] == nil {
return fmt.Errorf("Invalid login response:\n-----\n%s\n-----", dr)
}
dat := jbody["data"].(map[string]interface{})
s.AuthTicket = dat["ticket"].(string)
s.CsrfToken = dat["CSRFPreventionToken"].(string)
return nil
}
func (s *Session) NewRequest(method, url string, headers *http.Header, body io.Reader) (req *http.Request, err error) {
req, err = http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
if headers != nil {
req.Header = *headers
}
if s.AuthTicket != "" {
req.Header.Add("Cookie", "PVEAuthCookie="+s.AuthTicket)
req.Header.Add("CSRFPreventionToken", s.CsrfToken)
}
return
}
func (s *Session) Do(req *http.Request) (*http.Response, error) {
// Add session headers
for k := range s.Headers {
req.Header.Set(k, s.Headers.Get(k))
}
if *Debug {
d, _ := httputil.DumpRequestOut(req, true)
log.Printf(">>>>>>>>>> REQUEST:\n", string(d))
}
resp, err := s.httpClient.Do(req)
if err != nil {
return nil, err
}
if *Debug {
dr, _ := httputil.DumpResponse(resp, true)
log.Printf("<<<<<<<<<< RESULT:\n", string(dr))
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return resp, errors.New(resp.Status)
}
return resp, nil
}
// Perform a simple get to an endpoint
func (s *Session) Request(
method string,
url string,
params *url.Values,
headers *http.Header,
body *[]byte,
) (resp *http.Response, err error) {
// add params to url here
url = s.ApiUrl + url
if params != nil {
url = url + "?" + params.Encode()
}
// Get the body if one is present
var buf io.Reader
if body != nil {
buf = bytes.NewReader(*body)
}
req, err := s.NewRequest(method, url, headers, buf)
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/json")
return s.Do(req)
}
// Perform a simple get to an endpoint and unmarshall returned JSON
func (s *Session) RequestJSON(
method string,
url string,
params *url.Values,
headers *http.Header,
body interface{},
responseContainer interface{},
) (resp *http.Response, err error) {
var bodyjson []byte
if body != nil {
bodyjson, err = json.Marshal(body)
if err != nil {
return nil, err
}
}
// if headers == nil {
// headers = &http.Header{}
// headers.Add("Content-Type", "application/json")
// }
resp, err = s.Request(method, url, params, headers, &bodyjson)
if err != nil {
return resp, err
}
// err = util.CheckHTTPResponseStatusCode(resp)
// if err != nil {
// return nil, err
// }
rbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return resp, errors.New("error reading response body")
}
if err = json.Unmarshal(rbody, &responseContainer); err != nil {
return resp, err
}
return resp, nil
}
func (s *Session) Delete(
url string,
params *url.Values,
headers *http.Header,
) (resp *http.Response, err error) {
return s.Request("DELETE", url, params, headers, nil)
}
func (s *Session) Get(
url string,
params *url.Values,
headers *http.Header,
) (resp *http.Response, err error) {
return s.Request("GET", url, params, headers, nil)
}
func (s *Session) GetJSON(
url string,
params *url.Values,
headers *http.Header,
responseContainer interface{},
) (resp *http.Response, err error) {
return s.RequestJSON("GET", url, params, headers, nil, responseContainer)
}
func (s *Session) Head(
url string,
params *url.Values,
headers *http.Header,
) (resp *http.Response, err error) {
return s.Request("HEAD", url, params, headers, nil)
}
func (s *Session) Post(
url string,
params *url.Values,
headers *http.Header,
body *[]byte,
) (resp *http.Response, err error) {
if headers == nil {
headers = &http.Header{}
headers.Add("Content-Type", "application/x-www-form-urlencoded")
}
return s.Request("POST", url, params, headers, body)
}
func (s *Session) PostJSON(
url string,
params *url.Values,
headers *http.Header,
body interface{},
responseContainer interface{},
) (resp *http.Response, err error) {
return s.RequestJSON("POST", url, params, headers, body, responseContainer)
}
func (s *Session) Put(
url string,
params *url.Values,
headers *http.Header,
body *[]byte,
) (resp *http.Response, err error) {
if headers == nil {
headers = &http.Header{}
headers.Add("Content-Type", "application/x-www-form-urlencoded")
}
return s.Request("PUT", url, params, headers, body)
}

View File

@ -1,62 +0,0 @@
package proxmox
import (
"strconv"
"strings"
)
func inArray(arr []string, str string) bool {
for _, elem := range arr {
if elem == str {
return true
}
}
return false
}
func Itob(i int) bool {
if i == 1 {
return true
}
return false
}
// ParseSubConf - Parse standard sub-conf strings `key=value`.
func ParseSubConf(
element string,
separator string,
) (key string, value interface{}) {
if strings.Contains(element, separator) {
conf := strings.Split(element, separator)
key, value := conf[0], conf[1]
var interValue interface{}
// Make sure to add value in right type,
// because all subconfig are returned as strings from Proxmox API.
if iValue, err := strconv.ParseInt(value, 10, 64); err == nil {
interValue = int(iValue)
} else if bValue, err := strconv.ParseBool(value); err == nil {
interValue = bValue
} else {
interValue = value
}
return key, interValue
}
return
}
// ParseConf - Parse standard device conf string `key1=val1,key2=val2`.
func ParseConf(
kvString string,
confSeparator string,
subConfSeparator string,
) QemuDevice {
var confMap = QemuDevice{}
confList := strings.Split(kvString, confSeparator)
for _, item := range confList {
key, value := ParseSubConf(item, subConfSeparator)
confMap[key] = value
}
return confMap
}

32
vendor/github.com/antchfx/xpath/.gitignore generated vendored Normal file
View File

@ -0,0 +1,32 @@
# vscode
.vscode
debug
*.test
./build
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

12
vendor/github.com/antchfx/xpath/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,12 @@
language: go
go:
- 1.6
- 1.7
- 1.8
install:
- go get github.com/mattn/goveralls
script:
- $HOME/gopath/bin/goveralls -service=travis-ci

View File

@ -0,0 +1,25 @@
*.received.*
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@ -0,0 +1,16 @@
sudo: false
language: go
go:
- 1.6
install:
- go get -u github.com/golang/lint/golint
script:
- test -z "$(go fmt -s -l -w ./... | tee /dev/stderr)"
- golint -set_exit_status ./...
- go vet ./...
- go build -v ./...
- go test -v ./...

24
vendor/github.com/armon/go-metrics/.gitignore generated vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
/metrics.out

22
vendor/github.com/armon/go-radix/.gitignore generated vendored Normal file
View File

@ -0,0 +1,22 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe

3
vendor/github.com/armon/go-radix/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,3 @@
language: go
go:
- tip

1
vendor/github.com/armon/go-radix/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/armon/go-radix

View File

@ -44,13 +44,13 @@ func (n *node) addEdge(e edge) {
n.edges.Sort()
}
func (n *node) replaceEdge(e edge) {
func (n *node) updateEdge(label byte, node *node) {
num := len(n.edges)
idx := sort.Search(num, func(i int) bool {
return n.edges[i].label >= e.label
return n.edges[i].label >= label
})
if idx < num && n.edges[idx].label == e.label {
n.edges[idx].node = e.node
if idx < num && n.edges[idx].label == label {
n.edges[idx].node = node
return
}
panic("replacing missing edge")
@ -198,10 +198,7 @@ func (t *Tree) Insert(s string, v interface{}) (interface{}, bool) {
child := &node{
prefix: search[:commonPrefix],
}
parent.replaceEdge(edge{
label: search[0],
node: child,
})
parent.updateEdge(search[0], child)
// Restore the existing node
child.addEdge(edge{
@ -292,6 +289,53 @@ DELETE:
return leaf.val, true
}
// DeletePrefix is used to delete the subtree under a prefix
// Returns how many nodes were deleted
// Use this to delete large subtrees efficiently
func (t *Tree) DeletePrefix(s string) int {
return t.deletePrefix(nil, t.root, s)
}
// delete does a recursive deletion
func (t *Tree) deletePrefix(parent, n *node, prefix string) int {
// Check for key exhaustion
if len(prefix) == 0 {
// Remove the leaf node
subTreeSize := 0
//recursively walk from all edges of the node to be deleted
recursiveWalk(n, func(s string, v interface{}) bool {
subTreeSize++
return false
})
if n.isLeaf() {
n.leaf = nil
}
n.edges = nil // deletes the entire subtree
// Check if we should merge the parent's other child
if parent != nil && parent != t.root && len(parent.edges) == 1 && !parent.isLeaf() {
parent.mergeChild()
}
t.size -= subTreeSize
return subTreeSize
}
// Look for an edge
label := prefix[0]
child := n.getEdge(label)
if child == nil || (!strings.HasPrefix(child.prefix, prefix) && !strings.HasPrefix(prefix, child.prefix)) {
return 0
}
// Consume the search prefix
if len(child.prefix) > len(prefix) {
prefix = prefix[len(prefix):]
} else {
prefix = prefix[len(child.prefix):]
}
return t.deletePrefix(n, child, prefix)
}
func (n *node) mergeChild() {
e := n.edges[0]
child := e.node

View File

@ -1,6 +1,5 @@
The MIT License (MIT)
Copyright (c) 2015 Microsoft Corporation
Original version Copyright © 2010 Fazlul Shahriar <fshahriar@gmail.com>. Newer
portions Copyright © 2014 Blake Gentry <blakesgentry@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

2
vendor/github.com/bgentry/speakeasy/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
example/example
example/example.exe

View File

@ -1,6 +1,9 @@
The MIT License (MIT)
MIT License
Copyright (c) 2017 <copyright holders>
Copyright (c) 2017 Blake Gentry
This license applies to the non-Windows portions of this library. The Windows
portion maintains its own Apache 2.0 license.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -9,13 +12,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,18 +0,0 @@
package main
import (
"fmt"
"os"
"github.com/bgentry/speakeasy"
)
func main() {
password, err := speakeasy.Ask("Please enter a password: ")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("Password result: %q\n", password)
fmt.Printf("Password len: %d\n", len(password))
}

View File

@ -14,16 +14,18 @@ func Ask(prompt string) (password string, err error) {
return FAsk(os.Stdout, prompt)
}
// Same as the Ask function, except it is possible to specify the file to write
// the prompt to.
func FAsk(file *os.File, prompt string) (password string, err error) {
if prompt != "" {
fmt.Fprint(file, prompt) // Display the prompt.
// FAsk is the same as Ask, except it is possible to specify the file to write
// the prompt to. If 'nil' is passed as the writer, no prompt will be written.
func FAsk(wr io.Writer, prompt string) (password string, err error) {
if wr != nil && prompt != "" {
fmt.Fprint(wr, prompt) // Display the prompt.
}
password, err = getPassword()
// Carriage return after the user input.
fmt.Fprintln(file, "")
if wr != nil {
fmt.Fprintln(wr, "")
}
return
}

View File

@ -4,7 +4,7 @@
// Original code is based on code by RogerV in the golang-nuts thread:
// https://groups.google.com/group/golang-nuts/browse_thread/thread/40cc41e9d9fc9247
// +build darwin freebsd linux netbsd openbsd solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package speakeasy

View File

@ -3,7 +3,6 @@
package speakeasy
import (
"os"
"syscall"
)
@ -12,18 +11,17 @@ import (
const ENABLE_ECHO_INPUT = 0x0004
func getPassword() (password string, err error) {
hStdin := syscall.Handle(os.Stdin.Fd())
var oldMode uint32
err = syscall.GetConsoleMode(hStdin, &oldMode)
err = syscall.GetConsoleMode(syscall.Stdin, &oldMode)
if err != nil {
return
}
var newMode uint32 = (oldMode &^ ENABLE_ECHO_INPUT)
err = setConsoleMode(hStdin, newMode)
defer setConsoleMode(hStdin, oldMode)
err = setConsoleMode(syscall.Stdin, newMode)
defer setConsoleMode(syscall.Stdin, oldMode)
if err != nil {
return
}

29
vendor/github.com/creack/goselect/.gitignore generated vendored Normal file
View File

@ -0,0 +1,29 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
go-select*
goselect*
example-*
example/example

0
vendor/github.com/creack/goselect/test_crosscompile.sh generated vendored Executable file → Normal file
View File

View File

@ -2,7 +2,7 @@ ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

View File

@ -16,7 +16,9 @@
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
// Go versions prior to 1.4 are disabled because they use a different layout
// for interfaces which make the implementation of unsafeReflectValue more complex.
// +build !js,!appengine,!safe,!disableunsafe,go1.4
package spew
@ -34,80 +36,49 @@ const (
ptrSize = unsafe.Sizeof((*byte)(nil))
)
var (
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
type flag uintptr
// flagKindWidth and flagKindShift indicate various bits that the
// reflect package uses internally to track kind information.
//
// flagRO indicates whether or not the value field of a reflect.Value is
// read-only.
//
// flagIndir indicates whether the value field of a reflect.Value is
// the actual data or a pointer to the data.
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
var (
// flagRO indicates whether the value field of a reflect.Value
// is read-only.
flagRO flag
// flagAddr indicates whether the address of the reflect.Value's
// value may be taken.
flagAddr flag
)
func init() {
// Older versions of reflect.Value stored small integers directly in the
// ptr field (which is named val in the older versions). Versions
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// flagKindMask holds the bits that make up the kind
// part of the flags field. In all the supported versions,
// it is in the lower 5 bits.
const flagKindMask = flag(0x1f)
// Commit 90a7c3c86944 changed the flag positions such that the low
// order bits are the kind. This code extracts the kind from the flags
// field and ensures it's the correct type. When it's not, the flag
// order has been changed to the newer format, so the flags are updated
// accordingly.
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
upfv := *(*uintptr)(upf)
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
flagKindShift = 0
flagRO = 1 << 5
flagIndir = 1 << 6
// Different versions of Go have used different
// bit layouts for the flags type. This table
// records the known combinations.
var okFlags = []struct {
ro, addr flag
}{{
// From Go 1.4 to 1.5
ro: 1 << 5,
addr: 1 << 7,
}, {
// Up to Go tip.
ro: 1<<5 | 1<<6,
addr: 1 << 8,
}}
// Commit adf9b30e5594 modified the flags to separate the
// flagRO flag into two bits which specifies whether or not the
// field is embedded. This causes flagIndir to move over a bit
// and means that flagRO is the combination of either of the
// original flagRO bit and the new bit.
//
// This code detects the change by extracting what used to be
// the indirect bit to ensure it's set. When it's not, the flag
// order has been changed to the newer format, so the flags are
// updated accordingly.
if upfv&flagIndir == 0 {
flagRO = 3 << 5
flagIndir = 1 << 7
}
var flagValOffset = func() uintptr {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
return field.Offset
}()
// flagField returns a pointer to the flag field of a reflect.Value.
func flagField(v *reflect.Value) *flag {
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
@ -119,34 +90,56 @@ func init() {
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
indirects := 1
vt := v.Type()
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
if rvf&flagIndir != 0 {
vt = reflect.PtrTo(v.Type())
indirects++
} else if offsetScalar != 0 {
// The value is in the scalar field when it's not one of the
// reference types.
switch vt.Kind() {
case reflect.Uintptr:
case reflect.Chan:
case reflect.Func:
case reflect.Map:
case reflect.Ptr:
case reflect.UnsafePointer:
default:
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
offsetScalar)
func unsafeReflectValue(v reflect.Value) reflect.Value {
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
return v
}
flagFieldPtr := flagField(&v)
*flagFieldPtr &^= flagRO
*flagFieldPtr |= flagAddr
return v
}
// Sanity checks against future reflect package changes
// to the type or semantics of the Value.flag field.
func init() {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
panic("reflect.Value flag field has changed kind")
}
type t0 int
var t struct {
A t0
// t0 will have flagEmbedRO set.
t0
// a will have flagStickyRO set
a t0
}
vA := reflect.ValueOf(t).FieldByName("A")
va := reflect.ValueOf(t).FieldByName("a")
vt0 := reflect.ValueOf(t).FieldByName("t0")
// Infer flagRO from the difference between the flags
// for the (otherwise identical) fields in t.
flagPublic := *flagField(&vA)
flagWithRO := *flagField(&va) | *flagField(&vt0)
flagRO = flagPublic ^ flagWithRO
// Infer flagAddr from the difference between a value
// taken from a pointer and not.
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
flagNoPtr := *flagField(&vA)
flagPtr := *flagField(&vPtrA)
flagAddr = flagNoPtr ^ flagPtr
// Check that the inferred flags tally with one of the known versions.
for _, f := range okFlags {
if flagRO == f.ro && flagAddr == f.addr {
return
}
}
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
panic("reflect.Value read-only flag has changed semantics")
}

38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe !go1.4
package spew
import "reflect"
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = true
)
// unsafeReflectValue typically converts the passed reflect.Value into a one
// that bypasses the typical safety restrictions preventing access to
// unaddressable and unexported data. However, doing this relies on access to
// the unsafe package. This is a stub version which simply returns the passed
// reflect.Value when the unsafe package is not available.
func unsafeReflectValue(v reflect.Value) reflect.Value {
return v
}

View File

@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) {
w.Write(closeParenBytes)
}
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
// Null pointer.

View File

@ -35,16 +35,16 @@ var (
// cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump
// them.
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
)
// dumpState contains information about the state of a dump operation.
@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
// Display dereferenced value.
d.w.Write(openParenBytes)
switch {
case nilFound == true:
case nilFound:
d.w.Write(nilAngleBytes)
case cycleFound == true:
case cycleFound:
d.w.Write(circularBytes)
default:

View File

@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
// Display dereferenced value.
switch {
case nilFound == true:
case nilFound:
f.fs.Write(nilAngleBytes)
case cycleFound == true:
case cycleFound:
f.fs.Write(circularShortBytes)
default:

View File

@ -69,7 +69,6 @@ func (client *Client) NewInit(endpoint, version, accessKeyId, accessKeySecret, s
client.Init(endpoint, version, accessKeyId, accessKeySecret)
client.serviceCode = serviceCode
client.regionID = regionID
client.setEndpointByLocation(regionID, serviceCode, accessKeyId, accessKeySecret, client.securityToken)
}
// Intialize client object when all properties are ready
@ -86,7 +85,6 @@ func (client *Client) InitClient() *Client {
TLSHandshakeTimeout: time.Duration(handshakeTimeout) * time.Second}
client.httpClient = &http.Client{Transport: t}
}
client.setEndpointByLocation(client.regionID, client.serviceCode, client.AccessKeyId, client.AccessKeySecret, client.securityToken)
return client
}
@ -95,9 +93,17 @@ func (client *Client) NewInitForAssumeRole(endpoint, version, accessKeyId, acces
client.securityToken = securityToken
}
//getLocationEndpoint
func (client *Client) getEndpointByLocation() string {
locationClient := NewLocationClient(client.AccessKeyId, client.AccessKeySecret, client.securityToken)
locationClient.SetDebug(true)
return locationClient.DescribeOpenAPIEndpoint(client.regionID, client.serviceCode)
}
//NewClient using location service
func (client *Client) setEndpointByLocation(region Region, serviceCode, accessKeyId, accessKeySecret, securityToken string) {
locationClient := NewLocationClient(accessKeyId, accessKeySecret, securityToken)
locationClient.SetDebug(true)
ep := locationClient.DescribeOpenAPIEndpoint(region, serviceCode)
if ep == "" {
ep = loadEndpointFromFile(region, serviceCode)
@ -251,12 +257,34 @@ func (client *Client) SetSecurityToken(securityToken string) {
client.securityToken = securityToken
}
func (client *Client) initEndpoint() error {
// if set any value to "CUSTOMIZED_ENDPOINT" could skip location service.
// example: export CUSTOMIZED_ENDPOINT=true
if os.Getenv("CUSTOMIZED_ENDPOINT") != "" {
return nil
}
if client.serviceCode != "" && client.regionID != "" {
endpoint := client.getEndpointByLocation()
if endpoint == "" {
return GetCustomError("InvalidEndpoint", "endpoint is empty,pls check")
}
client.endpoint = endpoint
}
return nil
}
// Invoke sends the raw HTTP request for ECS services
func (client *Client) Invoke(action string, args interface{}, response interface{}) error {
if err := client.ensureProperties(); err != nil {
return err
}
//init endpoint
if err := client.initEndpoint(); err != nil {
return err
}
request := Request{}
request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)
@ -330,6 +358,11 @@ func (client *Client) InvokeByFlattenMethod(action string, args interface{}, res
return err
}
//init endpoint
if err := client.initEndpoint(); err != nil {
return err
}
request := Request{}
request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)
@ -406,6 +439,11 @@ func (client *Client) InvokeByAnyMethod(method, action, path string, args interf
return err
}
//init endpoint
if err := client.initEndpoint(); err != nil {
return err
}
request := Request{}
request.init(client.version, action, client.AccessKeyId, client.securityToken, client.regionID)
data := util.ConvertToQueryValues(request)
@ -500,3 +538,13 @@ func GetClientErrorFromString(str string) error {
func GetClientError(err error) error {
return GetClientErrorFromString(err.Error())
}
func GetCustomError(code, message string) error {
return &Error{
ErrorResponse: ErrorResponse{
Code: code,
Message: message,
},
StatusCode: 400,
}
}

View File

@ -4,8 +4,10 @@ import (
"encoding/xml"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"time"
)
const (
@ -50,6 +52,12 @@ var (
"rds": "https://rds.eu-central-1.aliyuncs.com",
"vpc": "https://vpc.eu-central-1.aliyuncs.com",
},
EUWest1: {
"ecs": "https://ecs.eu-west-1.aliyuncs.com",
"slb": "https://slb.eu-west-1.aliyuncs.com",
"rds": "https://rds.eu-west-1.aliyuncs.com",
"vpc": "https://vpc.eu-west-1.aliyuncs.com",
},
Zhangjiakou: {
"ecs": "https://ecs.cn-zhangjiakou.aliyuncs.com",
"slb": "https://slb.cn-zhangjiakou.aliyuncs.com",
@ -140,7 +148,6 @@ func (client *LocationClient) DescribeOpenAPIEndpoint(region Region, serviceCode
if endpoint := getProductRegionEndpoint(region, serviceCode); endpoint != "" {
return endpoint
}
defaultProtocols := HTTP_PROTOCOL
args := &DescribeEndpointsArgs{
@ -149,8 +156,18 @@ func (client *LocationClient) DescribeOpenAPIEndpoint(region Region, serviceCode
Type: "openAPI",
}
endpoint, err := client.DescribeEndpoints(args)
if err != nil || len(endpoint.Endpoints.Endpoint) <= 0 {
var endpoint *DescribeEndpointsResponse
var err error
for index := 0; index < 5; index++ {
endpoint, err = client.DescribeEndpoints(args)
if err == nil && endpoint != nil && len(endpoint.Endpoints.Endpoint) > 0 {
break
}
time.Sleep(500 * time.Millisecond)
}
if err != nil || endpoint == nil || len(endpoint.Endpoints.Endpoint) <= 0 {
log.Printf("aliyungo: can not get endpoint from service, use default. endpoint=[%v], error=[%v]\n", endpoint, err)
return ""
}
@ -163,7 +180,7 @@ func (client *LocationClient) DescribeOpenAPIEndpoint(region Region, serviceCode
ep := fmt.Sprintf("%s://%s", defaultProtocols, endpoint.Endpoints.Endpoint[0].Endpoint)
//setProductRegionEndpoint(region, serviceCode, ep)
setProductRegionEndpoint(region, serviceCode, ep)
return ep
}

View File

@ -1336,6 +1336,17 @@
<Product><ProductName>Slb</ProductName><DomainName>slb.eu-central-1.aliyuncs.com</DomainName></Product>
</Products>
</Endpoint>
<Endpoint name="eu-west-1">
<RegionIds><RegionId>eu-west-1</RegionId></RegionIds>
<Products>
<Product><ProductName>Rds</ProductName><DomainName>rds.eu-west-1.aliyuncs.com</DomainName></Product>
<Product><ProductName>Ecs</ProductName><DomainName>ecs.eu-west-1.aliyuncs.com</DomainName></Product>
<Product><ProductName>Vpc</ProductName><DomainName>vpc.eu-west-1.aliyuncs.com</DomainName></Product>
<Product><ProductName>Kms</ProductName><DomainName>kms.eu-west-1.aliyuncs.com</DomainName></Product>
<Product><ProductName>Cms</ProductName><DomainName>metrics.cn-hangzhou.aliyuncs.com</DomainName></Product>
<Product><ProductName>Slb</ProductName><DomainName>slb.eu-west-1.aliyuncs.com</DomainName></Product>
</Products>
</Endpoint>
<Endpoint name="cn-zhangjiakou">
<RegionIds><RegionId>cn-zhangjiakou</RegionId></RegionIds>
<Products>

View File

@ -28,6 +28,7 @@ const (
MEEast1 = Region("me-east-1")
EUCentral1 = Region("eu-central-1")
EUWest1 = Region("eu-west-1")
ShenZhenFinance = Region("cn-shenzhen-finance-1")
ShanghaiFinance = Region("cn-shanghai-finance-1")
@ -39,6 +40,16 @@ var ValidRegions = []Region{
APNorthEast1, APSouthEast1, APSouthEast2, APSouthEast3, APSouthEast5,
APSouth1,
MEEast1,
EUCentral1,
EUCentral1, EUWest1,
ShenZhenFinance, ShanghaiFinance,
}
// IsValidRegion checks if r is an Ali supported region.
func IsValidRegion(r string) bool {
for _, v := range ValidRegions {
if r == string(v) {
return true
}
}
return false
}

View File

@ -113,3 +113,12 @@ func NewVPCClientWithEndpointAndSecurityToken(endpoint string, accessKeyId strin
InitClient()
return client
}
// ---------------------------------------
// NewVPCClientWithRegion creates a new instance of VPC client automatically get endpoint
// ---------------------------------------
func NewVPCClientWithRegion(endpoint string, accessKeyId string, accessKeySecret string, regionID common.Region) *Client {
client := &Client{}
client.NewInit(endpoint, VPCAPIVersion, accessKeyId, accessKeySecret, VPCServiceCode, regionID)
return client
}

View File

@ -59,7 +59,7 @@ type DescribeDisksArgs struct {
Category DiskCategory //enum for all(default) | cloud | ephemeral
Status DiskStatus //enum for In_use | Available | Attaching | Detaching | Creating | ReIniting | All(default)
SnapshotId string
Name string
DiskName string
Portable *bool //optional
DeleteWithInstance *bool //optional
DeleteAutoSnapshot *bool //optional
@ -78,6 +78,7 @@ type DiskItemType struct {
DiskName string
Description string
Type DiskType
Encrypted bool
Category DiskCategory
Size int
ImageId string
@ -242,7 +243,7 @@ func (client *Client) DetachDisk(instanceId string, diskId string) error {
}
type ResizeDiskArgs struct {
DiskId string
DiskId string
NewSize int
}
@ -255,15 +256,14 @@ type ResizeDiskResponse struct {
// You can read doc at https://help.aliyun.com/document_detail/25522.html
func (client *Client) ResizeDisk(diskId string, sizeGB int) error {
args := ResizeDiskArgs{
DiskId:diskId,
NewSize:sizeGB,
DiskId: diskId,
NewSize: sizeGB,
}
response := ResizeDiskResponse{}
err := client.Invoke("ResizeDisk", &args, &response)
return err
}
type ResetDiskArgs struct {
DiskId string
SnapshotId string
@ -273,7 +273,6 @@ type ResetDiskResponse struct {
common.Response
}
// ResetDisk resets disk to original status
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/disk&resetdisk

183
vendor/github.com/denverdino/aliyungo/ecs/eni.go generated vendored Normal file
View File

@ -0,0 +1,183 @@
package ecs
import (
"fmt"
"time"
"github.com/denverdino/aliyungo/common"
)
type CreateNetworkInterfaceArgs struct {
RegionId common.Region
VSwitchId string
PrimaryIpAddress string // optional
SecurityGroupId string
NetworkInterfaceName string // optional
Description string // optional
ClientToken string // optional
}
type CreateNetworkInterfaceResponse struct {
common.Response
NetworkInterfaceId string
}
type DeleteNetworkInterfaceArgs struct {
RegionId common.Region
NetworkInterfaceId string
}
type DeleteNetworkInterfaceResponse struct {
common.Response
}
type DescribeNetworkInterfacesArgs struct {
RegionId common.Region
VSwitchId string
PrimaryIpAddress string
SecurityGroupId string
NetworkInterfaceName string
Type string
InstanceId string
NetworkInterfaceId []string `query:"list"`
PageNumber int
PageSize int
}
type NetworkInterfaceType struct {
NetworkInterfaceId string
NetworkInterfaceName string
PrimaryIpAddress string
MacAddress string
Status string
PrivateIpAddress string
}
type DescribeNetworkInterfacesResponse struct {
common.Response
NetworkInterfaceSets struct {
NetworkInterfaceSet []NetworkInterfaceType
}
TotalCount int
PageNumber int
PageSize int
}
type AttachNetworkInterfaceArgs struct {
RegionId common.Region
NetworkInterfaceId string
InstanceId string
}
type AttachNetworkInterfaceResponse common.Response
type DetachNetworkInterfaceArgs AttachNetworkInterfaceArgs
type DetachNetworkInterfaceResponse common.Response
type ModifyNetworkInterfaceAttributeArgs struct {
RegionId common.Region
NetworkInterfaceId string
SecurityGroupId []string
NetworkInterfaceName string
Description string
}
type ModifyNetworkInterfaceAttributeResponse common.Response
type UnassignPrivateIpAddressesArgs struct {
RegionId common.Region
NetworkInterfaceId string
PrivateIpAddress []string `query:"list"`
}
type UnassignPrivateIpAddressesResponse common.Response
type AssignPrivateIpAddressesArgs struct {
RegionId common.Region
NetworkInterfaceId string
PrivateIpAddress []string `query:"list"` // optional
SecondaryPrivateIpAddressCount int // optional
}
type AssignPrivateIpAddressesResponse common.Response
func (client *Client) CreateNetworkInterface(args *CreateNetworkInterfaceArgs) (resp *CreateNetworkInterfaceResponse, err error) {
resp = &CreateNetworkInterfaceResponse{}
err = client.Invoke("CreateNetworkInterface", args, resp)
return resp, err
}
func (client *Client) DeleteNetworkInterface(args *DeleteNetworkInterfaceArgs) (resp *DeleteNetworkInterfaceResponse, err error) {
resp = &DeleteNetworkInterfaceResponse{}
err = client.Invoke("DeleteNetworkInterface", args, resp)
return resp, err
}
func (client *Client) DescribeNetworkInterfaces(args *DescribeNetworkInterfacesArgs) (resp *DescribeNetworkInterfacesResponse, err error) {
resp = &DescribeNetworkInterfacesResponse{}
err = client.Invoke("DescribeNetworkInterfaces", args, resp)
return resp, err
}
func (client *Client) AttachNetworkInterface(args *AttachNetworkInterfaceArgs) error {
resp := &AttachNetworkInterfaceResponse{}
err := client.Invoke("AttachNetworkInterface", args, resp)
return err
}
func (client *Client) DetachNetworkInterface(args *DetachNetworkInterfaceArgs) (resp *DetachNetworkInterfaceResponse, err error) {
resp = &DetachNetworkInterfaceResponse{}
err = client.Invoke("DetachNetworkInterface", args, resp)
return resp, err
}
func (client *Client) ModifyNetworkInterfaceAttribute(args *ModifyNetworkInterfaceAttributeArgs) (resp *ModifyNetworkInterfaceAttributeResponse, err error) {
resp = &ModifyNetworkInterfaceAttributeResponse{}
err = client.Invoke("ModifyNetworkInterfaceAttribute", args, resp)
return resp, err
}
func (client *Client) UnassignPrivateIpAddresses(args *UnassignPrivateIpAddressesArgs) (resp *UnassignPrivateIpAddressesResponse, err error) {
resp = &UnassignPrivateIpAddressesResponse{}
err = client.Invoke("UnassignPrivateIpAddresses", args, resp)
return resp, err
}
func (client *Client) AssignPrivateIpAddresses(args *AssignPrivateIpAddressesArgs) (resp *AssignPrivateIpAddressesResponse, err error) {
resp = &AssignPrivateIpAddressesResponse{}
err = client.Invoke("AssignPrivateIpAddresses", args, resp)
return resp, err
}
// Default timeout value for WaitForInstance method
const NetworkInterfacesDefaultTimeout = 120
// WaitForInstance waits for instance to given status
func (client *Client) WaitForNetworkInterface(regionId common.Region, eniID string, status string, timeout int) error {
if timeout <= 0 {
timeout = NetworkInterfacesDefaultTimeout
}
for {
eniIds := []string{eniID}
describeNetworkInterfacesArgs := DescribeNetworkInterfacesArgs{
RegionId: regionId,
NetworkInterfaceId: eniIds,
}
nisResponse, err := client.DescribeNetworkInterfaces(&describeNetworkInterfacesArgs)
if err != nil {
return fmt.Errorf("Failed to describe network interface %v: %v", eniID, err)
}
if len(nisResponse.NetworkInterfaceSets.NetworkInterfaceSet) > 0 && nisResponse.NetworkInterfaceSets.NetworkInterfaceSet[0].Status == status {
break
}
timeout = timeout - DefaultWaitForInterval
if timeout <= 0 {
return fmt.Errorf("Timeout for waiting available status for network interfaces")
}
time.Sleep(DefaultWaitForInterval * time.Second)
}
return nil
}

View File

@ -37,6 +37,13 @@ const (
ImageUsageNone = ImageUsage("none")
)
type ImageFormatType string
const (
RAW = ImageFormatType("RAW")
VHD = ImageFormatType("VHD")
)
// DescribeImagesArgs repsents arguments to describe images
type DescribeImagesArgs struct {
RegionId common.Region
@ -63,8 +70,10 @@ type DescribeImagesResponse struct {
type DiskDeviceMapping struct {
SnapshotId string
//Why Size Field is string-type.
Size string
Device string
Size string
// Now the key Size change to DiskImageSize
DiskImageSize string
Device string
//For import images
Format string
OSSBucket string
@ -151,6 +160,7 @@ func (client *Client) CreateImage(args *CreateImageArgs) (imageId string, err er
type DeleteImageArgs struct {
RegionId common.Region
ImageId string
Force bool
}
type DeleteImageResponse struct {
@ -170,6 +180,20 @@ func (client *Client) DeleteImage(regionId common.Region, imageId string) error
return client.Invoke("DeleteImage", &args, &response)
}
// DeleteImage deletes Image
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/image&deleteimage
func (client *Client) DeleteImageWithForce(regionId common.Region, imageId string, force bool) error {
args := DeleteImageArgs{
RegionId: regionId,
ImageId: imageId,
Force: force,
}
response := &DeleteImageResponse{}
return client.Invoke("DeleteImage", &args, &response)
}
// ModifyImageSharePermission repsents arguments to share image
type ModifyImageSharePermissionArgs struct {
RegionId common.Region

View File

@ -9,10 +9,19 @@ type DescribeInstanceTypesArgs struct {
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instancetypeitemtype
type InstanceTypeItemType struct {
InstanceTypeId string
CpuCoreCount int
MemorySize float64
InstanceTypeFamily string
InstanceTypeId string
CpuCoreCount int
MemorySize float64
InstanceTypeFamily string
GPUAmount int
GPUSpec string
InitialCredit int
BaselineCredit int
EniQuantity int
EniPrivateIpAddressQuantity int
LocalStorageCapacity int
LocalStorageAmount int
LocalStorageCategory string
}
type DescribeInstanceTypesResponse struct {

View File

@ -245,7 +245,7 @@ type InstanceAttributesType struct {
SerialNumber string
Status InstanceStatus
OperationLocks OperationLocksType
SecurityGroupIds struct {
SecurityGroupIds struct {
SecurityGroupId []string
}
PublicIpAddress IpAddressSetType
@ -260,7 +260,7 @@ type InstanceAttributesType struct {
IoOptimized StringOrBool
InstanceChargeType common.InstanceChargeType
ExpiredTime util.ISO6801Time
Tags struct {
Tags struct {
Tag []TagItemType
}
SpotStrategy SpotStrategyType
@ -440,6 +440,28 @@ func (client *Client) DescribeInstancesWithRaw(args *DescribeInstancesArgs) (res
return response, nil
}
type ModifyInstanceAutoReleaseTimeArgs struct {
InstanceId string
AutoReleaseTime string
}
type ModifyInstanceAutoReleaseTimeResponse struct {
common.Response
}
// 对给定的实例设定自动释放时间。
//
// You can read doc at https://help.aliyun.com/document_detail/47576.html
func (client *Client) ModifyInstanceAutoReleaseTime(instanceId, time string) error {
args := ModifyInstanceAutoReleaseTimeArgs{
InstanceId: instanceId,
AutoReleaseTime: time,
}
response := ModifyInstanceAutoReleaseTimeResponse{}
err := client.Invoke("ModifyInstanceAutoReleaseTime", &args, &response)
return err
}
type DeleteInstanceArgs struct {
InstanceId string
}
@ -512,34 +534,43 @@ var (
IoOptimizedOptimized = IoOptimized("optimized")
)
type SecurityEnhancementStrategy string
var (
InactiveSecurityEnhancementStrategy = SecurityEnhancementStrategy("Active")
DeactiveSecurityEnhancementStrategy = SecurityEnhancementStrategy("Deactive")
)
type CreateInstanceArgs struct {
RegionId common.Region
ZoneId string
ImageId string
InstanceType string
SecurityGroupId string
InstanceName string
Description string
InternetChargeType common.InternetChargeType
InternetMaxBandwidthIn int
InternetMaxBandwidthOut int
HostName string
Password string
IoOptimized IoOptimized
SystemDisk SystemDiskType
DataDisk []DataDiskType
VSwitchId string
PrivateIpAddress string
ClientToken string
InstanceChargeType common.InstanceChargeType
Period int
UserData string
AutoRenew bool
AutoRenewPeriod int
SpotStrategy SpotStrategyType
SpotPriceLimit float64
KeyPairName string
RamRoleName string
RegionId common.Region
ZoneId string
ImageId string
InstanceType string
SecurityGroupId string
InstanceName string
Description string
InternetChargeType common.InternetChargeType
InternetMaxBandwidthIn int
InternetMaxBandwidthOut int
HostName string
Password string
IoOptimized IoOptimized
SystemDisk SystemDiskType
DataDisk []DataDiskType
VSwitchId string
PrivateIpAddress string
ClientToken string
InstanceChargeType common.InstanceChargeType
Period int
PeriodUnit common.TimeType
UserData string
AutoRenew bool
AutoRenewPeriod int
SpotStrategy SpotStrategyType
SpotPriceLimit float64
KeyPairName string
RamRoleName string
SecurityEnhancementStrategy SecurityEnhancementStrategy
}
type CreateInstanceResponse struct {
@ -682,3 +713,120 @@ func (client *Client) DescribeInstanceRamRole(args *AttachInstancesArgs) (resp *
}
return response, nil
}
type ModifyInstanceSpecArgs struct {
InstanceId string
InstanceType string
InternetMaxBandwidthOut *int
InternetMaxBandwidthIn *int
ClientToken string
}
type ModifyInstanceSpecResponse struct {
common.Response
}
//ModifyInstanceSpec modify instance specification
//
// Notice: 1. An instance that was successfully modified once cannot be modified again within 5 minutes.
// 2. The API only can be used Pay-As-You-Go (PostPaid) instance
//
// You can read doc at https://www.alibabacloud.com/help/doc-detail/57633.htm
func (client *Client) ModifyInstanceSpec(args *ModifyInstanceSpecArgs) error {
response := ModifyInstanceSpecResponse{}
return client.Invoke("ModifyInstanceSpec", args, &response)
}
type ModifyInstanceVpcAttributeArgs struct {
InstanceId string
VSwitchId string
PrivateIpAddress string
}
type ModifyInstanceVpcAttributeResponse struct {
common.Response
}
//ModifyInstanceVpcAttribute modify instance vswitchID and private ip address
//
// You can read doc at https://www.alibabacloud.com/help/doc-detail/25504.htm
func (client *Client) ModifyInstanceVpcAttribute(args *ModifyInstanceVpcAttributeArgs) error {
response := ModifyInstanceVpcAttributeResponse{}
return client.Invoke("ModifyInstanceVpcAttribute", args, &response)
}
type ModifyInstanceChargeTypeArgs struct {
InstanceIds string
RegionId common.Region
Period int
PeriodUnit common.TimeType
IncludeDataDisks bool
DryRun bool
AutoPay bool
ClientToken string
}
type ModifyInstanceChargeTypeResponse struct {
common.Response
Order string
}
//ModifyInstanceChargeType modify instance charge type
//
// You can read doc at https://www.alibabacloud.com/help/doc-detail/25504.htm
func (client *Client) ModifyInstanceChargeType(args *ModifyInstanceChargeTypeArgs) (*ModifyInstanceChargeTypeResponse, error) {
response := &ModifyInstanceChargeTypeResponse{}
if err := client.Invoke("ModifyInstanceChargeType", args, response); err != nil {
return response, err
}
return response, nil
}
type RenewalStatus string
const (
RenewAutoRenewal = RenewalStatus("AutoRenewal")
RenewNormal = RenewalStatus("Normal")
RenewNotRenewal = RenewalStatus("NotRenewal")
)
type ModifyInstanceAutoRenewAttributeArgs struct {
InstanceId string
RegionId common.Region
Duration int
AutoRenew bool
RenewalStatus RenewalStatus
}
// You can read doc at https://www.alibabacloud.com/help/doc-detail/52843.htm
func (client *Client) ModifyInstanceAutoRenewAttribute(args *ModifyInstanceAutoRenewAttributeArgs) error {
response := &common.Response{}
return client.Invoke("ModifyInstanceAutoRenewAttribute", args, response)
}
type DescribeInstanceAutoRenewAttributeArgs struct {
InstanceId string
RegionId common.Region
}
type InstanceRenewAttribute struct {
InstanceId string
Duration int
AutoRenewEnabled bool
PeriodUnit string
RenewalStatus RenewalStatus
}
type DescribeInstanceAutoRenewAttributeResponse struct {
common.Response
InstanceRenewAttributes struct {
InstanceRenewAttribute []InstanceRenewAttribute
}
}
// You can read doc at https://www.alibabacloud.com/help/doc-detail/52844.htm
func (client *Client) DescribeInstanceAutoRenewAttribute(args *DescribeInstanceAutoRenewAttributeArgs) (*DescribeInstanceAutoRenewAttributeResponse, error) {
response := &DescribeInstanceAutoRenewAttributeResponse{}
err := client.Invoke("DescribeInstanceAutoRenewAttribute", args, response)
return response, err
}

View File

@ -28,6 +28,16 @@ type SnatTableIdType struct {
SnatTableId []string
}
type IpListsType struct {
IpList []IpListItem
}
type IpListItem struct {
IpAddress string
AllocationId string
UsingStatus string
}
type BandwidthPackageIdType struct {
BandwidthPackageId []string
}
@ -57,6 +67,7 @@ type NatGatewaySetType struct {
BandwidthPackageIds BandwidthPackageIdType
ForwardTableIds ForwardTableIdType
SnatTableIds SnatTableIdType
IpLists IpListsType
InstanceChargeType string
Name string
NatGatewayId string
@ -147,7 +158,8 @@ func (client *Client) DeleteNatGateway(args *DeleteNatGatewayArgs) error {
}
type DescribeBandwidthPackagesArgs struct {
RegionId common.Region
RegionId common.Region
common.Pagination
BandwidthPackageId string
NatGatewayId string
}
@ -170,12 +182,13 @@ type DescribeBandwidthPackageType struct {
type DescribeBandwidthPackagesResponse struct {
common.Response
common.PaginationResult
BandwidthPackages struct {
BandwidthPackage []DescribeBandwidthPackageType
}
}
func (client *Client) DescribeBandwidthPackages(args *DescribeBandwidthPackagesArgs) ([]DescribeBandwidthPackageType, error) {
func (client *Client) DescribeBandwidthPackages(args *DescribeBandwidthPackagesArgs) (*DescribeBandwidthPackagesResponse, error) {
response := &DescribeBandwidthPackagesResponse{}
err := client.Invoke("DescribeBandwidthPackages", args, response)
@ -183,7 +196,7 @@ func (client *Client) DescribeBandwidthPackages(args *DescribeBandwidthPackagesA
return nil, err
}
return response.BandwidthPackages.BandwidthPackage, err
return response, err
}
type DeleteBandwidthPackageArgs struct {

View File

@ -36,8 +36,9 @@ func (client *Client) AllocatePublicIpAddress(instanceId string) (ipAddress stri
type ModifyInstanceNetworkSpec struct {
InstanceId string
InternetMaxBandwidthOut int
InternetMaxBandwidthIn int
InternetMaxBandwidthOut *int
InternetMaxBandwidthIn *int
NetworkChargeType common.InternetChargeType
}
type ModifyInstanceNetworkSpecResponse struct {
@ -57,6 +58,7 @@ type AllocateEipAddressArgs struct {
RegionId common.Region
Bandwidth int
InternetChargeType common.InternetChargeType
ISP string
ClientToken string
}
@ -81,9 +83,19 @@ func (client *Client) AllocateEipAddress(args *AllocateEipAddressArgs) (EipAddre
return response.EipAddress, response.AllocationId, nil
}
type EipInstanceType string
const (
EcsInstance = "EcsInstance"
SlbInstance = "SlbInstance"
Nat = "Nat"
HaVip = "HaVip"
)
type AssociateEipAddressArgs struct {
AllocationId string
InstanceId string
InstanceType EipInstanceType
}
type AssociateEipAddressResponse struct {
@ -102,6 +114,11 @@ func (client *Client) AssociateEipAddress(allocationId string, instanceId string
return client.Invoke("AssociateEipAddress", &args, &response)
}
func (client *Client) NewAssociateEipAddress(args *AssociateEipAddressArgs) error {
response := ModifyInstanceNetworkSpecResponse{}
return client.Invoke("AssociateEipAddress", args, &response)
}
// Status of disks
type EipStatus string
@ -112,11 +129,22 @@ const (
EipStatusAvailable = EipStatus("Available")
)
type AssociatedInstanceType string
const (
AssociatedInstanceTypeEcsInstance = AssociatedInstanceType("EcsInstance")
AssociatedInstanceTypeSlbInstance = AssociatedInstanceType("SlbInstance")
AssociatedInstanceTypeNat = AssociatedInstanceType("Nat")
AssociatedInstanceTypeHaVip = AssociatedInstanceType("HaVip")
)
type DescribeEipAddressesArgs struct {
RegionId common.Region
Status EipStatus //enum Associating | Unassociating | InUse | Available
EipAddress string
AllocationId string
RegionId common.Region
Status EipStatus //enum Associating | Unassociating | InUse | Available
EipAddress string
AllocationId string
AssociatedInstanceType AssociatedInstanceType //enum EcsInstance | SlbInstance | Nat | HaVip
AssociatedInstanceId string //绑定的资源的Id。 这是一个过滤器性质的参数,若不指定,则表示不适用该条件对结果进行过滤。 如果要使用该过滤器必须同时使用AssociatedInstanceType。若InstanceType为EcsInstance则此处填写ECS实例Id。若InstanceType为SlbInstance则此处填写VPC类型的私网SLB 的实例ID。若InstanceType为Nat则此处填写NAT 的实例ID。。若InstanceType为HaVip则此处填写HaVipId。
common.Pagination
}
@ -128,6 +156,7 @@ type EipAddressSetType struct {
AllocationId string
Status EipStatus
InstanceId string
InstanceType string
Bandwidth string // Why string
InternetChargeType common.InternetChargeType
OperationLocks OperationLocksType

View File

@ -100,8 +100,8 @@ func (client *Client) DescribeRouteTablesWithRaw(args *DescribeRouteTablesArgs)
type NextHopType string
const (
NextHopIntance = NextHopType("Instance") //Default
NextHopTunnel = NextHopType("Tunnel")
NextHopIntance = NextHopType("Instance") //Default
NextHopTunnel = NextHopType("Tunnel")
NextHopTunnelRouterInterface = NextHopType("RouterInterface")
)

View File

@ -1,6 +1,8 @@
package ecs
import (
"time"
"github.com/denverdino/aliyungo/common"
)
@ -19,6 +21,8 @@ const (
Idl = InterfaceStatus("Idl")
Active = InterfaceStatus("Active")
Inactive = InterfaceStatus("Inactive")
// 'Idle' means the router interface is not connected. 'Idl' may be a incorrect status.
Idle = InterfaceStatus("Idle")
InitiatingSide = Role("InitiatingSide")
AcceptingSide = Role("AcceptingSide")
@ -77,7 +81,7 @@ type Filter struct {
type DescribeRouterInterfacesArgs struct {
RegionId common.Region
common.Pagination
Filter []Filter
Filter []Filter
}
type RouterInterfaceItemType struct {
@ -225,3 +229,29 @@ func (client *Client) DeleteRouterInterface(args *OperateRouterInterfaceArgs) (r
}
return response, nil
}
// WaitForRouterInterface waits for router interface to given status
func (client *Client) WaitForRouterInterfaceAsyn(regionId common.Region, interfaceId string, status InterfaceStatus, timeout int) error {
if timeout <= 0 {
timeout = InstanceDefaultTimeout
}
for {
interfaces, err := client.DescribeRouterInterfaces(&DescribeRouterInterfacesArgs{
RegionId: regionId,
Filter: []Filter{Filter{Key: "RouterInterfaceId", Value: []string{interfaceId}}},
})
if err != nil {
return err
} else if interfaces != nil && InterfaceStatus(interfaces.RouterInterfaceSet.RouterInterfaceType[0].Status) == status {
//TODO
break
}
timeout = timeout - DefaultWaitForInterval
if timeout <= 0 {
return common.GetClientErrorFromString("Timeout")
}
time.Sleep(DefaultWaitForInterval * time.Second)
}
return nil
}

View File

@ -6,10 +6,15 @@ import (
)
type NicType string
type Direction string
const (
NicTypeInternet = NicType("internet")
NicTypeIntranet = NicType("intranet")
DirectionIngress = Direction("ingress")
DirectionEgress = Direction("egress")
DirectionAll = Direction("all")
)
type IpProtocol string
@ -29,11 +34,18 @@ const (
PermissionPolicyDrop = PermissionPolicy("drop")
)
type GroupInnerAccessPolicy string
const (
GroupInnerAccept = GroupInnerAccessPolicy("Accept")
GroupInnerDrop = GroupInnerAccessPolicy("Drop")
)
type DescribeSecurityGroupAttributeArgs struct {
SecurityGroupId string
RegionId common.Region
NicType NicType //enum for internet (default) |intranet
Direction string // enum ingress egress
NicType NicType //enum for internet (default) |intranet
Direction Direction // enum ingress egress
}
//
@ -64,7 +76,8 @@ type DescribeSecurityGroupAttributeResponse struct {
Permissions struct {
Permission []PermissionType
}
VpcId string
VpcId string
InnerAccessPolicy GroupInnerAccessPolicy
}
//
@ -197,6 +210,21 @@ func (client *Client) ModifySecurityGroupAttribute(args *ModifySecurityGroupAttr
return err
}
type ModifySecurityGroupPolicyArgs struct {
RegionId common.Region
SecurityGroupId string
InnerAccessPolicy GroupInnerAccessPolicy
}
// ModifySecurityGroupPolicy modifies inner access policy of security group
//
// You can read doc at https://www.alibabacloud.com/help/doc-detail/57315.htm
func (client *Client) ModifySecurityGroupPolicy(args *ModifySecurityGroupPolicyArgs) error {
response := common.Response{}
err := client.Invoke("ModifySecurityGroupPolicy", args, &response)
return err
}
type AuthorizeSecurityGroupArgs struct {
SecurityGroupId string
RegionId common.Region

Some files were not shown because too many files have changed in this diff Show More