Get plugin building and mostly working
This commit is contained in:
parent
aff02b798a
commit
1221794f0a
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
||||
*~
|
||||
bin
|
||||
pkg
|
||||
crash.log
|
||||
packer_cache/*
|
||||
|
202
Godeps/Godeps.json
generated
202
Godeps/Godeps.json
generated
@ -1,202 +0,0 @@
|
||||
{
|
||||
"ImportPath": "github.com/xenserver/packer-builder-xenserver",
|
||||
"GoVersion": "go1.6",
|
||||
"GodepVersion": "v74",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/Sirupsen/logrus",
|
||||
"Comment": "v0.10.0-19-gf3cfb45",
|
||||
"Rev": "f3cfb454f4c209e6668c95216c4744b8fddb2356"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/dylanmei/iso8601",
|
||||
"Comment": "v0.1.0",
|
||||
"Rev": "2075bf119b58e5576c6ed9f867b8f3d17f2e54d4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/dylanmei/winrmtest",
|
||||
"Rev": "025617847eb2cf9bd1d851bc3b22ed28e6245ce5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/errwrap",
|
||||
"Rev": "7554cd9344cec97297fa6649b055a8c98c2a1e55"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-multierror",
|
||||
"Rev": "d30f09973e19c1dfcd120b2d9c4f168e68d6b5d5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/go-version",
|
||||
"Rev": "7e3c02b30806fa5779d3bdfc152ce4c6f40e7b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/hashicorp/yamux",
|
||||
"Rev": "df949784da9ed028ee76df44652e42d37a09d7e4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/kr/fs",
|
||||
"Rev": "2788f0dbd16903de03cb8186e5c7d97b69ad387b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/masterzen/simplexml/dom",
|
||||
"Rev": "95ba30457eb1121fa27753627c774c7cd4e90083"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/masterzen/winrm/soap",
|
||||
"Rev": "54ea5d01478cfc2afccec1504bd0dfcd8c260cfa"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/masterzen/winrm/winrm",
|
||||
"Rev": "54ea5d01478cfc2afccec1504bd0dfcd8c260cfa"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/masterzen/xmlpath",
|
||||
"Rev": "13f4951698adc0fa9c1dda3e275d489a24201161"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/go-fs",
|
||||
"Rev": "a34c1b9334e86165685a9449b782f20465eb8c69"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/go-fs/fat",
|
||||
"Rev": "a34c1b9334e86165685a9449b782f20465eb8c69"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/iochan",
|
||||
"Rev": "87b45ffd0e9581375c491fef3d32130bb15c5bd7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/mapstructure",
|
||||
"Rev": "281073eb9eb092240d33ef253c404f1cca550309"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/multistep",
|
||||
"Rev": "162146fc57112954184d90266f4733e900ed05a5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/osext",
|
||||
"Rev": "5e2d6d41470f99c881826dedd8c526728b783c9c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/common",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/common/ssh",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/common/uuid",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/communicator/none",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/communicator/ssh",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/communicator/winrm",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/helper/communicator",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/helper/config",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/packer",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/packer/plugin",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/packer/rpc",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/template",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/packer/template/interpolate",
|
||||
"Comment": "v0.10.1-135-g63edbd4",
|
||||
"Rev": "63edbd40edc5a55394f8532aa9958bbe257b31b5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mitchellh/reflectwalk",
|
||||
"Rev": "eecf4c70c626c7cfbb95c90195bc34d386c74ac6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/nilshell/xmlrpc",
|
||||
"Rev": "41b9444050f7a0494a44cd5644f5048aa8261b17"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/nu7hatch/gouuid",
|
||||
"Rev": "179d4d0c4d8d407a32af483c2354df1d2c91e6c3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/packer-community/winrmcp/winrmcp",
|
||||
"Rev": "f1bcf36a69fa2945e65dd099eee11b560fbd3346"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pkg/sftp",
|
||||
"Rev": "e84cc8c755ca39b7b64f510fe1fffc1b51f210a5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/satori/go.uuid",
|
||||
"Rev": "d41af8bb6a7704f00bc3b7cba9355ae6a5a80048"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/svanharmelen/gocs",
|
||||
"Comment": "v1.0.0-4-ga53656b",
|
||||
"Rev": "a53656b67c7b6db48362e3b4edb5e335a7162bf0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ugorji/go/codec",
|
||||
"Rev": "646ae4a518c1c3be0739df898118d9bccf993858"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/xenserver/go-xenserver-client",
|
||||
"Rev": "42dc9035c2e805b844614741d804f308bacb7490"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||
"Rev": "1f22c0103821b9390939b6776727195525381532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ssh",
|
||||
"Rev": "1f22c0103821b9390939b6776727195525381532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ssh/agent",
|
||||
"Rev": "1f22c0103821b9390939b6776727195525381532"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "50c6bc5e4292a1d4e65c6e9be5f53be28bcbe28e"
|
||||
}
|
||||
]
|
||||
}
|
5
Godeps/Readme
generated
5
Godeps/Readme
generated
@ -1,5 +0,0 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
4
build.sh
4
build.sh
@ -12,10 +12,10 @@ GOPATH=${GOPATH:-$(go env GOPATH)}
|
||||
echo "==> Removing old directory..."
|
||||
rm -f bin/*
|
||||
rm -rf pkg/*
|
||||
rm -rf $GOPATH/pkg/*
|
||||
# rm -rf $GOPATH/pkg/*
|
||||
mkdir -p bin/
|
||||
|
||||
gox \
|
||||
~/go/bin/gox \
|
||||
-os="${XC_OS}" \
|
||||
-arch="${XC_ARCH}" \
|
||||
-output "pkg/{{.OS}}_{{.Arch}}/packer-{{.Dir}}" \
|
||||
|
BIN
builder-xenserver-iso
Executable file
BIN
builder-xenserver-iso
Executable file
Binary file not shown.
BIN
builder-xenserver-xva
Executable file
BIN
builder-xenserver-xva
Executable file
Binary file not shown.
@ -4,9 +4,10 @@ import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/nilshell/xmlrpc"
|
||||
"log"
|
||||
"regexp"
|
||||
|
||||
xmlrpc "github.com/amfranz/go-xmlrpc-client"
|
||||
xenapi "github.com/terra-farm/go-xen-api-client"
|
||||
)
|
||||
|
||||
type XenAPIClient struct {
|
||||
@ -62,9 +63,8 @@ const (
|
||||
|
||||
func (c *XenAPIClient) RPCCall(result interface{}, method string, params []interface{}) (err error) {
|
||||
fmt.Println(params)
|
||||
p := new(xmlrpc.Params)
|
||||
p.Params = params
|
||||
err = c.RPC.Call(method, *p, result)
|
||||
p := xmlrpc.Params{Params: params}
|
||||
err = c.RPC.Call(method, p, result)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -202,24 +202,6 @@ func (client *XenAPIClient) GetVMByNameLabel(name_label string) (vms []*VM, err
|
||||
return vms, nil
|
||||
}
|
||||
|
||||
func (client *XenAPIClient) GetSRByNameLabel(name_label string) (srs []*SR, err error) {
|
||||
srs = make([]*SR, 0)
|
||||
result := APIResult{}
|
||||
err = client.APICall(&result, "SR.get_by_name_label", name_label)
|
||||
if err != nil {
|
||||
return srs, err
|
||||
}
|
||||
|
||||
for _, elem := range result.Value.([]interface{}) {
|
||||
sr := new(SR)
|
||||
sr.Ref = elem.(string)
|
||||
sr.Client = client
|
||||
srs = append(srs, sr)
|
||||
}
|
||||
|
||||
return srs, nil
|
||||
}
|
||||
|
||||
func (client *XenAPIClient) GetNetworkByUuid(network_uuid string) (network *Network, err error) {
|
||||
network = new(Network)
|
||||
result := APIResult{}
|
||||
@ -268,18 +250,6 @@ func (client *XenAPIClient) GetVdiByNameLabel(name_label string) (vdis []*VDI, e
|
||||
return vdis, nil
|
||||
}
|
||||
|
||||
func (client *XenAPIClient) GetSRByUuid(sr_uuid string) (sr *SR, err error) {
|
||||
sr = new(SR)
|
||||
result := APIResult{}
|
||||
err = client.APICall(&result, "SR.get_by_uuid", sr_uuid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr.Ref = result.Value.(string)
|
||||
sr.Client = client
|
||||
return
|
||||
}
|
||||
|
||||
func (client *XenAPIClient) GetVdiByUuid(vdi_uuid string) (vdi *VDI, err error) {
|
||||
vdi = new(VDI)
|
||||
result := APIResult{}
|
||||
@ -309,20 +279,6 @@ func (client *XenAPIClient) GetPIFs() (pifs []*PIF, err error) {
|
||||
return pifs, nil
|
||||
}
|
||||
|
||||
func (client *XenAPIClient) CreateTask() (task *Task, err error) {
|
||||
result := APIResult{}
|
||||
err = client.APICall(&result, "task.create", "packer-task", "Packer task")
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
task = new(Task)
|
||||
task.Ref = result.Value.(string)
|
||||
task.Client = client
|
||||
return
|
||||
}
|
||||
|
||||
// Host associated functions
|
||||
|
||||
func (self *Host) GetSoftwareVersion() (versions map[string]interface{}, err error) {
|
||||
@ -400,18 +356,8 @@ func (self *VM) CleanShutdown() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self *VM) HardShutdown() (err error) {
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "VM.hard_shutdown", self.Ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *VM) Unpause() (err error) {
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "VM.unpause", self.Ref)
|
||||
func Unpause(c *Connection, vmRef xenapi.VMRef) (err error) {
|
||||
err = c.client.VM.Unpause(c.session, vmRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -495,39 +441,22 @@ func (self *VM) GetVBDs() (vbds []VBD, err error) {
|
||||
return vbds, nil
|
||||
}
|
||||
|
||||
func (self *VM) GetVIFs() (vifs []VIF, err error) {
|
||||
vifs = make([]VIF, 0)
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "VM.get_VIFs", self.Ref)
|
||||
if err != nil {
|
||||
return vifs, err
|
||||
}
|
||||
for _, elem := range result.Value.([]interface{}) {
|
||||
vif := VIF{}
|
||||
vif.Ref = elem.(string)
|
||||
vif.Client = self.Client
|
||||
vifs = append(vifs, vif)
|
||||
}
|
||||
|
||||
return vifs, nil
|
||||
}
|
||||
|
||||
func (self *VM) GetDisks() (vdis []*VDI, err error) {
|
||||
func GetDisks(c *Connection, vmRef xenapi.VMRef) (vdis []xenapi.VDIRef, err error) {
|
||||
// Return just data disks (non-isos)
|
||||
vdis = make([]*VDI, 0)
|
||||
vbds, err := self.GetVBDs()
|
||||
vdis = make([]xenapi.VDIRef, 0)
|
||||
vbds, err := c.client.VM.GetVBDs(c.session, vmRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, vbd := range vbds {
|
||||
rec, err := vbd.GetRecord()
|
||||
rec, err := c.client.VBD.GetRecord(c.session, vbd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rec["type"] == "Disk" {
|
||||
if rec.Type == "Disk" {
|
||||
|
||||
vdi, err := vbd.GetVDI()
|
||||
vdi, err := c.client.VBD.GetVDI(c.session, vbd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -576,51 +505,53 @@ func (self *VM) SetStaticMemoryRange(min, max uint) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self *VM) ConnectVdi(vdi *VDI, vdiType VDIType) (err error) {
|
||||
func ConnectVdi(c *Connection, vmRef xenapi.VMRef, vdiRef xenapi.VDIRef, vbdType xenapi.VbdType) (err error) {
|
||||
|
||||
// 1. Create a VBD
|
||||
|
||||
vbd_rec := make(xmlrpc.Struct)
|
||||
vbd_rec["VM"] = self.Ref
|
||||
vbd_rec["VDI"] = vdi.Ref
|
||||
vbd_rec["userdevice"] = "autodetect"
|
||||
vbd_rec["empty"] = false
|
||||
vbd_rec["other_config"] = make(xmlrpc.Struct)
|
||||
vbd_rec["qos_algorithm_type"] = ""
|
||||
vbd_rec["qos_algorithm_params"] = make(xmlrpc.Struct)
|
||||
|
||||
switch vdiType {
|
||||
case CD:
|
||||
vbd_rec["mode"] = "RO"
|
||||
vbd_rec["bootable"] = true
|
||||
vbd_rec["unpluggable"] = false
|
||||
vbd_rec["type"] = "CD"
|
||||
case Disk:
|
||||
vbd_rec["mode"] = "RW"
|
||||
vbd_rec["bootable"] = false
|
||||
vbd_rec["unpluggable"] = false
|
||||
vbd_rec["type"] = "Disk"
|
||||
case Floppy:
|
||||
vbd_rec["mode"] = "RW"
|
||||
vbd_rec["bootable"] = false
|
||||
vbd_rec["unpluggable"] = true
|
||||
vbd_rec["type"] = "Floppy"
|
||||
var mode xenapi.VbdMode
|
||||
var unpluggable bool
|
||||
var bootable bool
|
||||
var t xenapi.VbdType
|
||||
switch vbdType {
|
||||
case xenapi.VbdTypeCD:
|
||||
mode = xenapi.VbdModeRO
|
||||
bootable = true
|
||||
unpluggable = false
|
||||
t = xenapi.VbdTypeCD
|
||||
case xenapi.VbdTypeDisk:
|
||||
mode = xenapi.VbdModeRW
|
||||
bootable = false
|
||||
unpluggable = false
|
||||
t = xenapi.VbdTypeDisk
|
||||
case xenapi.VbdTypeFloppy:
|
||||
mode = xenapi.VbdModeRW
|
||||
bootable = false
|
||||
unpluggable = true
|
||||
t = xenapi.VbdTypeFloppy
|
||||
}
|
||||
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "VBD.create", vbd_rec)
|
||||
vbd_ref, err := c.client.VBD.Create(c.session, xenapi.VBDRecord{
|
||||
VM: xenapi.VMRef(vmRef),
|
||||
VDI: xenapi.VDIRef(vdiRef),
|
||||
Userdevice: "autodetect",
|
||||
Empty: false,
|
||||
// OtherConfig: map[string]interface{{}},
|
||||
QosAlgorithmType: "",
|
||||
// QosAlgorithmParams: map[string]interface{{}},
|
||||
Mode: mode,
|
||||
Unpluggable: unpluggable,
|
||||
Bootable: bootable,
|
||||
Type: t,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vbd_ref := result.Value.(string)
|
||||
fmt.Println("VBD Ref:", vbd_ref)
|
||||
|
||||
result = APIResult{}
|
||||
err = self.Client.APICall(&result, "VBD.get_uuid", vbd_ref)
|
||||
uuid, err := c.client.VBD.GetUUID(c.session, vbd_ref)
|
||||
|
||||
fmt.Println("VBD UUID: ", result.Value.(string))
|
||||
fmt.Println("VBD UUID: ", uuid)
|
||||
/*
|
||||
// 2. Plug VBD (Non need - the VM hasn't booted.
|
||||
// @todo - check VM state
|
||||
@ -634,34 +565,32 @@ func (self *VM) ConnectVdi(vdi *VDI, vdiType VDIType) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self *VM) DisconnectVdi(vdi *VDI) error {
|
||||
vbds, err := self.GetVBDs()
|
||||
func DisconnectVdi(c *Connection, vmRef xenapi.VMRef, vdi xenapi.VDIRef) error {
|
||||
vbds, err := c.client.VM.GetVBDs(c.session, vmRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to get VM VBDs: %s", err.Error())
|
||||
}
|
||||
|
||||
for _, vbd := range vbds {
|
||||
rec, err := vbd.GetRecord()
|
||||
rec, err := c.client.VBD.GetRecord(c.session, vbd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not get record for VBD '%s': %s", vbd.Ref, err.Error())
|
||||
return fmt.Errorf("Could not get record for VBD '%s': %s", vbd, err.Error())
|
||||
}
|
||||
|
||||
if recVdi, ok := rec["VDI"].(string); ok {
|
||||
if recVdi == vdi.Ref {
|
||||
_ = vbd.Unplug()
|
||||
err = vbd.Destroy()
|
||||
recVdi := rec.VDI
|
||||
if recVdi == vdi {
|
||||
_ = c.client.VBD.Unplug(c.session, vbd)
|
||||
err = c.client.VBD.Destroy(c.session, vbd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not destroy VBD '%s': %s", vbd.Ref, err.Error())
|
||||
return fmt.Errorf("Could not destroy VBD '%s': %s", vbd, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
log.Printf("Could not find VDI record in VBD '%s'", vbd.Ref)
|
||||
log.Printf("Could not find VDI record in VBD '%s'", vbd)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("Could not find VBD for VDI '%s'", vdi.Ref)
|
||||
return fmt.Errorf("Could not find VBD for VDI '%s'", vdi)
|
||||
}
|
||||
|
||||
func (self *VM) SetPlatform(params map[string]string) (err error) {
|
||||
@ -679,31 +608,25 @@ func (self *VM) SetPlatform(params map[string]string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self *VM) ConnectNetwork(network *Network, device string) (vif *VIF, err error) {
|
||||
func ConnectNetwork(c *Connection, networkRef xenapi.NetworkRef, vmRef xenapi.VMRef, device string) (*xenapi.VIFRef, error) {
|
||||
// Create the VIF
|
||||
// vif_rec["other_config"] = make(xmlrpc.Struct)
|
||||
// vif_rec["qos_algorithm_params"] = make(xmlrpc.Struct)
|
||||
|
||||
vif_rec := make(xmlrpc.Struct)
|
||||
vif_rec["network"] = network.Ref
|
||||
vif_rec["VM"] = self.Ref
|
||||
vif_rec["MAC"] = ""
|
||||
vif_rec["device"] = device
|
||||
vif_rec["MTU"] = "1504"
|
||||
vif_rec["other_config"] = make(xmlrpc.Struct)
|
||||
vif_rec["qos_algorithm_type"] = ""
|
||||
vif_rec["qos_algorithm_params"] = make(xmlrpc.Struct)
|
||||
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "VIF.create", vif_rec)
|
||||
vif, err := c.client.VIF.Create(c.session, xenapi.VIFRecord{
|
||||
Network: networkRef,
|
||||
VM: vmRef,
|
||||
MAC: "",
|
||||
Device: device,
|
||||
MTU: 1504,
|
||||
QosAlgorithmType: "",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vif = new(VIF)
|
||||
vif.Ref = result.Value.(string)
|
||||
vif.Client = self.Client
|
||||
|
||||
return vif, nil
|
||||
return &vif, nil
|
||||
}
|
||||
|
||||
// Setters
|
||||
@ -901,9 +824,9 @@ type TransferRecord struct {
|
||||
UrlFull string `xml:"url_full,attr"`
|
||||
}
|
||||
|
||||
func (self *VDI) Expose(format string) (url string, err error) {
|
||||
func Expose(c *Connection, vdiRef xenapi.VDIRef, format string) (url string, err error) {
|
||||
|
||||
hosts, err := self.Client.GetHosts()
|
||||
hosts, err := c.client.Host.GetAll(c.session)
|
||||
|
||||
if err != nil {
|
||||
err = errors.New(fmt.Sprintf("Could not retrieve hosts in the pool: %s", err.Error()))
|
||||
@ -911,33 +834,31 @@ func (self *VDI) Expose(format string) (url string, err error) {
|
||||
}
|
||||
host := hosts[0]
|
||||
|
||||
disk_uuid, err := self.GetUuid()
|
||||
|
||||
if err != nil {
|
||||
err = errors.New(fmt.Sprintf("Failed to get VDI uuid for %s: %s", self.Ref, err.Error()))
|
||||
err = errors.New(fmt.Sprintf("Failed to get VDI uuid for %s: %s", vdiRef, err.Error()))
|
||||
return "", err
|
||||
}
|
||||
|
||||
args := make(map[string]string)
|
||||
args["transfer_mode"] = "http"
|
||||
args["vdi_uuid"] = disk_uuid
|
||||
args["vdi_uuid"] = string(vdiRef)
|
||||
args["expose_vhd"] = "true"
|
||||
args["network_uuid"] = "management"
|
||||
args["timeout_minutes"] = "5"
|
||||
|
||||
handle, err := host.CallPlugin("transfer", "expose", args)
|
||||
handle, err := c.client.Host.CallPlugin(c.session, host, "transfer", "expose", args)
|
||||
|
||||
if err != nil {
|
||||
err = errors.New(fmt.Sprintf("Error whilst exposing VDI %s: %s", disk_uuid, err.Error()))
|
||||
err = errors.New(fmt.Sprintf("Error whilst exposing VDI %s: %s", vdiRef, err.Error()))
|
||||
return "", err
|
||||
}
|
||||
|
||||
args = make(map[string]string)
|
||||
args["record_handle"] = handle
|
||||
record_xml, err := host.CallPlugin("transfer", "get_record", args)
|
||||
record_xml, err := c.client.Host.CallPlugin(c.session, host, "transfer", "get_record", args)
|
||||
|
||||
if err != nil {
|
||||
err = errors.New(fmt.Sprintf("Unable to retrieve transfer record for VDI %s: %s", disk_uuid, err.Error()))
|
||||
err = errors.New(fmt.Sprintf("Unable to retrieve transfer record for VDI %s: %s", vdiRef, err.Error()))
|
||||
return "", err
|
||||
}
|
||||
|
||||
@ -961,17 +882,15 @@ func (self *VDI) Expose(format string) (url string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Unexpose a VDI if exposed with a Transfer VM.
|
||||
func Unexpose(c *Connection, vdiRef xenapi.VDIRef) (err error) {
|
||||
|
||||
func (self *VDI) Unexpose() (err error) {
|
||||
|
||||
disk_uuid, err := self.GetUuid()
|
||||
disk_uuid, err := c.client.VDI.GetUUID(c.session, vdiRef)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hosts, err := self.Client.GetHosts()
|
||||
hosts, err := c.client.Host.GetAll(c.session)
|
||||
|
||||
if err != nil {
|
||||
err = errors.New(fmt.Sprintf("Could not retrieve hosts in the pool: %s", err.Error()))
|
||||
@ -983,7 +902,7 @@ func (self *VDI) Unexpose() (err error) {
|
||||
args := make(map[string]string)
|
||||
args["vdi_uuid"] = disk_uuid
|
||||
|
||||
result, err := host.CallPlugin("transfer", "unexpose", args)
|
||||
result, err := c.client.Host.CallPlugin(c.session, host, "transfer", "unexpose", args)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@ -996,94 +915,65 @@ func (self *VDI) Unexpose() (err error) {
|
||||
|
||||
// Task associated functions
|
||||
|
||||
func (self *Task) GetStatus() (status TaskStatusType, err error) {
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "task.get_status", self.Ref)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rawStatus := result.Value.(string)
|
||||
switch rawStatus {
|
||||
case "pending":
|
||||
status = Pending
|
||||
case "success":
|
||||
status = Success
|
||||
case "failure":
|
||||
status = Failure
|
||||
case "cancelling":
|
||||
status = Cancelling
|
||||
case "cancelled":
|
||||
status = Cancelled
|
||||
default:
|
||||
panic(fmt.Sprintf("Task.get_status: Unknown status '%s'", rawStatus))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Task) GetProgress() (progress float64, err error) {
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "task.get_progress", self.Ref)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
progress = result.Value.(float64)
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Task) GetResult() (object *XenAPIObject, err error) {
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "task.get_result", self.Ref)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch ref := result.Value.(type) {
|
||||
case string:
|
||||
// @fixme: xapi currently sends us an xmlrpc-encoded string via xmlrpc.
|
||||
// This seems to be a bug in xapi. Remove this workaround when it's fixed
|
||||
re := regexp.MustCompile("^<value><array><data><value>([^<]*)</value>.*</data></array></value>$")
|
||||
match := re.FindStringSubmatch(ref)
|
||||
if match == nil {
|
||||
object = nil
|
||||
} else {
|
||||
object = &XenAPIObject{
|
||||
Ref: match[1],
|
||||
Client: self.Client,
|
||||
}
|
||||
}
|
||||
case nil:
|
||||
object = nil
|
||||
default:
|
||||
err = fmt.Errorf("task.get_result: unknown value type %T (expected string or nil)", ref)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Task) GetErrorInfo() (errorInfo []string, err error) {
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "task.get_error_info", self.Ref)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
errorInfo = make([]string, 0)
|
||||
for _, infoRaw := range result.Value.([]interface{}) {
|
||||
errorInfo = append(errorInfo, fmt.Sprintf("%v", infoRaw))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Task) Destroy() (err error) {
|
||||
result := APIResult{}
|
||||
err = self.Client.APICall(&result, "task.destroy", self.Ref)
|
||||
return
|
||||
}
|
||||
// func (self *Task) GetResult() (object *XenAPIObject, err error) {
|
||||
// result := APIResult{}
|
||||
// err = self.Client.APICall(&result, "task.get_result", self.Ref)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// switch ref := result.Value.(type) {
|
||||
// case string:
|
||||
// // @fixme: xapi currently sends us an xmlrpc-encoded string via xmlrpc.
|
||||
// // This seems to be a bug in xapi. Remove this workaround when it's fixed
|
||||
// re := regexp.MustCompile("^<value><array><data><value>([^<]*)</value>.*</data></array></value>$")
|
||||
// match := re.FindStringSubmatch(ref)
|
||||
// if match == nil {
|
||||
// object = nil
|
||||
// } else {
|
||||
// object = &XenAPIObject{
|
||||
// Ref: match[1],
|
||||
// Client: self.Client,
|
||||
// }
|
||||
// }
|
||||
// case nil:
|
||||
// object = nil
|
||||
// default:
|
||||
// err = fmt.Errorf("task.get_result: unknown value type %T (expected string or nil)", ref)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// Client Initiator
|
||||
|
||||
func NewXenAPIClient(host, username, password string) (client XenAPIClient) {
|
||||
client.Host = host
|
||||
client.Url = "http://" + host
|
||||
client.Username = username
|
||||
client.Password = password
|
||||
client.RPC, _ = xmlrpc.NewClient(client.Url, nil)
|
||||
return
|
||||
type Connection struct {
|
||||
client *xenapi.Client
|
||||
session xenapi.SessionRef
|
||||
Host string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
func (c Connection) GetSession() string {
|
||||
return string(c.session)
|
||||
}
|
||||
|
||||
func NewXenAPIClient(host, username, password string) (*Connection, error) {
|
||||
client, err := xenapi.NewClient("https://"+host, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session, err := client.Session.LoginWithPassword(username, password, "1.0", "packer")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Connection{client, session, host, username, password}, nil
|
||||
}
|
||||
|
||||
func (c *Connection) GetClient() *xenapi.Client {
|
||||
return c.client
|
||||
}
|
||||
|
||||
func (c *Connection) GetSessionRef() xenapi.SessionRef {
|
||||
return c.session
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"github.com/mitchellh/packer/common"
|
||||
commonssh "github.com/mitchellh/packer/common/ssh"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
)
|
||||
|
||||
type CommonConfig struct {
|
||||
@ -221,27 +220,3 @@ func (c CommonConfig) ShouldKeepVM(state multistep.StateBag) bool {
|
||||
panic(fmt.Sprintf("Unknown keep_vm value '%s'", c.KeepVM))
|
||||
}
|
||||
}
|
||||
|
||||
func (config CommonConfig) GetSR(client xsclient.XenAPIClient) (*xsclient.SR, error) {
|
||||
if config.SrName == "" {
|
||||
// Find the default SR
|
||||
return client.GetDefaultSR()
|
||||
|
||||
} else {
|
||||
// Use the provided name label to find the SR to use
|
||||
srs, err := client.GetSRByNameLabel(config.SrName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(srs) == 0:
|
||||
return nil, fmt.Errorf("Couldn't find a SR with the specified name-label '%s'", config.SrName)
|
||||
case len(srs) > 1:
|
||||
return nil, fmt.Errorf("Found more than one SR with the name '%s'. The name must be unique", config.SrName)
|
||||
}
|
||||
|
||||
return srs[0], nil
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,15 @@ package common
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||
)
|
||||
|
||||
func appendQuery(urlstring, k, v string) (string, error) {
|
||||
@ -24,18 +25,18 @@ func appendQuery(urlstring, k, v string) (string, error) {
|
||||
return u.String(), err
|
||||
}
|
||||
|
||||
func HTTPUpload(import_url string, fh *os.File, state multistep.StateBag) (result *xsclient.XenAPIObject, err error) {
|
||||
func HTTPUpload(import_url string, fh *os.File, state multistep.StateBag) (result string, err error) {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
task, err := client.CreateTask()
|
||||
task, err := c.client.Task.Create(c.session, "packer-task", "Packer task")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Unable to create task: %s", err.Error())
|
||||
return
|
||||
}
|
||||
defer task.Destroy()
|
||||
defer c.client.Task.Destroy(c.session, task)
|
||||
|
||||
import_task_url, err := appendQuery(import_url, "task_id", task.Ref)
|
||||
import_task_url, err := appendQuery(import_url, "task_id", string(task))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -75,13 +76,13 @@ func HTTPUpload(import_url string, fh *os.File, state multistep.StateBag) (resul
|
||||
logIteration := 0
|
||||
err = InterruptibleWait{
|
||||
Predicate: func() (bool, error) {
|
||||
status, err := task.GetStatus()
|
||||
status, err := c.client.Task.GetStatus(c.session, task)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get task status: %s", err.Error())
|
||||
}
|
||||
switch status {
|
||||
case xsclient.Pending:
|
||||
progress, err := task.GetProgress()
|
||||
case xsclient.TaskStatusTypePending:
|
||||
progress, err := c.client.Task.GetProgress(c.session, task)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get progress: %s", err.Error())
|
||||
}
|
||||
@ -90,15 +91,15 @@ func HTTPUpload(import_url string, fh *os.File, state multistep.StateBag) (resul
|
||||
log.Printf("Upload %.0f%% complete", progress*100)
|
||||
}
|
||||
return false, nil
|
||||
case xsclient.Success:
|
||||
case xsclient.TaskStatusTypeSuccess:
|
||||
return true, nil
|
||||
case xsclient.Failure:
|
||||
errorInfo, err := task.GetErrorInfo()
|
||||
case xsclient.TaskStatusTypeFailure:
|
||||
errorInfo, err := c.client.Task.GetErrorInfo(c.session, task)
|
||||
if err != nil {
|
||||
errorInfo = []string{fmt.Sprintf("furthermore, failed to get error info: %s", err.Error())}
|
||||
}
|
||||
return false, fmt.Errorf("Task failed: %s", errorInfo)
|
||||
case xsclient.Cancelling, xsclient.Cancelled:
|
||||
case xsclient.TaskStatusTypeCancelling, xsclient.TaskStatusTypeCancelled:
|
||||
return false, fmt.Errorf("Task cancelled")
|
||||
default:
|
||||
return false, fmt.Errorf("Unknown task status %v", status)
|
||||
@ -115,7 +116,7 @@ func HTTPUpload(import_url string, fh *os.File, state multistep.StateBag) (resul
|
||||
return
|
||||
}
|
||||
|
||||
result, err = task.GetResult()
|
||||
result, err = c.client.Task.GetResult(c.session, task)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error getting result: %s", err.Error())
|
||||
return
|
||||
|
@ -2,22 +2,23 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
"log"
|
||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||
)
|
||||
|
||||
type StepAttachVdi struct {
|
||||
VdiUuidKey string
|
||||
VdiType xsclient.VDIType
|
||||
VdiType xsclient.VbdType
|
||||
|
||||
vdi *xsclient.VDI
|
||||
vdi xsclient.VDIRef
|
||||
}
|
||||
|
||||
func (self *StepAttachVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
var vdiUuid string
|
||||
if vdiUuidRaw, ok := state.GetOk(self.VdiUuidKey); ok {
|
||||
@ -28,20 +29,20 @@ func (self *StepAttachVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
}
|
||||
|
||||
var err error
|
||||
self.vdi, err = client.GetVdiByUuid(vdiUuid)
|
||||
self.vdi, err = c.client.VDI.GetByUUID(c.session, vdiUuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VDI from UUID '%s': %s", vdiUuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.ConnectVdi(self.vdi, self.VdiType, "")
|
||||
err = ConnectVdi(c, instance, self.vdi, self.VdiType)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error attaching VDI '%s': '%s'", vdiUuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -54,17 +55,18 @@ func (self *StepAttachVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
func (self *StepAttachVdi) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
if config.ShouldKeepVM(state) {
|
||||
return
|
||||
}
|
||||
|
||||
if self.vdi == nil {
|
||||
// TODO: What the fuck does this mean?
|
||||
if self.vdi == "" {
|
||||
return
|
||||
}
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
vmRef, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
log.Printf("Unable to get VM from UUID '%s': %s", uuid, err.Error())
|
||||
return
|
||||
@ -72,7 +74,7 @@ func (self *StepAttachVdi) Cleanup(state multistep.StateBag) {
|
||||
|
||||
vdiUuid := state.Get(self.VdiUuidKey).(string)
|
||||
|
||||
err = instance.DisconnectVdi(self.vdi)
|
||||
err = DisconnectVdi(c, vmRef, self.vdi)
|
||||
if err != nil {
|
||||
log.Printf("Unable to disconnect VDI '%s': %s", vdiUuid, err.Error())
|
||||
return
|
||||
|
@ -2,21 +2,21 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
)
|
||||
|
||||
type StepBootWait struct{}
|
||||
|
||||
func (self *StepBootWait) Run(state multistep.StateBag) multistep.StepAction {
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
instance, _ := client.GetVMByUuid(state.Get("instance_uuid").(string))
|
||||
instance, _ := c.client.VM.GetByUUID(c.session, state.Get("instance_uuid").(string))
|
||||
ui.Say("Unpausing VM " + state.Get("instance_uuid").(string))
|
||||
instance.Unpause()
|
||||
Unpause(c, instance)
|
||||
|
||||
if int64(config.BootWait) > 0 {
|
||||
ui.Say(fmt.Sprintf("Waiting %s for boot...", config.BootWait))
|
||||
|
@ -2,10 +2,10 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
"log"
|
||||
)
|
||||
|
||||
type StepDetachVdi struct {
|
||||
@ -14,7 +14,7 @@ type StepDetachVdi struct {
|
||||
|
||||
func (self *StepDetachVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
var vdiUuid string
|
||||
if vdiUuidRaw, ok := state.GetOk(self.VdiUuidKey); ok {
|
||||
@ -24,20 +24,20 @@ func (self *StepDetachVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
vdi, err := client.GetVdiByUuid(vdiUuid)
|
||||
vdi, err := c.client.VDI.GetByUUID(c.session, vdiUuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VDI from UUID '%s': %s", vdiUuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.DisconnectVdi(vdi)
|
||||
err = DisconnectVdi(c, instance, vdi)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to detach VDI '%s': %s", vdiUuid, err.Error()))
|
||||
//return multistep.ActionHalt
|
||||
|
@ -3,13 +3,13 @@ package common
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
|
||||
type StepExport struct{}
|
||||
@ -82,33 +82,33 @@ func downloadFile(url, filename string, ui packer.Ui) (err error) {
|
||||
func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
instance_uuid := state.Get("instance_uuid").(string)
|
||||
suffix := ".vhd"
|
||||
extrauri := "&format=vhd"
|
||||
|
||||
instance, err := client.GetVMByUuid(instance_uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, instance_uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not get VM with UUID '%s': %s", instance_uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if len(config.ExportNetworkNames) > 0 {
|
||||
vifs, err := instance.GetVIFs()
|
||||
vifs, err := c.client.VM.GetVIFs(c.session, instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error occured getting VIFs: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
for _, vif := range vifs {
|
||||
err := vif.Destroy()
|
||||
err := c.client.VIF.Destroy(c.session, vif)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Destroy vif fail: '%s': %s", vif.Ref, err.Error()))
|
||||
ui.Error(fmt.Sprintf("Destroy vif fail: '%s': %s", vif, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
for i, networkNameLabel := range config.ExportNetworkNames {
|
||||
networks, err := client.GetNetworkByNameLabel(networkNameLabel)
|
||||
networks, err := c.client.Network.GetByNameLabel(c.session, networkNameLabel)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error occured getting Network by name-label: %s", err.Error()))
|
||||
@ -126,7 +126,7 @@ func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
//we need the VIF index string
|
||||
vifIndexString := fmt.Sprintf("%d", i)
|
||||
_, err = instance.ConnectNetwork(networks[0], vifIndexString)
|
||||
_, err = ConnectNetwork(c, networks[0], instance, vifIndexString)
|
||||
|
||||
if err != nil {
|
||||
ui.Say(err.Error())
|
||||
@ -157,10 +157,10 @@ func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
if xe, e := exec.LookPath("xe"); e == nil && use_xe {
|
||||
cmd := exec.Command(
|
||||
xe,
|
||||
"-s", client.Host,
|
||||
"-s", c.Host,
|
||||
"-p", "443",
|
||||
"-u", client.Username,
|
||||
"-pw", client.Password,
|
||||
"-u", c.Username,
|
||||
"-pw", c.Password,
|
||||
"vm-export",
|
||||
"vm="+instance_uuid,
|
||||
compress_option_xe,
|
||||
@ -172,10 +172,10 @@ func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
err = cmd.Run()
|
||||
} else {
|
||||
export_url := fmt.Sprintf("https://%s/export?%suuid=%s&session_id=%s",
|
||||
client.Host,
|
||||
c.Host,
|
||||
compress_option_url,
|
||||
instance_uuid,
|
||||
client.Session.(string),
|
||||
c.GetSession(),
|
||||
)
|
||||
|
||||
ui.Say("Getting XVA " + export_url)
|
||||
@ -194,28 +194,28 @@ func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
case "vdi_vhd":
|
||||
// export the disks
|
||||
|
||||
disks, err := instance.GetDisks()
|
||||
disks, err := GetDisks(c, instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not get VM disks: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
for _, disk := range disks {
|
||||
disk_uuid, err := disk.GetUuid()
|
||||
disk_uuid, err := c.client.VDI.GetUUID(c.session, disk)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not get disk with UUID '%s': %s", disk_uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Work out XenServer version
|
||||
hosts, err := client.GetHosts()
|
||||
hosts, err := c.client.Host.GetAll(c.session)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not retrieve hosts in the pool: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
host := hosts[0]
|
||||
host_software_versions, err := host.GetSoftwareVersion()
|
||||
xs_version := host_software_versions["product_version"].(string)
|
||||
host_software_versions, err := c.client.Host.GetSoftwareVersion(c.session, host)
|
||||
xs_version := host_software_versions["product_version"]
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not get the software version: %s", err.Error()))
|
||||
@ -228,7 +228,7 @@ func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
if xs_version <= "6.5.0" && config.Format == "vdi_vhd" {
|
||||
// Export the VHD using a Transfer VM
|
||||
|
||||
disk_export_url, err = disk.Expose("vhd")
|
||||
disk_export_url, err = Expose(c, disk, "vhd")
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Failed to expose disk %s: %s", disk_uuid, err.Error()))
|
||||
@ -242,9 +242,9 @@ func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
// accepted for some reason.
|
||||
// @todo: raise with XAPI team.
|
||||
disk_export_url = fmt.Sprintf("https://%s:%s@%s/export_raw_vdi?vdi=%s%s",
|
||||
client.Username,
|
||||
client.Password,
|
||||
client.Host,
|
||||
c.Username,
|
||||
c.Password,
|
||||
c.Host,
|
||||
disk_uuid,
|
||||
extrauri)
|
||||
|
||||
@ -261,7 +261,7 @@ func (StepExport) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
// Call unexpose in case a TVM was used. The call is harmless
|
||||
// if that is not the case.
|
||||
disk.Unexpose()
|
||||
Unexpose(c, disk)
|
||||
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,9 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
)
|
||||
|
||||
type StepFindVdi struct {
|
||||
@ -15,14 +15,14 @@ type StepFindVdi struct {
|
||||
|
||||
func (self *StepFindVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
// Ignore if VdiName is not specified
|
||||
if self.VdiName == "" {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
vdis, err := client.GetVdiByNameLabel(self.VdiName)
|
||||
vdis, err := c.client.VDI.GetByNameLabel(c.session, self.VdiName)
|
||||
|
||||
switch {
|
||||
case len(vdis) == 0:
|
||||
@ -35,7 +35,7 @@ func (self *StepFindVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
vdi := vdis[0]
|
||||
|
||||
vdiUuid, err := vdi.GetUuid()
|
||||
vdiUuid, err := c.client.VDI.GetUUID(c.session, vdi)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get UUID of VDI '%s': %s", self.VdiName, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
|
@ -2,9 +2,10 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type StepGetVNCPort struct{}
|
||||
@ -14,8 +15,8 @@ func (self *StepGetVNCPort) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
ui.Say("Step: forward the instances VNC port over SSH")
|
||||
|
||||
domid := state.Get("domid").(string)
|
||||
cmd := fmt.Sprintf("xenstore-read /local/domain/%s/console/vnc-port", domid)
|
||||
domid := state.Get("domid").(int)
|
||||
cmd := fmt.Sprintf("xenstore-read /local/domain/%d/console/vnc-port", domid)
|
||||
|
||||
remote_vncport, err := ExecuteHostSSHCmd(state, cmd)
|
||||
if err != nil {
|
||||
|
@ -2,33 +2,33 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
)
|
||||
|
||||
type StepSetVmHostSshAddress struct{}
|
||||
|
||||
func (self *StepSetVmHostSshAddress) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Step: Set SSH address to VM host IP")
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
host, err := instance.GetResidentOn()
|
||||
host, err := c.client.VM.GetResidentOn(c.session, instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM Host for VM '%s': %s", uuid, err.Error()))
|
||||
}
|
||||
|
||||
address, err := host.GetAddress()
|
||||
address, err := c.client.Host.GetAddress(c.session, host)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get address from VM Host: %s", err.Error()))
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
"time"
|
||||
xenapi "github.com/terra-farm/go-xen-api-client"
|
||||
)
|
||||
|
||||
type StepShutdown struct{}
|
||||
@ -13,10 +14,10 @@ type StepShutdown struct{}
|
||||
func (StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
instance_uuid := state.Get("instance_uuid").(string)
|
||||
|
||||
instance, err := client.GetVMByUuid(instance_uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, instance_uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not get VM with UUID '%s': %s", instance_uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -39,8 +40,8 @@ func (StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
err = InterruptibleWait{
|
||||
Predicate: func() (bool, error) {
|
||||
power_state, err := instance.GetPowerState()
|
||||
return power_state == "Halted", err
|
||||
power_state, err := c.client.VM.GetPowerState(c.session, instance)
|
||||
return power_state == xenapi.VMPowerStateHalted, err
|
||||
},
|
||||
PredicateInterval: 5 * time.Second,
|
||||
Timeout: 300 * time.Second,
|
||||
@ -54,7 +55,7 @@ func (StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
} else {
|
||||
ui.Message("Attempting to cleanly shutdown the VM...")
|
||||
|
||||
err = instance.CleanShutdown()
|
||||
err = c.client.VM.CleanShutdown(c.session, instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not shut down VM: %s", err.Error()))
|
||||
return false
|
||||
@ -66,7 +67,7 @@ func (StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
if !success {
|
||||
ui.Say("WARNING: Forcing hard shutdown of the VM...")
|
||||
err = instance.HardShutdown()
|
||||
err = c.client.VM.HardShutdown(c.session, instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Could not hard shut down VM -- giving up: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
|
@ -2,12 +2,12 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type StepStartOnHIMN struct{}
|
||||
@ -23,19 +23,19 @@ type StepStartOnHIMN struct{}
|
||||
func (self *StepStartOnHIMN) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
ui.Say("Step: Start VM on the Host Internal Mangement Network")
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Find the HIMN Ref
|
||||
networks, err := client.GetNetworkByNameLabel("Host internal management network")
|
||||
networks, err := c.client.Network.GetByNameLabel(c.session, "Host internal management network")
|
||||
if err != nil || len(networks) == 0 {
|
||||
ui.Error("Unable to find a host internal management network")
|
||||
ui.Error(err.Error())
|
||||
@ -45,7 +45,7 @@ func (self *StepStartOnHIMN) Run(state multistep.StateBag) multistep.StepAction
|
||||
himn := networks[0]
|
||||
|
||||
// Create a VIF for the HIMN
|
||||
himn_vif, err := instance.ConnectNetwork(himn, "0")
|
||||
himn_vif, err := ConnectNetwork(c, himn, instance, "0")
|
||||
if err != nil {
|
||||
ui.Error("Error creating VIF")
|
||||
ui.Error(err.Error())
|
||||
@ -53,22 +53,22 @@ func (self *StepStartOnHIMN) Run(state multistep.StateBag) multistep.StepAction
|
||||
}
|
||||
|
||||
// Start the VM
|
||||
instance.Start(false, false)
|
||||
c.client.VM.Start(c.session, instance, false, false)
|
||||
|
||||
var himn_iface_ip string = ""
|
||||
|
||||
// Obtain the allocated IP
|
||||
err = InterruptibleWait{
|
||||
Predicate: func() (found bool, err error) {
|
||||
ips, err := himn.GetAssignedIPs()
|
||||
ips, err := c.client.Network.GetAssignedIps(c.session, himn)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Can't get assigned IPs: %s", err.Error())
|
||||
}
|
||||
log.Printf("IPs: %s", ips)
|
||||
log.Printf("Ref: %s", instance.Ref)
|
||||
log.Printf("Ref: %s", instance)
|
||||
|
||||
//Check for instance.Ref in map
|
||||
if vm_ip, ok := ips[himn_vif.Ref]; ok && vm_ip != "" {
|
||||
if vm_ip, ok := ips[*himn_vif]; ok && vm_ip != "" {
|
||||
ui.Say("Found the VM's IP: " + vm_ip)
|
||||
himn_iface_ip = vm_ip
|
||||
return true, nil
|
||||
|
@ -2,42 +2,49 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
"log"
|
||||
)
|
||||
|
||||
type StepStartVmPaused struct{}
|
||||
|
||||
func (self *StepStartVmPaused) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Step: Start VM Paused")
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// note that here "cd" means boot from hard drive ('c') first, then CDROM ('d')
|
||||
err = instance.SetHVMBoot("BIOS order", "cd")
|
||||
err = c.client.VM.SetHVMBootPolicy(c.session, instance, "BIOS order")
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to set HVM boot params: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.Start(true, false)
|
||||
err = c.client.VM.SetHVMBootParams(c.session, instance, map[string]string{"order": "cd"})
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to set HVM boot params: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = c.client.VM.Start(c.session, instance, true, false)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to start VM with UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
domid, err := instance.GetDomainId()
|
||||
domid, err := c.client.VM.GetDomid(c.session, instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get domid of VM with UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -49,20 +56,20 @@ func (self *StepStartVmPaused) Run(state multistep.StateBag) multistep.StepActio
|
||||
|
||||
func (self *StepStartVmPaused) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
if config.ShouldKeepVM(state) {
|
||||
return
|
||||
}
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
log.Printf(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
err = instance.HardShutdown()
|
||||
err = c.client.VM.HardShutdown(c.session, instance)
|
||||
if err != nil {
|
||||
log.Printf(fmt.Sprintf("Unable to force shutdown VM '%s': %s", uuid, err.Error()))
|
||||
}
|
||||
|
@ -4,16 +4,17 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/go-vnc"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/mitchellh/go-vnc"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
|
||||
const KeyLeftShift uint = 0xFFE1
|
||||
@ -195,7 +196,9 @@ func vncSendString(c *vnc.ClientConn, original string) {
|
||||
}
|
||||
|
||||
c.KeyEvent(keyCode, true)
|
||||
time.Sleep(time.Second / 10)
|
||||
c.KeyEvent(keyCode, false)
|
||||
time.Sleep(time.Second / 10)
|
||||
|
||||
if keyShift {
|
||||
c.KeyEvent(uint32(KeyLeftShift), false)
|
||||
|
@ -2,12 +2,13 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xenapi "github.com/terra-farm/go-xen-api-client"
|
||||
)
|
||||
|
||||
type StepUploadVdi struct {
|
||||
@ -17,9 +18,8 @@ type StepUploadVdi struct {
|
||||
}
|
||||
|
||||
func (self *StepUploadVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
imagePath := self.ImagePathFunc()
|
||||
vdiName := self.VdiNameFunc()
|
||||
@ -31,7 +31,12 @@ func (self *StepUploadVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Say(fmt.Sprintf("Step: Upload VDI '%s'", vdiName))
|
||||
|
||||
// Create VDI for the image
|
||||
sr, err := config.GetSR(client)
|
||||
srs, err := c.client.SR.GetAll(c.session)
|
||||
ui.Say(fmt.Sprintf("Step: Found SRs '%v'", srs))
|
||||
|
||||
srs, err = c.client.SR.GetByNameLabel(c.session, "LocalISO")
|
||||
sr := srs[0]
|
||||
ui.Say(fmt.Sprintf("Step: Found SRs '%v' Choosing: '%v'", srs, sr))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -53,13 +58,24 @@ func (self *StepUploadVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
fileLength := fstat.Size()
|
||||
|
||||
// Create the VDI
|
||||
vdi, err := sr.CreateVdi(vdiName, fileLength)
|
||||
// vdi, err := sr.CreateVdi(vdiName, fileLength)
|
||||
vdi, err := c.client.VDI.Create(c.session, xenapi.VDIRecord{
|
||||
NameLabel: vdiName,
|
||||
VirtualSize: int(fileLength),
|
||||
Type: "user",
|
||||
Sharable: false,
|
||||
ReadOnly: false,
|
||||
SR: sr,
|
||||
OtherConfig: map[string]string{
|
||||
"temp": "temp",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to create VDI '%s': %s", vdiName, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
vdiUuid, err := vdi.GetUuid()
|
||||
vdiUuid, err := c.client.VDI.GetUUID(c.session, vdi)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get UUID of VDI '%s': %s", vdiName, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -67,9 +83,9 @@ func (self *StepUploadVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
state.Put(self.VdiUuidKey, vdiUuid)
|
||||
|
||||
_, err = HTTPUpload(fmt.Sprintf("https://%s/import_raw_vdi?vdi=%s&session_id=%s",
|
||||
client.Host,
|
||||
vdi.Ref,
|
||||
client.Session.(string),
|
||||
c.Host,
|
||||
vdi,
|
||||
c.GetSession(),
|
||||
), fh, state)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to upload VDI: %s", err.Error()))
|
||||
@ -82,7 +98,7 @@ func (self *StepUploadVdi) Run(state multistep.StateBag) multistep.StepAction {
|
||||
func (self *StepUploadVdi) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
vdiName := self.VdiNameFunc()
|
||||
|
||||
@ -102,7 +118,7 @@ func (self *StepUploadVdi) Cleanup(state multistep.StateBag) {
|
||||
return
|
||||
}
|
||||
|
||||
vdi, err := client.GetVdiByUuid(vdiUuid)
|
||||
vdi, err := c.client.VDI.GetByUUID(c.session, vdiUuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Can't get VDI '%s': %s", vdiUuid, err.Error()))
|
||||
return
|
||||
@ -112,7 +128,7 @@ func (self *StepUploadVdi) Cleanup(state multistep.StateBag) {
|
||||
// so try several times
|
||||
for i := 0; i < 3; i++ {
|
||||
log.Printf("Trying to destroy VDI...")
|
||||
err = vdi.Destroy()
|
||||
err = c.client.VDI.Destroy(c.session, vdi)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ import (
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/nilshell/xmlrpc"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
)
|
||||
|
||||
type StepWaitForIP struct {
|
||||
@ -17,13 +15,13 @@ type StepWaitForIP struct {
|
||||
|
||||
func (self *StepWaitForIP) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*Connection)
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
|
||||
ui.Say("Step: Wait for VM's IP to become known to us.")
|
||||
|
||||
uuid := state.Get("instance_uuid").(string)
|
||||
instance, err := client.GetVMByUuid(uuid)
|
||||
instance, err := c.client.VM.GetByUUID(c.session, uuid)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM from UUID '%s': %s", uuid, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -50,14 +48,18 @@ func (self *StepWaitForIP) Run(state multistep.StateBag) multistep.StepAction {
|
||||
if config.IPGetter == "auto" || config.IPGetter == "tools" {
|
||||
|
||||
// Look for PV IP
|
||||
metrics, err := instance.GetGuestMetrics()
|
||||
m, err := c.client.VM.GetGuestMetrics(c.session, instance)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if metrics != nil {
|
||||
networks := metrics["networks"].(xmlrpc.Struct)
|
||||
if ipRaw, ok := networks["0/ip"]; ok {
|
||||
if ip = ipRaw.(string); ip != "" {
|
||||
if m != "" {
|
||||
metrics, err := c.client.VMGuestMetrics.GetRecord(c.session, m)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
networks := metrics.Networks
|
||||
if ip, ok := networks["0/ip"]; ok {
|
||||
if ip != "" {
|
||||
ui.Message(fmt.Sprintf("Got IP '%s' from XenServer tools", ip))
|
||||
return true, nil
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
hconfig "github.com/mitchellh/packer/helper/config"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||
xscommon "github.com/xenserver/packer-builder-xenserver/builder/xenserver/common"
|
||||
)
|
||||
|
||||
@ -191,21 +191,19 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
|
||||
}
|
||||
|
||||
func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
//Setup XAPI client
|
||||
client := xsclient.NewXenAPIClient(self.config.HostIp, self.config.Username, self.config.Password)
|
||||
c, err := xscommon.NewXenAPIClient(self.config.HostIp, self.config.Username, self.config.Password)
|
||||
|
||||
err := client.Login()
|
||||
if err != nil {
|
||||
return nil, err.(error)
|
||||
return nil, err
|
||||
}
|
||||
ui.Say("XAPI client session established")
|
||||
|
||||
client.GetHosts()
|
||||
c.GetClient().Host.GetAll(c.GetSessionRef())
|
||||
|
||||
//Share state between the other steps using a statebag
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("cache", cache)
|
||||
state.Put("client", client)
|
||||
state.Put("client", c)
|
||||
state.Put("config", self.config)
|
||||
state.Put("commonconfig", self.config.CommonConfig)
|
||||
state.Put("hook", hook)
|
||||
@ -273,19 +271,19 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
|
||||
new(stepCreateInstance),
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
VdiType: xsclient.Floppy,
|
||||
VdiType: xsclient.VbdTypeFloppy,
|
||||
},
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "iso_vdi_uuid",
|
||||
VdiType: xsclient.CD,
|
||||
VdiType: xsclient.VbdTypeCD,
|
||||
},
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "isoname_vdi_uuid",
|
||||
VdiType: xsclient.CD,
|
||||
VdiType: xsclient.VbdTypeCD,
|
||||
},
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "tools_vdi_uuid",
|
||||
VdiType: xsclient.CD,
|
||||
VdiType: xsclient.VbdTypeCD,
|
||||
},
|
||||
new(xscommon.StepStartVmPaused),
|
||||
new(xscommon.StepSetVmHostSshAddress),
|
||||
|
@ -5,17 +5,19 @@ import (
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
xenapi "github.com/terra-farm/go-xen-api-client"
|
||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||
xscommon "github.com/xenserver/packer-builder-xenserver/builder/xenserver/common"
|
||||
)
|
||||
|
||||
type stepCreateInstance struct {
|
||||
instance *xsclient.VM
|
||||
vdi *xsclient.VDI
|
||||
instance *xsclient.VMRef
|
||||
vdi *xsclient.VDIRef
|
||||
}
|
||||
|
||||
func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*xscommon.Connection)
|
||||
config := state.Get("config").(config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
@ -23,7 +25,7 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
|
||||
// Get the template to clone from
|
||||
|
||||
vms, err := client.GetVMByNameLabel(config.CloneTemplate)
|
||||
vms, err := c.GetClient().VM.GetByNameLabel(c.GetSessionRef(), config.CloneTemplate)
|
||||
|
||||
switch {
|
||||
case len(vms) == 0:
|
||||
@ -37,51 +39,51 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
template := vms[0]
|
||||
|
||||
// Clone that VM template
|
||||
instance, err := template.Clone(config.VMName)
|
||||
instance, err := c.GetClient().VM.Clone(c.GetSessionRef(), template, config.VMName)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error cloning VM: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
self.instance = instance
|
||||
self.instance = &instance
|
||||
|
||||
err = instance.SetIsATemplate(false)
|
||||
err = c.GetClient().VM.SetIsATemplate(c.GetSessionRef(), instance, false)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting is_a_template=false: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.SetVCPUsMax(config.VCPUsMax)
|
||||
err = c.GetClient().VM.SetVCPUsMax(c.GetSessionRef(), instance, int(config.VCPUsMax))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM VCPUs Max=%d: %s", config.VCPUsMax, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.SetVCPUsAtStartup(config.VCPUsAtStartup)
|
||||
err = c.GetClient().VM.SetVCPUsAtStartup(c.GetSessionRef(), instance, int(config.VCPUsAtStartup))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM VCPUs At Startup=%d: %s", config.VCPUsAtStartup, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.SetStaticMemoryRange(uint64(config.VMMemory*1024*1024), uint64(config.VMMemory*1024*1024))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM memory=%d: %s", config.VMMemory*1024*1024, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
// err = c.GetClient().VM.SetMemoryStaticRange(c.GetSessionRef(), instance, int(config.VMMemory*1024*1024), int(config.VMMemory*1024*1024))
|
||||
// if err != nil {
|
||||
// ui.Error(fmt.Sprintf("Error setting VM memory=%d: %s", config.VMMemory*1024*1024, err.Error()))
|
||||
// return multistep.ActionHalt
|
||||
// }
|
||||
|
||||
err = instance.SetPlatform(config.PlatformArgs)
|
||||
err = c.GetClient().VM.SetPlatform(c.GetSessionRef(), instance, config.PlatformArgs)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM platform: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.SetDescription(config.VMDescription)
|
||||
err = c.GetClient().VM.SetNameDescription(c.GetSessionRef(), instance, config.VMDescription)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM description: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if len(config.VMOtherConfig) != 0 {
|
||||
vm_other_config, err := instance.GetOtherConfig()
|
||||
vm_other_config, err := c.GetClient().VM.GetOtherConfig(c.GetSessionRef(), instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error getting VM other-config: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -89,7 +91,7 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
for key, value := range config.VMOtherConfig {
|
||||
vm_other_config[key] = value
|
||||
}
|
||||
err = instance.SetOtherConfig(vm_other_config)
|
||||
err = c.GetClient().VM.SetOtherConfig(c.GetSessionRef(), instance, vm_other_config)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM other-config: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -98,20 +100,31 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
|
||||
// Create VDI for the instance
|
||||
|
||||
sr, err := config.GetSR(client)
|
||||
srs, err := c.GetClient().SR.GetByNameLabel(c.GetSessionRef(), "Local storage")
|
||||
sr := srs[0]
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
vdi, err := sr.CreateVdi("Packer-disk", int64(config.DiskSize*1024*1024))
|
||||
vdi, err := c.GetClient().VDI.Create(c.GetSessionRef(), xenapi.VDIRecord{
|
||||
NameLabel: "Packer-disk",
|
||||
VirtualSize: int(config.DiskSize * 1024 * 1024),
|
||||
Type: "user",
|
||||
Sharable: false,
|
||||
ReadOnly: false,
|
||||
SR: sr,
|
||||
OtherConfig: map[string]string{
|
||||
"temp": "temp",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
self.vdi = vdi
|
||||
self.vdi = &vdi
|
||||
|
||||
err = instance.ConnectVdi(vdi, xsclient.Disk, "")
|
||||
err = xscommon.ConnectVdi(c, instance, vdi, xsclient.VbdTypeDisk)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -119,15 +132,11 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
|
||||
// Connect Network
|
||||
|
||||
var network *xsclient.Network
|
||||
var network xsclient.NetworkRef
|
||||
|
||||
if len(config.NetworkNames) == 0 {
|
||||
// No network has be specified. Use the management interface
|
||||
network = new(xsclient.Network)
|
||||
network.Ref = ""
|
||||
network.Client = &client
|
||||
|
||||
pifs, err := client.GetPIFs()
|
||||
pifs, err := c.GetClient().PIF.GetAll(c.GetSessionRef())
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error getting PIFs: %s", err.Error()))
|
||||
@ -135,25 +144,25 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
}
|
||||
|
||||
for _, pif := range pifs {
|
||||
pif_rec, err := pif.GetRecord()
|
||||
pif_rec, err := c.GetClient().PIF.GetRecord(c.GetSessionRef(), pif)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error getting PIF record: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if pif_rec["management"].(bool) {
|
||||
network.Ref = pif_rec["network"].(string)
|
||||
if pif_rec.Management {
|
||||
network = pif_rec.Network
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if network.Ref == "" {
|
||||
if string(network) == "" {
|
||||
ui.Error("Error: couldn't find management network. Aborting.")
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
_, err = instance.ConnectNetwork(network, "0")
|
||||
_, err = xscommon.ConnectNetwork(c, network, instance, "0")
|
||||
|
||||
if err != nil {
|
||||
ui.Say(err.Error())
|
||||
@ -162,7 +171,7 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
} else {
|
||||
// Look up each network by it's name label
|
||||
for i, networkNameLabel := range config.NetworkNames {
|
||||
networks, err := client.GetNetworkByNameLabel(networkNameLabel)
|
||||
networks, err := c.GetClient().Network.GetByNameLabel(c.GetSessionRef(), networkNameLabel)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error occured getting Network by name-label: %s", err.Error()))
|
||||
@ -180,15 +189,15 @@ func (self *stepCreateInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
|
||||
//we need the VIF index string
|
||||
vifIndexString := fmt.Sprintf("%d", i)
|
||||
_, err = instance.ConnectNetwork(networks[0], vifIndexString)
|
||||
_, err = xscommon.ConnectNetwork(c, networks[0], instance, vifIndexString)
|
||||
|
||||
if err != nil {
|
||||
ui.Say(err.Error())
|
||||
ui.Say(fmt.Sprintf("Failed to connect VIF with error: %v", err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instanceId, err := instance.GetUuid()
|
||||
instanceId, err := c.GetClient().VM.GetUUID(c.GetSessionRef(), instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM UUID: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -207,11 +216,12 @@ func (self *stepCreateInstance) Cleanup(state multistep.StateBag) {
|
||||
}
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("client").(*xscommon.Connection)
|
||||
|
||||
if self.instance != nil {
|
||||
ui.Say("Destroying VM")
|
||||
_ = self.instance.HardShutdown() // redundant, just in case
|
||||
err := self.instance.Destroy()
|
||||
_ = c.GetClient().VM.HardShutdown(c.GetSessionRef(), *self.instance) // redundant, just in case
|
||||
err := c.GetClient().VM.Destroy(c.GetSessionRef(), *self.instance)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
@ -219,7 +229,7 @@ func (self *stepCreateInstance) Cleanup(state multistep.StateBag) {
|
||||
|
||||
if self.vdi != nil {
|
||||
ui.Say("Destroying VDI")
|
||||
err := self.vdi.Destroy()
|
||||
err := c.GetClient().VDI.Destroy(c.GetSessionRef(), *self.vdi)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
hconfig "github.com/mitchellh/packer/helper/config"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||
xscommon "github.com/xenserver/packer-builder-xenserver/builder/xenserver/common"
|
||||
)
|
||||
|
||||
@ -99,21 +99,21 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, retErr error
|
||||
|
||||
func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
//Setup XAPI client
|
||||
client := xsclient.NewXenAPIClient(self.config.HostIp, self.config.Username, self.config.Password)
|
||||
c, err := xscommon.NewXenAPIClient(self.config.HostIp, self.config.Username, self.config.Password)
|
||||
|
||||
err := client.Login()
|
||||
if err != nil {
|
||||
return nil, err.(error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ui.Say("XAPI client session established")
|
||||
|
||||
client.GetHosts()
|
||||
c.GetClient().Host.GetAll(c.GetSessionRef())
|
||||
|
||||
//Share state between the other steps using a statebag
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("cache", cache)
|
||||
state.Put("client", client)
|
||||
state.Put("config", self.config)
|
||||
state.Put("client", c)
|
||||
// state.Put("config", self.config)
|
||||
state.Put("commonconfig", self.config.CommonConfig)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
@ -149,11 +149,11 @@ func (self *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (pa
|
||||
new(stepImportInstance),
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
VdiType: xsclient.Floppy,
|
||||
VdiType: xsclient.VbdTypeFloppy,
|
||||
},
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "tools_vdi_uuid",
|
||||
VdiType: xsclient.CD,
|
||||
VdiType: xsclient.VbdTypeCD,
|
||||
},
|
||||
new(xscommon.StepStartVmPaused),
|
||||
new(xscommon.StepSetVmHostSshAddress),
|
||||
|
@ -6,25 +6,26 @@ import (
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
xsclient "github.com/xenserver/go-xenserver-client"
|
||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||
xscommon "github.com/xenserver/packer-builder-xenserver/builder/xenserver/common"
|
||||
)
|
||||
|
||||
type stepImportInstance struct {
|
||||
instance *xsclient.VM
|
||||
vdi *xsclient.VDI
|
||||
instance xsclient.VMRef
|
||||
vdi xsclient.VDIRef
|
||||
}
|
||||
|
||||
func (self *stepImportInstance) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
client := state.Get("client").(xsclient.XenAPIClient)
|
||||
c := state.Get("client").(*xscommon.Connection)
|
||||
config := state.Get("config").(config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Step: Import Instance")
|
||||
|
||||
// find the SR
|
||||
sr, err := config.GetSR(client)
|
||||
srs, err := c.GetClient().SR.GetAll(c.GetSessionRef())
|
||||
sr := srs[0]
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
@ -38,41 +39,41 @@ func (self *stepImportInstance) Run(state multistep.StateBag) multistep.StepActi
|
||||
}
|
||||
|
||||
result, err := xscommon.HTTPUpload(fmt.Sprintf("https://%s/import?session_id=%s&sr_id=%s",
|
||||
client.Host,
|
||||
client.Session.(string),
|
||||
sr.Ref,
|
||||
c.Host,
|
||||
c.GetSession(),
|
||||
sr,
|
||||
), fh, state)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to upload VDI: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
if result == nil {
|
||||
if result == "" {
|
||||
ui.Error("XAPI did not reply with an instance reference")
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
instance := xsclient.VM(*result)
|
||||
instance := xsclient.VMRef(result)
|
||||
|
||||
instanceId, err := instance.GetUuid()
|
||||
instanceId, err := c.GetClient().VM.GetUUID(c.GetSessionRef(), instance)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get VM UUID: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
state.Put("instance_uuid", instanceId)
|
||||
|
||||
err = instance.SetVCPUsMax(config.VCPUsMax)
|
||||
err = c.GetClient().VM.SetVCPUsMax(c.GetSessionRef(), instance, int(config.VCPUsMax))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM VCPUs Max=%d: %s", config.VCPUsMax, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = instance.SetVCPUsAtStartup(config.VCPUsAtStartup)
|
||||
err = c.GetClient().VM.SetVCPUsAtStartup(c.GetSessionRef(), instance, int(config.VCPUsAtStartup))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM VCPUs At Startup=%d: %s", config.VCPUsAtStartup, err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
instance.SetDescription(config.VMDescription)
|
||||
err = c.GetClient().VM.SetNameDescription(c.GetSessionRef(), instance, config.VMDescription)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error setting VM description: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
|
199
examples/http/ks-1804-minimalvm.cfg
Normal file
199
examples/http/ks-1804-minimalvm.cfg
Normal file
@ -0,0 +1,199 @@
|
||||
#
|
||||
#Kickstart template for Ubuntu
|
||||
#Platform: x86-64
|
||||
#
|
||||
# Customized for Server 18.04 minimal vm install
|
||||
#
|
||||
# See README.mkd for usage
|
||||
|
||||
# Load the minimal server preseed off cdrom
|
||||
preseed preseed/file string /cdrom/preseed/ubuntu-server-minimalvm.seed
|
||||
|
||||
# OPTIONAL: Change hostname from default 'preseed'
|
||||
# If your DHCP hands out a hostname that will take precedence over this
|
||||
# see: https://bugs.launchpad.net/ubuntu/+source/preseed/+bug/1452202
|
||||
#preseed netcfg/hostname string minimal-vm
|
||||
|
||||
# Use local proxy
|
||||
# Setup a server with apt-cacher-ng and enter that hostname here
|
||||
#preseed mirror/http/proxy string http://my-local-cache:3142/
|
||||
|
||||
#System language
|
||||
lang en_US
|
||||
|
||||
#Language modules to install
|
||||
langsupport en_US
|
||||
|
||||
#System keyboard
|
||||
keyboard us
|
||||
|
||||
#System mouse
|
||||
mouse
|
||||
|
||||
#System timezone
|
||||
timezone America/New_York
|
||||
|
||||
#Root password
|
||||
rootpw --disabled
|
||||
|
||||
#Initial user (user with sudo capabilities)
|
||||
user ubuntu --fullname "Ubuntu" --password ChangeMe
|
||||
|
||||
#Reboot after installation
|
||||
reboot
|
||||
|
||||
#Use text mode install
|
||||
text
|
||||
|
||||
#Install OS instead of upgrade
|
||||
install
|
||||
|
||||
#Installation media
|
||||
cdrom
|
||||
|
||||
#Change console size to 1024x768x24
|
||||
preseed debian-installer/add-kernel-opts string "vga=792"
|
||||
|
||||
#System bootloader configuration
|
||||
bootloader --location=mbr
|
||||
|
||||
#Clear the Master Boot Record
|
||||
zerombr yes
|
||||
|
||||
#Partition clearing information
|
||||
# `--all` will give message in install log about only clearing first drive but
|
||||
# this is still needed
|
||||
clearpart --all --initlabel
|
||||
|
||||
#Advanced partition
|
||||
# The last lv specified will take up the remaining space of the vg. To get
|
||||
# around that add up all your disk sizes and set this value. It appears to
|
||||
# factor in the size of non lvm partitions as well
|
||||
preseed partman-auto-lvm/guided_size string 8192MB
|
||||
part /boot --fstype=ext4 --size=512 --asprimary
|
||||
part pv.1 --grow --size=1 --asprimary
|
||||
volgroup vg0 pv.1
|
||||
logvol / --fstype=ext4 --name=root --vgname=vg0 --size=1024
|
||||
logvol /usr --fstype=ext4 --name=usr --vgname=vg0 --size=2048
|
||||
logvol /var --fstype=ext4 --name=var --vgname=vg0 --size=1536
|
||||
logvol /var/log --fstype=ext4 --name=var_log --vgname=vg0 --size=512
|
||||
logvol swap --name=swap --vgname=vg0 --size=2048 --maxsize=2048
|
||||
logvol /home --fstype=ext4 --name=home --vgname=vg0 --size=512
|
||||
|
||||
# Don't install recommended items by default
|
||||
# This will also be set for built system at
|
||||
# /etc/apt/apt.conf.d/00InstallRecommends
|
||||
preseed base-installer/install-recommends boolean false
|
||||
|
||||
#System authorization infomation
|
||||
auth --useshadow
|
||||
|
||||
#Network information
|
||||
# If the system has a single interface the '--device' option isn't needed. If
|
||||
# you do use it remember that in 18.04 the device names are different. For
|
||||
# example I was seeing enp0s3 as the interface name. I haven't tested this
|
||||
# but you should be able to specify 'interface=enp0s3' as a boot paramater and
|
||||
# it will be passed through to installer. I have tested setting the device to
|
||||
# 'auto' will have it automatically pick the first active interface
|
||||
#network --bootproto=dhcp --device=enp0s3
|
||||
network --bootproto=dhcp --device=auto
|
||||
|
||||
#Firewall configuration
|
||||
# Not supported by ubuntu
|
||||
#firewall --disabled --trust=eth0 --ssh
|
||||
|
||||
|
||||
# Policy for applying updates. May be "none" (no automatic updates),
|
||||
# "unattended-upgrades" (install security updates automatically), or
|
||||
# "landscape" (manage system with Landscape).
|
||||
preseed pkgsel/update-policy select unattended-upgrades
|
||||
|
||||
#Do not configure the X Window System
|
||||
skipx
|
||||
|
||||
# Additional packages to install
|
||||
# - Most of these would have installed if it wasn't for turning off
|
||||
# install-recommends
|
||||
# - software-properties-common provides add-apt-repository which is needed for
|
||||
# adding additional PPAs. You can remove that if you don't plan on
|
||||
# installing anything. The %post script needs it for adding git
|
||||
# - Starting in 16.04 Ubuntu no longer installs python v2.7 by default.
|
||||
# Instead the default version of python is v3.x. If you still need v2.7
|
||||
# then add the `python` package to this list
|
||||
# - Uncomment the open-vm-tools line if this is going to run in vmware and are
|
||||
# not going to use vmware-tools that's distributed with it. Don't think the
|
||||
# --no-install-recommends is needed to not install desktop tools but doesn't
|
||||
# hurt anything
|
||||
%packages
|
||||
# -- required for %post --
|
||||
vim
|
||||
software-properties-common
|
||||
# -- pretty much required --
|
||||
gpg-agent # apt-key needs this when piping certs in through stdin
|
||||
curl
|
||||
openssh-server
|
||||
net-tools # this includes commands like ifconfig and netstat
|
||||
wget
|
||||
man
|
||||
# -- additional packages you'll likely want --
|
||||
#open-vm-tools --no-install-recommends # only needed on vmware vms
|
||||
#bash-completion # personally I always install it but not everyone uses bash
|
||||
#chrony # default time server in 18.04. systemd will manage time if this doesn't
|
||||
#haveged # helps keep entropy pool full on VMs
|
||||
|
||||
|
||||
%post
|
||||
# -- begin security hardening --
|
||||
# Change default umask from 022 to 027 (not world readable)
|
||||
sed -i -e 's/^\(UMASK\W*\)[0-9]\+$/\1027/' /etc/login.defs
|
||||
|
||||
# Add noatime to /
|
||||
sed -i -e 's/\(errors=remount-ro\)/noatime,\1/' /etc/fstab
|
||||
# Add noatime and nodev to everything else
|
||||
sed -i -e 's/\(boot.*defaults\)/\1,noatime,nodev/' /etc/fstab
|
||||
sed -i -e 's/\(home.*defaults\)/\1,noatime,nodev/' /etc/fstab
|
||||
sed -i -e 's/\(usr.*defaults\)/\1,noatime,nodev/' /etc/fstab
|
||||
# Remove nodev from this one if it causes issues for you
|
||||
sed -i -e 's/\(var .*defaults\)/\1,noatime,nodev/' /etc/fstab
|
||||
# Add noatime, nodev, and noexec to /var/log
|
||||
sed -i -e 's/\(var\/log .*defaults\)/\1,noatime,nodev,noexec/' /etc/fstab
|
||||
# Add line to enable noexec on /dev/shm
|
||||
echo "none /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0" >>/etc/fstab
|
||||
# -- end security hardening --
|
||||
|
||||
# Set some defaults for apt to keep things tidy
|
||||
cat > /etc/apt/apt.conf.d/90local <<"_EOF_"
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
APT::Periodic::AutocleanInterval "1";
|
||||
APT::Periodic::MaxSize "200";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
#Acquire::http::Proxy "http://my-local-cache:3142";
|
||||
_EOF_
|
||||
|
||||
# -- begin vim package customizations --
|
||||
echo "set background=dark" >>/etc/vim/vimrc.local
|
||||
# -- end vim package customizations --
|
||||
|
||||
# -- begin install git from 'Ubuntu Git Maintainers' PPA --
|
||||
add-apt-repository -y ppa:git-core/ppa
|
||||
apt-get -qq -y update
|
||||
apt-get -qq -y install git
|
||||
# -- end install git from 'Ubuntu Git Maintainers' PPA --
|
||||
|
||||
# -- begin set xdg base directories --
|
||||
cat > /etc/profile.d/xdg_basedir.sh <<"_EOF_"
|
||||
# Set XDG base directory global variables
|
||||
# XDG_RUNTIME_HOME is set on user login
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-"${HOME}/.local/share"}"
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-"${HOME}/.config"}"
|
||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-"${HOME}/.cache"}"
|
||||
_EOF_
|
||||
chmod 0644 /etc/profile.d/xdg_basedir.sh
|
||||
# -- end set xdg base directories --
|
||||
|
||||
# Clean up
|
||||
apt-get -qq -y autoremove
|
||||
apt-get clean
|
||||
rm -f /var/cache/apt/*cache.bin
|
||||
rm -rf /var/lib/apt/lists/*
|
@ -2,19 +2,20 @@
|
||||
"builders": [
|
||||
{
|
||||
"type": "xenserver-iso",
|
||||
"remote_host": "your-server.example.com",
|
||||
"tools_iso_name": "guest-tools.iso",
|
||||
"remote_host": "",
|
||||
"remote_username": "root",
|
||||
"remote_password": "password",
|
||||
"remote_password": "",
|
||||
|
||||
"boot_command": [
|
||||
"<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/centos6-ks.cfg<enter><wait>"
|
||||
"<tab> text ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks-1804-minimalvm.cfg<enter><wait>"
|
||||
],
|
||||
"boot_wait": "10s",
|
||||
"disk_size": 40960,
|
||||
"http_directory": "http",
|
||||
"iso_checksum": "4ed6c56d365bd3ab12cd88b8a480f4a62e7c66d2",
|
||||
"iso_checksum_type": "sha1",
|
||||
"iso_url": "{{user `mirror`}}/6.6/isos/x86_64/CentOS-6.6-x86_64-minimal.iso",
|
||||
"http_directory": "examples/http",
|
||||
"iso_checksum": "443511f6bf12402c12503733059269a2e10dec602916c0a75263e5d990f6bb93",
|
||||
"iso_checksum_type": "sha256",
|
||||
"iso_url": "https://releases.ubuntu.com/20.04.1/ubuntu-20.04.1-live-server-amd64.iso",
|
||||
"vm_other_config": {
|
||||
"conversionvm":"true"
|
||||
},
|
||||
@ -28,7 +29,10 @@
|
||||
"ssh_password": "vmpassword",
|
||||
"ssh_wait_timeout": "10000s",
|
||||
"vm_name": "packer-centos-6.6-x86_64",
|
||||
"vm_description": "Build time: {{isotime}}"
|
||||
"vm_description": "Build time: {{isotime}}",
|
||||
"clone_template": "Ubuntu Bionic Beaver 18.04",
|
||||
"disk_size": "20000",
|
||||
"vm_memory": "2048"
|
||||
}
|
||||
],
|
||||
|
38
go.mod
Normal file
38
go.mod
Normal file
@ -0,0 +1,38 @@
|
||||
module github.com/xenserver/packer-builder-xenserver
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/Sirupsen/logrus v0.10.1-0.20160601113210-f3cfb454f4c2 // indirect
|
||||
github.com/dylanmei/iso8601 v0.1.0 // indirect
|
||||
github.com/dylanmei/winrmtest v0.0.0-20151226195028-025617847eb2 // indirect
|
||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce // indirect
|
||||
github.com/hashicorp/go-multierror v0.0.0-20150916205742-d30f09973e19 // indirect
|
||||
github.com/hashicorp/go-version v0.0.0-20160119211326-7e3c02b30806 // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20151129044643-df949784da9e // indirect
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b
|
||||
github.com/kr/fs v0.0.0-20131111012553-2788f0dbd169 // indirect
|
||||
github.com/masterzen/simplexml v0.0.0-20140219194429-95ba30457eb1 // indirect
|
||||
github.com/masterzen/winrm v0.0.0-20151214220635-54ea5d01478c // indirect
|
||||
github.com/masterzen/xmlpath v0.0.0-20140218185901-13f4951698ad // indirect
|
||||
github.com/mitchellh/go-fs v0.0.0-20150611040906-a34c1b9334e8 // indirect
|
||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed
|
||||
github.com/mitchellh/iochan v0.0.0-20150529224432-87b45ffd0e95 // indirect
|
||||
github.com/mitchellh/mapstructure v0.0.0-20150717051158-281073eb9eb0 // indirect
|
||||
github.com/mitchellh/multistep v0.0.0-20140407010115-162146fc5711
|
||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f // indirect
|
||||
github.com/mitchellh/packer v0.10.2-0.20160629004225-63edbd40edc5
|
||||
github.com/mitchellh/reflectwalk v0.0.0-20150527153153-eecf4c70c626 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||
github.com/packer-community/winrmcp v0.0.0-20160310040704-f1bcf36a69fa // indirect
|
||||
github.com/pkg/sftp v0.0.0-20160118190721-e84cc8c755ca // indirect
|
||||
github.com/satori/go.uuid v0.0.0-20151028231719-d41af8bb6a77 // indirect
|
||||
github.com/stretchr/testify v1.6.1 // indirect
|
||||
github.com/terra-farm/go-xen-api-client v0.0.1
|
||||
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20160126184038-1f22c0103821
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect
|
||||
launchpad.net/xmlpath v0.0.0-20130614043138-000000000004 // indirect
|
||||
)
|
85
go.sum
Normal file
85
go.sum
Normal file
@ -0,0 +1,85 @@
|
||||
github.com/Sirupsen/logrus v0.10.1-0.20160601113210-f3cfb454f4c2 h1:3BYvDlSNPyoYk6lr17s9IueNAabOBur3f3uVULjbhTA=
|
||||
github.com/Sirupsen/logrus v0.10.1-0.20160601113210-f3cfb454f4c2/go.mod h1:rmk17hk6i8ZSAJkSDa7nOxamrG+SP4P0mm+DAvExv4U=
|
||||
github.com/amfranz/go-xmlrpc-client v0.0.0-20190612172737-76858463955d h1:39lR6Kg+GsvDpLMD2Mb7gkjXmmLexqfr7SPy4iQWDTE=
|
||||
github.com/amfranz/go-xmlrpc-client v0.0.0-20190612172737-76858463955d/go.mod h1:2NlXXRCkTbr/vZtUjcHKhbrESE4a3CDqVrgOROB16dg=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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-20151226195028-025617847eb2 h1:J29UzyZ34t5zmOLtGgjoSMpbCYCFooaNWlP/j+dX2Go=
|
||||
github.com/dylanmei/winrmtest v0.0.0-20151226195028-025617847eb2/go.mod h1:VBVDFSBXCIW8JaHQpI8lldSKfYaLMzP9oyq6IJ4fhzY=
|
||||
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/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-version v0.0.0-20160119211326-7e3c02b30806 h1:0MKTKHll8VOZ0ciR+yTIEJ8JrT0UUiRDsgtujJT7a8U=
|
||||
github.com/hashicorp/go-version v0.0.0-20160119211326-7e3c02b30806/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/yamux v0.0.0-20151129044643-df949784da9e h1:R35YxgX/iWqsDjzoNO/7uFf8vjcgBIc02rvaV/Vr15c=
|
||||
github.com/hashicorp/yamux v0.0.0-20151129044643-df949784da9e/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b h1:DzHy0GlWeF0KAglaTMY7Q+khIFoG8toHP+wLFBVBQJc=
|
||||
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/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/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/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/winrm v0.0.0-20151214220635-54ea5d01478c h1:qhyvK0cWkEirK1O/Kz1NLY1PUnOLONqvbdLaFjOYj+A=
|
||||
github.com/masterzen/winrm v0.0.0-20151214220635-54ea5d01478c/go.mod h1:CfZSN7zwz5gJiFhZJz49Uzk7mEBHIceWmbFmYx7Hf7E=
|
||||
github.com/masterzen/xmlpath v0.0.0-20140218185901-13f4951698ad h1:x50MyJNOPLsHR1euYRIaBx3Z2wlE0UPfZOHSYD+Flo0=
|
||||
github.com/masterzen/xmlpath v0.0.0-20140218185901-13f4951698ad/go.mod h1:A0zPC53iKKKcXYxr4ROjpQRQ5FgJXtelNdSmHHuq/tY=
|
||||
github.com/mitchellh/go-fs v0.0.0-20150611040906-a34c1b9334e8 h1:UCZ0aWSjQ9BAqutuze9boB7V75PRtZrBdNQ2FNgr3cg=
|
||||
github.com/mitchellh/go-fs v0.0.0-20150611040906-a34c1b9334e8/go.mod h1:g7SZj7ABpStq3tM4zqHiVEG5un/DZ1+qJJKO7qx1EvU=
|
||||
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/mapstructure v0.0.0-20150717051158-281073eb9eb0 h1:6VeKv8nNMVKA6qmZLYnPTx0tJ//NbDj1SbubWIikJ9k=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20150717051158-281073eb9eb0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/multistep v0.0.0-20140407010115-162146fc5711 h1:wYK+RW7LV1GJQf1XzS7gL8zVBa+3C963Dsy2Hduzse0=
|
||||
github.com/mitchellh/multistep v0.0.0-20140407010115-162146fc5711/go.mod h1:tZVWRY9V2OVYseuyNEjh0rb7qkeCMl+kRSGLqUEhFNg=
|
||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
|
||||
github.com/mitchellh/packer v0.10.2-0.20160629004225-63edbd40edc5 h1:s+nOB41LJjSQe7yeqNVEJll6IY/cViGUckFFoqP6whw=
|
||||
github.com/mitchellh/packer v0.10.2-0.20160629004225-63edbd40edc5/go.mod h1:3TnGTkplC/koV8K6bCfCN1NB34Tye7lmUzo55/X5wqw=
|
||||
github.com/mitchellh/reflectwalk v0.0.0-20150527153153-eecf4c70c626 h1:88u9H4mNODBcQUwlNpl6+jBhdoYT3WSi0w4hpYaYZ/o=
|
||||
github.com/mitchellh/reflectwalk v0.0.0-20150527153153-eecf4c70c626/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
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/packer-community/winrmcp v0.0.0-20160310040704-f1bcf36a69fa h1:ePOmpdPK/UHhi2SKiOxFiC76BZXaG3FMOzxKxIH/kAE=
|
||||
github.com/packer-community/winrmcp v0.0.0-20160310040704-f1bcf36a69fa/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk=
|
||||
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/satori/go.uuid v0.0.0-20151028231719-d41af8bb6a77 h1:X4eLA68fCmv+kFpUBFXIhv5wD5IFVB+oWUxjmpyl02c=
|
||||
github.com/satori/go.uuid v0.0.0-20151028231719-d41af8bb6a77/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/terra-farm/go-xen-api-client v0.0.1 h1:EigkWRuAwSktqwFwX1DV64RDWTZTTC0uwmP9W3xlLjE=
|
||||
github.com/terra-farm/go-xen-api-client v0.0.1/go.mod h1:DDTy4ADe11t55X7nHKZ92rsU6fGHDjLbGmn3+ZqvZ2w=
|
||||
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/xenserver/go-xenserver-client v0.0.0-20150518141242-42dc9035c2e8 h1:5VQ4LGdVcauqxTlnAfwZY8KTn1XlJMxEHOIJqthKJtM=
|
||||
github.com/xenserver/go-xenserver-client v0.0.0-20150518141242-42dc9035c2e8/go.mod h1:1ItwtwM/tObrp073TdWdvA+4lzAeWCDMJZ7fmntbJUc=
|
||||
golang.org/x/crypto v0.0.0-20160126184038-1f22c0103821 h1:Ufz3iUGlZbo8uCQ3IddvmNoW0T2XwdZqjVpOrdtyO0c=
|
||||
golang.org/x/crypto v0.0.0-20160126184038-1f22c0103821/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/sys v0.0.0-20160204225817-50c6bc5e4292 h1:FrW0lbpMBPKe4sGJsd3V/eCGzsC2ksMAG+LlbO74+VQ=
|
||||
golang.org/x/sys v0.0.0-20160204225817-50c6bc5e4292/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
|
||||
launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
|
||||
launchpad.net/xmlpath v0.0.0-20130614043138-000000000004 h1:B8nNZBUrx8YufDCAJjvO/lVs4GxXMQHyrjwJdJzXMFg=
|
||||
launchpad.net/xmlpath v0.0.0-20130614043138-000000000004/go.mod h1:vqyExLOM3qBx7mvYRkoxjSCF945s0mbe7YynlKYXtsA=
|
6
packer.json
Normal file
6
packer.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"builders": [{
|
||||
"type": "xenserver-iso",
|
||||
"tools_iso_name": "guest-tools.iso"
|
||||
}]
|
||||
}
|
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
@ -1 +0,0 @@
|
||||
logrus
|
10
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
10
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
@ -1,10 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
install:
|
||||
- go get -t ./...
|
||||
script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
|
66
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
66
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
@ -1,66 +0,0 @@
|
||||
# 0.10.0
|
||||
|
||||
* feature: Add a test hook (#180)
|
||||
* feature: `ParseLevel` is now case-insensitive (#326)
|
||||
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
|
||||
* performance: avoid re-allocations on `WithFields` (#335)
|
||||
|
||||
# 0.9.0
|
||||
|
||||
* logrus/text_formatter: don't emit empty msg
|
||||
* logrus/hooks/airbrake: move out of main repository
|
||||
* logrus/hooks/sentry: move out of main repository
|
||||
* logrus/hooks/papertrail: move out of main repository
|
||||
* logrus/hooks/bugsnag: move out of main repository
|
||||
* logrus/core: run tests with `-race`
|
||||
* logrus/core: detect TTY based on `stderr`
|
||||
* logrus/core: support `WithError` on logger
|
||||
* logrus/core: Solaris support
|
||||
|
||||
# 0.8.7
|
||||
|
||||
* logrus/core: fix possible race (#216)
|
||||
* logrus/doc: small typo fixes and doc improvements
|
||||
|
||||
|
||||
# 0.8.6
|
||||
|
||||
* hooks/raven: allow passing an initialized client
|
||||
|
||||
# 0.8.5
|
||||
|
||||
* logrus/core: revert #208
|
||||
|
||||
# 0.8.4
|
||||
|
||||
* formatter/text: fix data race (#218)
|
||||
|
||||
# 0.8.3
|
||||
|
||||
* logrus/core: fix entry log level (#208)
|
||||
* logrus/core: improve performance of text formatter by 40%
|
||||
* logrus/core: expose `LevelHooks` type
|
||||
* logrus/core: add support for DragonflyBSD and NetBSD
|
||||
* formatter/text: print structs more verbosely
|
||||
|
||||
# 0.8.2
|
||||
|
||||
* logrus: fix more Fatal family functions
|
||||
|
||||
# 0.8.1
|
||||
|
||||
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
||||
|
||||
# 0.8.0
|
||||
|
||||
* logrus: defaults to stderr instead of stdout
|
||||
* hooks/sentry: add special field for `*http.Request`
|
||||
* formatter/text: ignore Windows for colors
|
||||
|
||||
# 0.7.3
|
||||
|
||||
* formatter/\*: allow configuration of timestamp layout
|
||||
|
||||
# 0.7.2
|
||||
|
||||
* formatter/text: Add configuration option for time format (#158)
|
390
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
390
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
@ -1,390 +0,0 @@
|
||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/Sirupsen/logrus) [](https://godoc.org/github.com/Sirupsen/logrus)
|
||||
|
||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
|
||||
many large deployments. The core API is unlikely to change much but please
|
||||
version control your Logrus to make sure you aren't fetching latest `master` on
|
||||
every build.**
|
||||
|
||||
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||
plain text):
|
||||
|
||||

|
||||
|
||||
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
|
||||
or Splunk:
|
||||
|
||||
```json
|
||||
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||
|
||||
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||
|
||||
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||
|
||||
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||
|
||||
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||
```
|
||||
|
||||
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
|
||||
attached, the output is compatible with the
|
||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||
|
||||
```text
|
||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||
exit status 1
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
The simplest way to use Logrus is simply the package-level exported logger:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
}).Info("A walrus appears")
|
||||
}
|
||||
```
|
||||
|
||||
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
||||
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||
want:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Log as JSON instead of the default ASCII formatter.
|
||||
log.SetFormatter(&log.JSONFormatter{})
|
||||
|
||||
// Output to stderr instead of stdout, could also be a file.
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
// Only log the warning severity or above.
|
||||
log.SetLevel(log.WarnLevel)
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"omg": true,
|
||||
"number": 122,
|
||||
}).Warn("The group's number increased tremendously!")
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"omg": true,
|
||||
"number": 100,
|
||||
}).Fatal("The ice breaks!")
|
||||
|
||||
// A common pattern is to re-use fields between logging statements by re-using
|
||||
// the logrus.Entry returned from WithFields()
|
||||
contextLogger := log.WithFields(log.Fields{
|
||||
"common": "this is a common field",
|
||||
"other": "I also should be logged always",
|
||||
})
|
||||
|
||||
contextLogger.Info("I'll be logged with common and other field")
|
||||
contextLogger.Info("Me too")
|
||||
}
|
||||
```
|
||||
|
||||
For more advanced usage such as logging to multiple locations from the same
|
||||
application, you can also create an instance of the `logrus` Logger:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Create a new instance of the logger. You can have any number of instances.
|
||||
var log = logrus.New()
|
||||
|
||||
func main() {
|
||||
// The API for setting attributes is a little different than the package level
|
||||
// exported logger. See Godoc.
|
||||
log.Out = os.Stderr
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"size": 10,
|
||||
}).Info("A group of walrus emerges from the ocean")
|
||||
}
|
||||
```
|
||||
|
||||
#### Fields
|
||||
|
||||
Logrus encourages careful, structured logging though logging fields instead of
|
||||
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||
to send event %s to topic %s with key %d")`, you should log the much more
|
||||
discoverable:
|
||||
|
||||
```go
|
||||
log.WithFields(log.Fields{
|
||||
"event": event,
|
||||
"topic": topic,
|
||||
"key": key,
|
||||
}).Fatal("Failed to send event")
|
||||
```
|
||||
|
||||
We've found this API forces you to think about logging in a way that produces
|
||||
much more useful logging messages. We've been in countless situations where just
|
||||
a single added field to a log statement that was already there would've saved us
|
||||
hours. The `WithFields` call is optional.
|
||||
|
||||
In general, with Logrus using any of the `printf`-family functions should be
|
||||
seen as a hint you should add a field, however, you can still use the
|
||||
`printf`-family functions with Logrus.
|
||||
|
||||
#### Hooks
|
||||
|
||||
You can add hooks for logging levels. For example to send errors to an exception
|
||||
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||
multiple places simultaneously, e.g. syslog.
|
||||
|
||||
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||
`init`:
|
||||
|
||||
```go
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||
"log/syslog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
|
||||
|
||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||
if err != nil {
|
||||
log.Error("Unable to connect to local syslog daemon")
|
||||
} else {
|
||||
log.AddHook(hook)
|
||||
}
|
||||
}
|
||||
```
|
||||
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||
|
||||
| Hook | Description |
|
||||
| ----- | ----------- |
|
||||
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
||||
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
||||
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
|
||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
||||
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
||||
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
||||
|
||||
#### Level logging
|
||||
|
||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||
|
||||
```go
|
||||
log.Debug("Useful debugging information.")
|
||||
log.Info("Something noteworthy happened!")
|
||||
log.Warn("You should probably take a look at this.")
|
||||
log.Error("Something failed but I'm not quitting.")
|
||||
// Calls os.Exit(1) after logging
|
||||
log.Fatal("Bye.")
|
||||
// Calls panic() after logging
|
||||
log.Panic("I'm bailing.")
|
||||
```
|
||||
|
||||
You can set the logging level on a `Logger`, then it will only log entries with
|
||||
that severity or anything above it:
|
||||
|
||||
```go
|
||||
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
||||
log.SetLevel(log.InfoLevel)
|
||||
```
|
||||
|
||||
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
||||
environment if your application has that.
|
||||
|
||||
#### Entries
|
||||
|
||||
Besides the fields added with `WithField` or `WithFields` some fields are
|
||||
automatically added to all logging events:
|
||||
|
||||
1. `time`. The timestamp when the entry was created.
|
||||
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
||||
the `AddFields` call. E.g. `Failed to send event.`
|
||||
3. `level`. The logging level. E.g. `info`.
|
||||
|
||||
#### Environments
|
||||
|
||||
Logrus has no notion of environment.
|
||||
|
||||
If you wish for hooks and formatters to only be used in specific environments,
|
||||
you should handle that yourself. For example, if your application has a global
|
||||
variable `Environment`, which is a string representation of the environment you
|
||||
could do:
|
||||
|
||||
```go
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
init() {
|
||||
// do something here to set environment depending on an environment variable
|
||||
// or command-line flag
|
||||
if Environment == "production" {
|
||||
log.SetFormatter(&log.JSONFormatter{})
|
||||
} else {
|
||||
// The TextFormatter is default, you don't actually have to do this.
|
||||
log.SetFormatter(&log.TextFormatter{})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This configuration is how `logrus` was intended to be used, but JSON in
|
||||
production is mostly only useful if you do log aggregation with tools like
|
||||
Splunk or Logstash.
|
||||
|
||||
#### Formatters
|
||||
|
||||
The built-in logging formatters are:
|
||||
|
||||
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||
without colors.
|
||||
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||
field to `true`. To force no colored output even if there is a TTY set the
|
||||
`DisableColors` field to `true`
|
||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||
* `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events.
|
||||
|
||||
```go
|
||||
logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"})
|
||||
```
|
||||
|
||||
Third party logging formatters:
|
||||
|
||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||
|
||||
You can define your formatter by implementing the `Formatter` interface,
|
||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||
default ones (see Entries section above):
|
||||
|
||||
```go
|
||||
type MyJSONFormatter struct {
|
||||
}
|
||||
|
||||
log.SetFormatter(new(MyJSONFormatter))
|
||||
|
||||
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
// Note this doesn't include Time, Level and Message which are available on
|
||||
// the Entry. Consult `godoc` on information about those fields or read the
|
||||
// source of the official loggers.
|
||||
serialized, err := json.Marshal(entry.Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
}
|
||||
```
|
||||
|
||||
#### Logger as an `io.Writer`
|
||||
|
||||
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
||||
|
||||
```go
|
||||
w := logger.Writer()
|
||||
defer w.Close()
|
||||
|
||||
srv := http.Server{
|
||||
// create a stdlib log.Logger that writes to
|
||||
// logrus.Logger.
|
||||
ErrorLog: log.New(w, "", 0),
|
||||
}
|
||||
```
|
||||
|
||||
Each line written to that writer will be printed the usual way, using formatters
|
||||
and hooks. The level for those entries is `info`.
|
||||
|
||||
#### Rotation
|
||||
|
||||
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||
external program (like `logrotate(8)`) that can compress and delete old log
|
||||
entries. It should not be a feature of the application-level logger.
|
||||
|
||||
#### Tools
|
||||
|
||||
| Tool | Description |
|
||||
| ---- | ----------- |
|
||||
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|
||||
|
||||
#### Testing
|
||||
|
||||
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
|
||||
|
||||
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
|
||||
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
|
||||
|
||||
```go
|
||||
logger, hook := NewNullLogger()
|
||||
logger.Error("Hello error")
|
||||
|
||||
assert.Equal(1, len(hook.Entries))
|
||||
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||
|
||||
hook.Reset()
|
||||
assert.Nil(hook.LastEntry())
|
||||
```
|
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
@ -1,26 +0,0 @@
|
||||
/*
|
||||
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||
|
||||
|
||||
The simplest way to use Logrus is simply the package-level exported logger:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.WithFields(log.Fields{
|
||||
"animal": "walrus",
|
||||
"number": 1,
|
||||
"size": 10,
|
||||
}).Info("A walrus appears")
|
||||
}
|
||||
|
||||
Output:
|
||||
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||
|
||||
For a full guide visit https://github.com/Sirupsen/logrus
|
||||
*/
|
||||
package logrus
|
264
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
264
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
@ -1,264 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Defines the key when adding errors using WithError.
|
||||
var ErrorKey = "error"
|
||||
|
||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||
// passed around as much as you wish to avoid field duplication.
|
||||
type Entry struct {
|
||||
Logger *Logger
|
||||
|
||||
// Contains all the fields set by the user.
|
||||
Data Fields
|
||||
|
||||
// Time at which the log entry was created
|
||||
Time time.Time
|
||||
|
||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||
Level Level
|
||||
|
||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
Message string
|
||||
}
|
||||
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
// Default is three fields, give a little extra room
|
||||
Data: make(Fields, 5),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a reader for the entry, which is a proxy to the formatter.
|
||||
func (entry *Entry) Reader() (*bytes.Buffer, error) {
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
return bytes.NewBuffer(serialized), err
|
||||
}
|
||||
|
||||
// Returns the string representation from the reader and ultimately the
|
||||
// formatter.
|
||||
func (entry *Entry) String() (string, error) {
|
||||
reader, err := entry.Reader()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return reader.String(), err
|
||||
}
|
||||
|
||||
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||
func (entry *Entry) WithError(err error) *Entry {
|
||||
return entry.WithField(ErrorKey, err)
|
||||
}
|
||||
|
||||
// Add a single field to the Entry.
|
||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||
return entry.WithFields(Fields{key: value})
|
||||
}
|
||||
|
||||
// Add a map of fields to the Entry.
|
||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||
data := make(Fields, len(entry.Data)+len(fields))
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
for k, v := range fields {
|
||||
data[k] = v
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data}
|
||||
}
|
||||
|
||||
// This function is not declared with a pointer value because otherwise
|
||||
// race conditions will occur when using multiple goroutines
|
||||
func (entry Entry) log(level Level, msg string) {
|
||||
entry.Time = time.Now()
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
|
||||
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
reader, err := entry.Reader()
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
|
||||
_, err = io.Copy(entry.Logger.Out, reader)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
|
||||
// To avoid Entry#log() returning a value that only would make sense for
|
||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
// directly here.
|
||||
if level <= PanicLevel {
|
||||
panic(&entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Print(args ...interface{}) {
|
||||
entry.Info(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warning(args ...interface{}) {
|
||||
entry.Warn(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
panic(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
entry.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
entry.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.Fatal(fmt.Sprintf(format, args...))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.Panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
entry.Debug(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
entry.Info(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Println(args ...interface{}) {
|
||||
entry.Infoln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
entry.Warn(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningln(args ...interface{}) {
|
||||
entry.Warnln(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
entry.Error(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
entry.Fatal(entry.sprintlnn(args...))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
entry.Panic(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||
// string allocation, we do the simplest thing.
|
||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||
msg := fmt.Sprintln(args...)
|
||||
return msg[:len(msg)-1]
|
||||
}
|
193
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
193
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
@ -1,193 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
// std is the name of the standard logger in stdlib `log`
|
||||
std = New()
|
||||
)
|
||||
|
||||
func StandardLogger() *Logger {
|
||||
return std
|
||||
}
|
||||
|
||||
// SetOutput sets the standard logger output.
|
||||
func SetOutput(out io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Out = out
|
||||
}
|
||||
|
||||
// SetFormatter sets the standard logger formatter.
|
||||
func SetFormatter(formatter Formatter) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Formatter = formatter
|
||||
}
|
||||
|
||||
// SetLevel sets the standard logger level.
|
||||
func SetLevel(level Level) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Level = level
|
||||
}
|
||||
|
||||
// GetLevel returns the standard logger level.
|
||||
func GetLevel() Level {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
return std.Level
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the standard logger hooks.
|
||||
func AddHook(hook Hook) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||
func WithError(err error) *Entry {
|
||||
return std.WithField(ErrorKey, err)
|
||||
}
|
||||
|
||||
// WithField creates an entry from the standard logger and adds a field to
|
||||
// it. If you want multiple fields, use `WithFields`.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithField(key string, value interface{}) *Entry {
|
||||
return std.WithField(key, value)
|
||||
}
|
||||
|
||||
// WithFields creates an entry from the standard logger and adds multiple
|
||||
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||
// once for each field.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithFields(fields Fields) *Entry {
|
||||
return std.WithFields(fields)
|
||||
}
|
||||
|
||||
// Debug logs a message at level Debug on the standard logger.
|
||||
func Debug(args ...interface{}) {
|
||||
std.Debug(args...)
|
||||
}
|
||||
|
||||
// Print logs a message at level Info on the standard logger.
|
||||
func Print(args ...interface{}) {
|
||||
std.Print(args...)
|
||||
}
|
||||
|
||||
// Info logs a message at level Info on the standard logger.
|
||||
func Info(args ...interface{}) {
|
||||
std.Info(args...)
|
||||
}
|
||||
|
||||
// Warn logs a message at level Warn on the standard logger.
|
||||
func Warn(args ...interface{}) {
|
||||
std.Warn(args...)
|
||||
}
|
||||
|
||||
// Warning logs a message at level Warn on the standard logger.
|
||||
func Warning(args ...interface{}) {
|
||||
std.Warning(args...)
|
||||
}
|
||||
|
||||
// Error logs a message at level Error on the standard logger.
|
||||
func Error(args ...interface{}) {
|
||||
std.Error(args...)
|
||||
}
|
||||
|
||||
// Panic logs a message at level Panic on the standard logger.
|
||||
func Panic(args ...interface{}) {
|
||||
std.Panic(args...)
|
||||
}
|
||||
|
||||
// Fatal logs a message at level Fatal on the standard logger.
|
||||
func Fatal(args ...interface{}) {
|
||||
std.Fatal(args...)
|
||||
}
|
||||
|
||||
// Debugf logs a message at level Debug on the standard logger.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
std.Debugf(format, args...)
|
||||
}
|
||||
|
||||
// Printf logs a message at level Info on the standard logger.
|
||||
func Printf(format string, args ...interface{}) {
|
||||
std.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Infof logs a message at level Info on the standard logger.
|
||||
func Infof(format string, args ...interface{}) {
|
||||
std.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Warnf logs a message at level Warn on the standard logger.
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
std.Warnf(format, args...)
|
||||
}
|
||||
|
||||
// Warningf logs a message at level Warn on the standard logger.
|
||||
func Warningf(format string, args ...interface{}) {
|
||||
std.Warningf(format, args...)
|
||||
}
|
||||
|
||||
// Errorf logs a message at level Error on the standard logger.
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
std.Errorf(format, args...)
|
||||
}
|
||||
|
||||
// Panicf logs a message at level Panic on the standard logger.
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
std.Panicf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf logs a message at level Fatal on the standard logger.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
std.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Debugln logs a message at level Debug on the standard logger.
|
||||
func Debugln(args ...interface{}) {
|
||||
std.Debugln(args...)
|
||||
}
|
||||
|
||||
// Println logs a message at level Info on the standard logger.
|
||||
func Println(args ...interface{}) {
|
||||
std.Println(args...)
|
||||
}
|
||||
|
||||
// Infoln logs a message at level Info on the standard logger.
|
||||
func Infoln(args ...interface{}) {
|
||||
std.Infoln(args...)
|
||||
}
|
||||
|
||||
// Warnln logs a message at level Warn on the standard logger.
|
||||
func Warnln(args ...interface{}) {
|
||||
std.Warnln(args...)
|
||||
}
|
||||
|
||||
// Warningln logs a message at level Warn on the standard logger.
|
||||
func Warningln(args ...interface{}) {
|
||||
std.Warningln(args...)
|
||||
}
|
||||
|
||||
// Errorln logs a message at level Error on the standard logger.
|
||||
func Errorln(args ...interface{}) {
|
||||
std.Errorln(args...)
|
||||
}
|
||||
|
||||
// Panicln logs a message at level Panic on the standard logger.
|
||||
func Panicln(args ...interface{}) {
|
||||
std.Panicln(args...)
|
||||
}
|
||||
|
||||
// Fatalln logs a message at level Fatal on the standard logger.
|
||||
func Fatalln(args ...interface{}) {
|
||||
std.Fatalln(args...)
|
||||
}
|
45
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
45
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import "time"
|
||||
|
||||
const DefaultTimestampFormat = time.RFC3339
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
//
|
||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||
// * `entry.Data["time"]`. The timestamp.
|
||||
// * `entry.Data["level"]. The level the entry was logged at.
|
||||
//
|
||||
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||
// logged to `logger.Out`.
|
||||
type Formatter interface {
|
||||
Format(*Entry) ([]byte, error)
|
||||
}
|
||||
|
||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||
// dumping it. If this code wasn't there doing:
|
||||
//
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
//
|
||||
// Would just silently drop the user provided level. Instead with this code
|
||||
// it'll logged as:
|
||||
//
|
||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
//
|
||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
// avoid code duplication between the two default formatters.
|
||||
func prefixFieldClashes(data Fields) {
|
||||
if t, ok := data["time"]; ok {
|
||||
data["fields.time"] = t
|
||||
}
|
||||
|
||||
if m, ok := data["msg"]; ok {
|
||||
data["fields.msg"] = m
|
||||
}
|
||||
|
||||
if l, ok := data["level"]; ok {
|
||||
data["fields.level"] = l
|
||||
}
|
||||
}
|
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package logrus
|
||||
|
||||
// A hook to be fired when logging on the logging levels returned from
|
||||
// `Levels()` on your implementation of the interface. Note that this is not
|
||||
// fired in a goroutine or a channel with workers, you should handle such
|
||||
// functionality yourself if your call is non-blocking and you don't wish for
|
||||
// the logging calls for levels returned from `Levels()` to block.
|
||||
type Hook interface {
|
||||
Levels() []Level
|
||||
Fire(*Entry) error
|
||||
}
|
||||
|
||||
// Internal type for storing the hooks on a logger instance.
|
||||
type LevelHooks map[Level][]Hook
|
||||
|
||||
// Add a hook to an instance of logger. This is called with
|
||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||
func (hooks LevelHooks) Add(hook Hook) {
|
||||
for _, level := range hook.Levels() {
|
||||
hooks[level] = append(hooks[level], hook)
|
||||
}
|
||||
}
|
||||
|
||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||
// appropriate hooks for a log entry.
|
||||
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
||||
for _, hook := range hooks[level] {
|
||||
if err := hook.Fire(entry); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
41
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
41
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
@ -1,41 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type JSONFormatter struct {
|
||||
// TimestampFormat sets the format used for marshaling timestamps.
|
||||
TimestampFormat string
|
||||
}
|
||||
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+3)
|
||||
for k, v := range entry.Data {
|
||||
switch v := v.(type) {
|
||||
case error:
|
||||
// Otherwise errors are ignored by `encoding/json`
|
||||
// https://github.com/Sirupsen/logrus/issues/137
|
||||
data[k] = v.Error()
|
||||
default:
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
prefixFieldClashes(data)
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
}
|
||||
|
||||
data["time"] = entry.Time.Format(timestampFormat)
|
||||
data["msg"] = entry.Message
|
||||
data["level"] = entry.Level.String()
|
||||
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
}
|
212
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
212
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
@ -1,212 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||
// something more adventorous, such as logging to Kafka.
|
||||
Out io.Writer
|
||||
// Hooks for the logger instance. These allow firing events based on logging
|
||||
// levels and log entries. For example, to send errors to an error tracking
|
||||
// service, log to StatsD or dump the core on fatal errors.
|
||||
Hooks LevelHooks
|
||||
// All log entries pass through the formatter before logged to Out. The
|
||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||
// own that implements the `Formatter` interface, see the `README` or included
|
||||
// formatters for examples.
|
||||
Formatter Formatter
|
||||
// The logging level the logger should log at. This is typically (and defaults
|
||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
// logged. `logrus.Debug` is useful in
|
||||
Level Level
|
||||
// Used to sync writing to the log.
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||
// instantiate your own:
|
||||
//
|
||||
// var log = &Logger{
|
||||
// Out: os.Stderr,
|
||||
// Formatter: new(JSONFormatter),
|
||||
// Hooks: make(LevelHooks),
|
||||
// Level: logrus.DebugLevel,
|
||||
// }
|
||||
//
|
||||
// It's recommended to make this a global instance called `log`.
|
||||
func New() *Logger {
|
||||
return &Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: new(TextFormatter),
|
||||
Hooks: make(LevelHooks),
|
||||
Level: InfoLevel,
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a field to the log entry, note that you it doesn't log until you call
|
||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||
// If you want multiple fields, use `WithFields`.
|
||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||
return NewEntry(logger).WithField(key, value)
|
||||
}
|
||||
|
||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||
// each `Field`.
|
||||
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||
return NewEntry(logger).WithFields(fields)
|
||||
}
|
||||
|
||||
// Add an error as single field to the log entry. All it does is call
|
||||
// `WithError` for the given `error`.
|
||||
func (logger *Logger) WithError(err error) *Entry {
|
||||
return NewEntry(logger).WithError(err)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
NewEntry(logger).Debugf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
NewEntry(logger).Infof(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
NewEntry(logger).Printf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
NewEntry(logger).Errorf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
NewEntry(logger).Fatalf(format, args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
NewEntry(logger).Panicf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
NewEntry(logger).Debug(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
NewEntry(logger).Info(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Print(args ...interface{}) {
|
||||
NewEntry(logger).Info(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warn(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warn(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
NewEntry(logger).Error(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
NewEntry(logger).Fatal(args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
NewEntry(logger).Panic(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
NewEntry(logger).Debugln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
NewEntry(logger).Infoln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Println(args ...interface{}) {
|
||||
NewEntry(logger).Println(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
NewEntry(logger).Warnln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
NewEntry(logger).Errorln(args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
NewEntry(logger).Fatalln(args...)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
NewEntry(logger).Panicln(args...)
|
||||
}
|
||||
}
|
143
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
143
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
@ -1,143 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Fields type, used to pass to `WithFields`.
|
||||
type Fields map[string]interface{}
|
||||
|
||||
// Level type
|
||||
type Level uint8
|
||||
|
||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||
func (level Level) String() string {
|
||||
switch level {
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warning"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
func ParseLevel(lvl string) (Level, error) {
|
||||
switch strings.ToLower(lvl) {
|
||||
case "panic":
|
||||
return PanicLevel, nil
|
||||
case "fatal":
|
||||
return FatalLevel, nil
|
||||
case "error":
|
||||
return ErrorLevel, nil
|
||||
case "warn", "warning":
|
||||
return WarnLevel, nil
|
||||
case "info":
|
||||
return InfoLevel, nil
|
||||
case "debug":
|
||||
return DebugLevel, nil
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
}
|
||||
|
||||
// A constant exposing all logging levels
|
||||
var AllLevels = []Level{
|
||||
PanicLevel,
|
||||
FatalLevel,
|
||||
ErrorLevel,
|
||||
WarnLevel,
|
||||
InfoLevel,
|
||||
DebugLevel,
|
||||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
// on your instance of logger, obtained with `logrus.New()`.
|
||||
const (
|
||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
// message passed to Debug, Info, ...
|
||||
PanicLevel Level = iota
|
||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||
// logging level is set to Panic.
|
||||
FatalLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
// Commonly used for hooks to send errors to an error tracking service.
|
||||
ErrorLevel
|
||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||
WarnLevel
|
||||
// InfoLevel level. General operational entries about what's going on inside the
|
||||
// application.
|
||||
InfoLevel
|
||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
DebugLevel
|
||||
)
|
||||
|
||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||
var (
|
||||
_ StdLogger = &log.Logger{}
|
||||
_ StdLogger = &Entry{}
|
||||
_ StdLogger = &Logger{}
|
||||
)
|
||||
|
||||
// StdLogger is what your logrus-enabled library should take, that way
|
||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||
// interface, this is the closest we get, unfortunately.
|
||||
type StdLogger interface {
|
||||
Print(...interface{})
|
||||
Printf(string, ...interface{})
|
||||
Println(...interface{})
|
||||
|
||||
Fatal(...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
Fatalln(...interface{})
|
||||
|
||||
Panic(...interface{})
|
||||
Panicf(string, ...interface{})
|
||||
Panicln(...interface{})
|
||||
}
|
||||
|
||||
// The FieldLogger interface generalizes the Entry and Logger types
|
||||
type FieldLogger interface {
|
||||
WithField(key string, value interface{}) *Entry
|
||||
WithFields(fields Fields) *Entry
|
||||
WithError(err error) *Entry
|
||||
|
||||
Debugf(format string, args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Printf(format string, args ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warningf(format string, args ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Fatalf(format string, args ...interface{})
|
||||
Panicf(format string, args ...interface{})
|
||||
|
||||
Debug(args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Print(args ...interface{})
|
||||
Warn(args ...interface{})
|
||||
Warning(args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Fatal(args ...interface{})
|
||||
Panic(args ...interface{})
|
||||
|
||||
Debugln(args ...interface{})
|
||||
Infoln(args ...interface{})
|
||||
Println(args ...interface{})
|
||||
Warnln(args ...interface{})
|
||||
Warningln(args ...interface{})
|
||||
Errorln(args ...interface{})
|
||||
Fatalln(args ...interface{})
|
||||
Panicln(args ...interface{})
|
||||
}
|
9
vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
9
vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
@ -1,9 +0,0 @@
|
||||
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
12
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
12
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
|
||||
type Termios syscall.Termios
|
21
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
21
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
@ -1,21 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
fd := syscall.Stderr
|
||||
var termios Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
15
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
15
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
@ -1,15 +0,0 @@
|
||||
// +build solaris
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
|
||||
return err == nil
|
||||
}
|
27
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
27
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
@ -1,27 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
)
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal() bool {
|
||||
fd := syscall.Stderr
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
161
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
161
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
@ -1,161 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
nocolor = 0
|
||||
red = 31
|
||||
green = 32
|
||||
yellow = 33
|
||||
blue = 34
|
||||
gray = 37
|
||||
)
|
||||
|
||||
var (
|
||||
baseTimestamp time.Time
|
||||
isTerminal bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseTimestamp = time.Now()
|
||||
isTerminal = IsTerminal()
|
||||
}
|
||||
|
||||
func miniTS() int {
|
||||
return int(time.Since(baseTimestamp) / time.Second)
|
||||
}
|
||||
|
||||
type TextFormatter struct {
|
||||
// Set to true to bypass checking for a TTY before outputting colors.
|
||||
ForceColors bool
|
||||
|
||||
// Force disabling colors.
|
||||
DisableColors bool
|
||||
|
||||
// Disable timestamp logging. useful when output is redirected to logging
|
||||
// system that already adds timestamps.
|
||||
DisableTimestamp bool
|
||||
|
||||
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||
// the time passed since beginning of execution.
|
||||
FullTimestamp bool
|
||||
|
||||
// TimestampFormat to use for display when a full timestamp is printed
|
||||
TimestampFormat string
|
||||
|
||||
// The fields are sorted by default for a consistent output. For applications
|
||||
// that log extremely frequently and don't use the JSON formatter this may not
|
||||
// be desired.
|
||||
DisableSorting bool
|
||||
}
|
||||
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
var keys []string = make([]string, 0, len(entry.Data))
|
||||
for k := range entry.Data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if !f.DisableSorting {
|
||||
sort.Strings(keys)
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
prefixFieldClashes(entry.Data)
|
||||
|
||||
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
||||
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
}
|
||||
if isColored {
|
||||
f.printColored(b, entry, keys, timestampFormat)
|
||||
} else {
|
||||
if !f.DisableTimestamp {
|
||||
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||
}
|
||||
f.appendKeyValue(b, "level", entry.Level.String())
|
||||
if entry.Message != "" {
|
||||
f.appendKeyValue(b, "msg", entry.Message)
|
||||
}
|
||||
for _, key := range keys {
|
||||
f.appendKeyValue(b, key, entry.Data[key])
|
||||
}
|
||||
}
|
||||
|
||||
b.WriteByte('\n')
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||
var levelColor int
|
||||
switch entry.Level {
|
||||
case DebugLevel:
|
||||
levelColor = gray
|
||||
case WarnLevel:
|
||||
levelColor = yellow
|
||||
case ErrorLevel, FatalLevel, PanicLevel:
|
||||
levelColor = red
|
||||
default:
|
||||
levelColor = blue
|
||||
}
|
||||
|
||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||
|
||||
if !f.FullTimestamp {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||
} else {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||
}
|
||||
for _, k := range keys {
|
||||
v := entry.Data[k]
|
||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func needsQuoting(text string) bool {
|
||||
for _, ch := range text {
|
||||
if !((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
ch == '-' || ch == '.') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||
|
||||
b.WriteString(key)
|
||||
b.WriteByte('=')
|
||||
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if !needsQuoting(value) {
|
||||
b.WriteString(value)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%q", value)
|
||||
}
|
||||
case error:
|
||||
errmsg := value.Error()
|
||||
if !needsQuoting(errmsg) {
|
||||
b.WriteString(errmsg)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%q", value)
|
||||
}
|
||||
default:
|
||||
fmt.Fprint(b, value)
|
||||
}
|
||||
|
||||
b.WriteByte(' ')
|
||||
}
|
53
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
53
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func (logger *Logger) Writer() *io.PipeWriter {
|
||||
return logger.WriterLevel(InfoLevel)
|
||||
}
|
||||
|
||||
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
|
||||
reader, writer := io.Pipe()
|
||||
|
||||
var printFunc func(args ...interface{})
|
||||
switch level {
|
||||
case DebugLevel:
|
||||
printFunc = logger.Debug
|
||||
case InfoLevel:
|
||||
printFunc = logger.Info
|
||||
case WarnLevel:
|
||||
printFunc = logger.Warn
|
||||
case ErrorLevel:
|
||||
printFunc = logger.Error
|
||||
case FatalLevel:
|
||||
printFunc = logger.Fatal
|
||||
case PanicLevel:
|
||||
printFunc = logger.Panic
|
||||
default:
|
||||
printFunc = logger.Print
|
||||
}
|
||||
|
||||
go logger.writerScanner(reader, printFunc)
|
||||
runtime.SetFinalizer(writer, writerFinalizer)
|
||||
|
||||
return writer
|
||||
}
|
||||
|
||||
func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
for scanner.Scan() {
|
||||
printFunc(scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
logger.Errorf("Error while reading from Writer: %s", err)
|
||||
}
|
||||
reader.Close()
|
||||
}
|
||||
|
||||
func writerFinalizer(writer *io.PipeWriter) {
|
||||
writer.Close()
|
||||
}
|
26
vendor/github.com/amfranz/go-xmlrpc-client/error.go
generated
vendored
Normal file
26
vendor/github.com/amfranz/go-xmlrpc-client/error.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Error represents errors returned on xmlrpc request.
|
||||
type Error struct {
|
||||
code string
|
||||
message string
|
||||
}
|
||||
|
||||
// Error() method implements Error interface
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("Error: \"%s\" Code: %s", e.message, e.code)
|
||||
}
|
||||
|
||||
// Code ...
|
||||
func (e *Error) Code() string {
|
||||
return e.code
|
||||
}
|
||||
|
||||
// Message ...
|
||||
func (e *Error) Message() string {
|
||||
return e.message
|
||||
}
|
@ -34,7 +34,7 @@ func parseFailedResponse(response []byte) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
return &(xmlrpcError{
|
||||
return &(Error{
|
||||
code: fmt.Sprintf("%v", faultDetails["faultCode"]),
|
||||
message: faultDetails["faultString"].(string),
|
||||
})
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
// TIME_LAYOUT defines time template defined by iso8601, used to encode/decode time values.
|
||||
const TIME_LAYOUT = "20060102T15:04:05"
|
||||
const TIME_LAYOUT_iso8601Z = "20060102T15:04:05Z07:00"
|
||||
|
||||
func parseValue(valueXml []byte) (result interface{}, err error) {
|
||||
parser := xml.NewDecoder(bytes.NewReader(valueXml))
|
||||
@ -90,7 +91,9 @@ func getDateValue(parser *xml.Decoder) (result interface{}, err error) {
|
||||
var value string
|
||||
value, err = getElementValue(parser)
|
||||
result, err = time.Parse(TIME_LAYOUT, value)
|
||||
|
||||
if err != nil {
|
||||
result, err = time.Parse(TIME_LAYOUT_iso8601Z, value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
12
vendor/github.com/amfranz/go-xmlrpc-client/xmlrpc.go
generated
vendored
Normal file
12
vendor/github.com/amfranz/go-xmlrpc-client/xmlrpc.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package xmlrpc
|
||||
|
||||
// Struct presents hash type used in xmlprc requests and responses.
|
||||
type Struct map[string]interface{}
|
||||
|
||||
// Base64 represents base64 data
|
||||
type Base64 string
|
||||
|
||||
// Params represents a list of parameters to a method.
|
||||
type Params struct {
|
||||
Params []interface{}
|
||||
}
|
2
vendor/github.com/hashicorp/go-version/constraint.go
generated
vendored
2
vendor/github.com/hashicorp/go-version/constraint.go
generated
vendored
@ -37,7 +37,7 @@ func init() {
|
||||
}
|
||||
|
||||
ops := make([]string, 0, len(constraintOperators))
|
||||
for k := range constraintOperators {
|
||||
for k, _ := range constraintOperators {
|
||||
ops = append(ops, regexp.QuoteMeta(k))
|
||||
}
|
||||
|
||||
|
19
vendor/github.com/kolo/xmlrpc/LICENSE
generated
vendored
Normal file
19
vendor/github.com/kolo/xmlrpc/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (C) 2012 Dmitry Maksimov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
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 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.
|
90
vendor/github.com/kolo/xmlrpc/README.md
generated
vendored
Normal file
90
vendor/github.com/kolo/xmlrpc/README.md
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
[](https://godoc.org/github.com/kolo/xmlrpc)
|
||||
|
||||
## Overview
|
||||
|
||||
xmlrpc is an implementation of client side part of XMLRPC protocol in Go language.
|
||||
|
||||
## Status
|
||||
|
||||
This project is in minimal maintenance mode with no further development. Bug fixes
|
||||
are accepted, but it might take some time until they will be merged.
|
||||
|
||||
## Installation
|
||||
|
||||
To install xmlrpc package run `go get github.com/kolo/xmlrpc`. To use
|
||||
it in application add `"github.com/kolo/xmlrpc"` string to `import`
|
||||
statement.
|
||||
|
||||
## Usage
|
||||
|
||||
client, _ := xmlrpc.NewClient("https://bugzilla.mozilla.org/xmlrpc.cgi", nil)
|
||||
result := struct{
|
||||
Version string `xmlrpc:"version"`
|
||||
}{}
|
||||
client.Call("Bugzilla.version", nil, &result)
|
||||
fmt.Printf("Version: %s\n", result.Version) // Version: 4.2.7+
|
||||
|
||||
Second argument of NewClient function is an object that implements
|
||||
[http.RoundTripper](http://golang.org/pkg/net/http/#RoundTripper)
|
||||
interface, it can be used to get more control over connection options.
|
||||
By default it initialized by http.DefaultTransport object.
|
||||
|
||||
### Arguments encoding
|
||||
|
||||
xmlrpc package supports encoding of native Go data types to method
|
||||
arguments.
|
||||
|
||||
Data types encoding rules:
|
||||
|
||||
* int, int8, int16, int32, int64 encoded to int;
|
||||
* float32, float64 encoded to double;
|
||||
* bool encoded to boolean;
|
||||
* string encoded to string;
|
||||
* time.Time encoded to datetime.iso8601;
|
||||
* xmlrpc.Base64 encoded to base64;
|
||||
* slice encoded to array;
|
||||
|
||||
Structs encoded to struct by following rules:
|
||||
|
||||
* all public field become struct members;
|
||||
* field name become member name;
|
||||
* if field has xmlrpc tag, its value become member name.
|
||||
* for fields tagged with `",omitempty"`, empty values are omitted;
|
||||
|
||||
Server method can accept few arguments, to handle this case there is
|
||||
special approach to handle slice of empty interfaces (`[]interface{}`).
|
||||
Each value of such slice encoded as separate argument.
|
||||
|
||||
### Result decoding
|
||||
|
||||
Result of remote function is decoded to native Go data type.
|
||||
|
||||
Data types decoding rules:
|
||||
|
||||
* int, i4 decoded to int, int8, int16, int32, int64;
|
||||
* double decoded to float32, float64;
|
||||
* boolean decoded to bool;
|
||||
* string decoded to string;
|
||||
* array decoded to slice;
|
||||
* structs decoded following the rules described in previous section;
|
||||
* datetime.iso8601 decoded as time.Time data type;
|
||||
* base64 decoded to string.
|
||||
|
||||
## Implementation details
|
||||
|
||||
xmlrpc package contains clientCodec type, that implements [rpc.ClientCodec](http://golang.org/pkg/net/rpc/#ClientCodec)
|
||||
interface of [net/rpc](http://golang.org/pkg/net/rpc) package.
|
||||
|
||||
xmlrpc package works over HTTP protocol, but some internal functions
|
||||
and data type were made public to make it easier to create another
|
||||
implementation of xmlrpc that works over another protocol. To encode
|
||||
request body there is EncodeMethodCall function. To decode server
|
||||
response Response data type can be used.
|
||||
|
||||
## Contribution
|
||||
|
||||
See [project status](#status).
|
||||
|
||||
## Authors
|
||||
|
||||
Dmitry Maksimov (dmtmax@gmail.com)
|
161
vendor/github.com/kolo/xmlrpc/client.go
generated
vendored
Normal file
161
vendor/github.com/kolo/xmlrpc/client.go
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/rpc"
|
||||
"net/url"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
*rpc.Client
|
||||
}
|
||||
|
||||
// clientCodec is rpc.ClientCodec interface implementation.
|
||||
type clientCodec struct {
|
||||
// url presents url of xmlrpc service
|
||||
url *url.URL
|
||||
|
||||
// httpClient works with HTTP protocol
|
||||
httpClient *http.Client
|
||||
|
||||
// cookies stores cookies received on last request
|
||||
cookies http.CookieJar
|
||||
|
||||
// responses presents map of active requests. It is required to return request id, that
|
||||
// rpc.Client can mark them as done.
|
||||
responses map[uint64]*http.Response
|
||||
mutex sync.Mutex
|
||||
|
||||
response Response
|
||||
|
||||
// ready presents channel, that is used to link request and it`s response.
|
||||
ready chan uint64
|
||||
|
||||
// close notifies codec is closed.
|
||||
close chan uint64
|
||||
}
|
||||
|
||||
func (codec *clientCodec) WriteRequest(request *rpc.Request, args interface{}) (err error) {
|
||||
httpRequest, err := NewRequest(codec.url.String(), request.ServiceMethod, args)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if codec.cookies != nil {
|
||||
for _, cookie := range codec.cookies.Cookies(codec.url) {
|
||||
httpRequest.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
|
||||
var httpResponse *http.Response
|
||||
httpResponse, err = codec.httpClient.Do(httpRequest)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if codec.cookies != nil {
|
||||
codec.cookies.SetCookies(codec.url, httpResponse.Cookies())
|
||||
}
|
||||
|
||||
codec.mutex.Lock()
|
||||
codec.responses[request.Seq] = httpResponse
|
||||
codec.mutex.Unlock()
|
||||
|
||||
codec.ready <- request.Seq
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *clientCodec) ReadResponseHeader(response *rpc.Response) (err error) {
|
||||
var seq uint64
|
||||
select {
|
||||
case seq = <-codec.ready:
|
||||
case <-codec.close:
|
||||
return errors.New("codec is closed")
|
||||
}
|
||||
response.Seq = seq
|
||||
|
||||
codec.mutex.Lock()
|
||||
httpResponse := codec.responses[seq]
|
||||
delete(codec.responses, seq)
|
||||
codec.mutex.Unlock()
|
||||
|
||||
defer httpResponse.Body.Close()
|
||||
|
||||
if httpResponse.StatusCode < 200 || httpResponse.StatusCode >= 300 {
|
||||
response.Error = fmt.Sprintf("request error: bad status code - %d", httpResponse.StatusCode)
|
||||
return nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(httpResponse.Body)
|
||||
if err != nil {
|
||||
response.Error = err.Error()
|
||||
return nil
|
||||
}
|
||||
|
||||
resp := Response(body)
|
||||
if err := resp.Err(); err != nil {
|
||||
response.Error = err.Error()
|
||||
return nil
|
||||
}
|
||||
|
||||
codec.response = resp
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *clientCodec) ReadResponseBody(v interface{}) (err error) {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return codec.response.Unmarshal(v)
|
||||
}
|
||||
|
||||
func (codec *clientCodec) Close() error {
|
||||
if transport, ok := codec.httpClient.Transport.(*http.Transport); ok {
|
||||
transport.CloseIdleConnections()
|
||||
}
|
||||
|
||||
close(codec.close)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClient returns instance of rpc.Client object, that is used to send request to xmlrpc service.
|
||||
func NewClient(requrl string, transport http.RoundTripper) (*Client, error) {
|
||||
if transport == nil {
|
||||
transport = http.DefaultTransport
|
||||
}
|
||||
|
||||
httpClient := &http.Client{Transport: transport}
|
||||
|
||||
jar, err := cookiejar.New(nil)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := url.Parse(requrl)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
codec := clientCodec{
|
||||
url: u,
|
||||
httpClient: httpClient,
|
||||
close: make(chan uint64),
|
||||
ready: make(chan uint64),
|
||||
responses: make(map[uint64]*http.Response),
|
||||
cookies: jar,
|
||||
}
|
||||
|
||||
return &Client{rpc.NewClientWithCodec(&codec)}, nil
|
||||
}
|
473
vendor/github.com/kolo/xmlrpc/decoder.go
generated
vendored
Normal file
473
vendor/github.com/kolo/xmlrpc/decoder.go
generated
vendored
Normal file
@ -0,0 +1,473 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
iso8601 = "20060102T15:04:05"
|
||||
iso8601Z = "20060102T15:04:05Z07:00"
|
||||
iso8601Hyphen = "2006-01-02T15:04:05"
|
||||
iso8601HyphenZ = "2006-01-02T15:04:05Z07:00"
|
||||
)
|
||||
|
||||
var (
|
||||
// CharsetReader is a function to generate reader which converts a non UTF-8
|
||||
// charset into UTF-8.
|
||||
CharsetReader func(string, io.Reader) (io.Reader, error)
|
||||
|
||||
timeLayouts = []string{iso8601, iso8601Z, iso8601Hyphen, iso8601HyphenZ}
|
||||
invalidXmlError = errors.New("invalid xml")
|
||||
)
|
||||
|
||||
type TypeMismatchError string
|
||||
|
||||
func (e TypeMismatchError) Error() string { return string(e) }
|
||||
|
||||
type decoder struct {
|
||||
*xml.Decoder
|
||||
}
|
||||
|
||||
func unmarshal(data []byte, v interface{}) (err error) {
|
||||
dec := &decoder{xml.NewDecoder(bytes.NewBuffer(data))}
|
||||
|
||||
if CharsetReader != nil {
|
||||
dec.CharsetReader = CharsetReader
|
||||
}
|
||||
|
||||
var tok xml.Token
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
if t.Name.Local == "value" {
|
||||
val := reflect.ValueOf(v)
|
||||
if val.Kind() != reflect.Ptr {
|
||||
return errors.New("non-pointer value passed to unmarshal")
|
||||
}
|
||||
if err = dec.decodeValue(val.Elem()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read until end of document
|
||||
err = dec.Skip()
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *decoder) decodeValue(val reflect.Value) error {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
val.Set(reflect.New(val.Type().Elem()))
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
var typeName string
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.EndElement); ok {
|
||||
if t.Name.Local == "value" {
|
||||
return nil
|
||||
} else {
|
||||
return invalidXmlError
|
||||
}
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
typeName = t.Name.Local
|
||||
break
|
||||
}
|
||||
|
||||
// Treat value data without type identifier as string
|
||||
if t, ok := tok.(xml.CharData); ok {
|
||||
if value := strings.TrimSpace(string(t)); value != "" {
|
||||
if err = checkType(val, reflect.String); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetString(value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch typeName {
|
||||
case "struct":
|
||||
ismap := false
|
||||
pmap := val
|
||||
valType := val.Type()
|
||||
|
||||
if err = checkType(val, reflect.Struct); err != nil {
|
||||
if checkType(val, reflect.Map) == nil {
|
||||
if valType.Key().Kind() != reflect.String {
|
||||
return fmt.Errorf("only maps with string key type can be unmarshalled")
|
||||
}
|
||||
ismap = true
|
||||
} else if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
var dummy map[string]interface{}
|
||||
valType = reflect.TypeOf(dummy)
|
||||
pmap = reflect.New(valType).Elem()
|
||||
val.Set(pmap)
|
||||
ismap = true
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var fields map[string]reflect.Value
|
||||
|
||||
if !ismap {
|
||||
fields = make(map[string]reflect.Value)
|
||||
|
||||
for i := 0; i < valType.NumField(); i++ {
|
||||
field := valType.Field(i)
|
||||
fieldVal := val.FieldByName(field.Name)
|
||||
|
||||
if fieldVal.CanSet() {
|
||||
if fn := field.Tag.Get("xmlrpc"); fn != "" {
|
||||
fields[fn] = fieldVal
|
||||
} else {
|
||||
fields[field.Name] = fieldVal
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create initial empty map
|
||||
pmap.Set(reflect.MakeMap(valType))
|
||||
}
|
||||
|
||||
// Process struct members.
|
||||
StructLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if t.Name.Local != "member" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
tagName, fieldName, err := dec.readTag()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tagName != "name" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
var fv reflect.Value
|
||||
ok := true
|
||||
|
||||
if !ismap {
|
||||
fv, ok = fields[string(fieldName)]
|
||||
} else {
|
||||
fv = reflect.New(valType.Elem())
|
||||
}
|
||||
|
||||
if ok {
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
if t, ok := tok.(xml.StartElement); ok && t.Name.Local == "value" {
|
||||
if err = dec.decodeValue(fv); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// </value>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// </member>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ismap {
|
||||
pmap.SetMapIndex(reflect.ValueOf(string(fieldName)), reflect.Indirect(fv))
|
||||
val.Set(pmap)
|
||||
}
|
||||
case xml.EndElement:
|
||||
break StructLoop
|
||||
}
|
||||
}
|
||||
case "array":
|
||||
slice := val
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
slice = reflect.ValueOf([]interface{}{})
|
||||
} else if err = checkType(val, reflect.Slice); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ArrayLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
var index int
|
||||
if t.Name.Local != "data" {
|
||||
return invalidXmlError
|
||||
}
|
||||
DataLoop:
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch tt := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if tt.Name.Local != "value" {
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
if index < slice.Len() {
|
||||
v := slice.Index(index)
|
||||
if v.Kind() == reflect.Interface {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return errors.New("error: cannot write to non-pointer array element")
|
||||
}
|
||||
if err = dec.decodeValue(v); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
v := reflect.New(slice.Type().Elem())
|
||||
if err = dec.decodeValue(v); err != nil {
|
||||
return err
|
||||
}
|
||||
slice = reflect.Append(slice, v.Elem())
|
||||
}
|
||||
|
||||
// </value>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
index++
|
||||
case xml.EndElement:
|
||||
val.Set(slice)
|
||||
break DataLoop
|
||||
}
|
||||
}
|
||||
case xml.EndElement:
|
||||
break ArrayLoop
|
||||
}
|
||||
}
|
||||
default:
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data []byte
|
||||
|
||||
switch t := tok.(type) {
|
||||
case xml.EndElement:
|
||||
return nil
|
||||
case xml.CharData:
|
||||
data = []byte(t.Copy())
|
||||
default:
|
||||
return invalidXmlError
|
||||
}
|
||||
|
||||
switch typeName {
|
||||
case "int", "i4", "i8":
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
i, err := strconv.ParseInt(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pi := reflect.New(reflect.TypeOf(i)).Elem()
|
||||
pi.SetInt(i)
|
||||
val.Set(pi)
|
||||
} else if err = checkType(val, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i, err := strconv.ParseInt(string(data), 10, val.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetInt(i)
|
||||
}
|
||||
case "string", "base64":
|
||||
str := string(data)
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
pstr := reflect.New(reflect.TypeOf(str)).Elem()
|
||||
pstr.SetString(str)
|
||||
val.Set(pstr)
|
||||
} else if err = checkType(val, reflect.String); err != nil {
|
||||
return err
|
||||
} else {
|
||||
val.SetString(str)
|
||||
}
|
||||
case "dateTime.iso8601":
|
||||
var t time.Time
|
||||
var err error
|
||||
|
||||
for _, layout := range timeLayouts {
|
||||
t, err = time.Parse(layout, string(data))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
ptime := reflect.New(reflect.TypeOf(t)).Elem()
|
||||
ptime.Set(reflect.ValueOf(t))
|
||||
val.Set(ptime)
|
||||
} else if _, ok := val.Interface().(time.Time); !ok {
|
||||
return TypeMismatchError(fmt.Sprintf("error: type mismatch error - can't decode %v to time", val.Kind()))
|
||||
} else {
|
||||
val.Set(reflect.ValueOf(t))
|
||||
}
|
||||
case "boolean":
|
||||
v, err := strconv.ParseBool(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
pv := reflect.New(reflect.TypeOf(v)).Elem()
|
||||
pv.SetBool(v)
|
||||
val.Set(pv)
|
||||
} else if err = checkType(val, reflect.Bool); err != nil {
|
||||
return err
|
||||
} else {
|
||||
val.SetBool(v)
|
||||
}
|
||||
case "double":
|
||||
if checkType(val, reflect.Interface) == nil && val.IsNil() {
|
||||
i, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pdouble := reflect.New(reflect.TypeOf(i)).Elem()
|
||||
pdouble.SetFloat(i)
|
||||
val.Set(pdouble)
|
||||
} else if err = checkType(val, reflect.Float32, reflect.Float64); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i, err := strconv.ParseFloat(string(data), val.Type().Bits())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.SetFloat(i)
|
||||
}
|
||||
default:
|
||||
return errors.New("unsupported type")
|
||||
}
|
||||
|
||||
// </type>
|
||||
if err = dec.Skip(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *decoder) readTag() (string, []byte, error) {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
var name string
|
||||
for {
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.StartElement); ok {
|
||||
name = t.Name.Local
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
value, err := dec.readCharData()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return name, value, dec.Skip()
|
||||
}
|
||||
|
||||
func (dec *decoder) readCharData() ([]byte, error) {
|
||||
var tok xml.Token
|
||||
var err error
|
||||
|
||||
if tok, err = dec.Token(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t, ok := tok.(xml.CharData); ok {
|
||||
return []byte(t.Copy()), nil
|
||||
} else {
|
||||
return nil, invalidXmlError
|
||||
}
|
||||
}
|
||||
|
||||
func checkType(val reflect.Value, kinds ...reflect.Kind) error {
|
||||
if len(kinds) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
match := false
|
||||
|
||||
for _, kind := range kinds {
|
||||
if val.Kind() == kind {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
return TypeMismatchError(fmt.Sprintf("error: type mismatch - can't unmarshal %v to %v",
|
||||
val.Kind(), kinds[0]))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
181
vendor/github.com/kolo/xmlrpc/encoder.go
generated
vendored
Normal file
181
vendor/github.com/kolo/xmlrpc/encoder.go
generated
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Base64 represents value in base64 encoding
|
||||
type Base64 string
|
||||
|
||||
type encodeFunc func(reflect.Value) ([]byte, error)
|
||||
|
||||
func marshal(v interface{}) ([]byte, error) {
|
||||
if v == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
val := reflect.ValueOf(v)
|
||||
return encodeValue(val)
|
||||
}
|
||||
|
||||
func encodeValue(val reflect.Value) ([]byte, error) {
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
if val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface {
|
||||
if val.IsNil() {
|
||||
return []byte("<value/>"), nil
|
||||
}
|
||||
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
switch val.Kind() {
|
||||
case reflect.Struct:
|
||||
switch val.Interface().(type) {
|
||||
case time.Time:
|
||||
t := val.Interface().(time.Time)
|
||||
b = []byte(fmt.Sprintf("<dateTime.iso8601>%s</dateTime.iso8601>", t.Format(iso8601)))
|
||||
default:
|
||||
b, err = encodeStruct(val)
|
||||
}
|
||||
case reflect.Map:
|
||||
b, err = encodeMap(val)
|
||||
case reflect.Slice:
|
||||
b, err = encodeSlice(val)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
b = []byte(fmt.Sprintf("<int>%s</int>", strconv.FormatInt(val.Int(), 10)))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
b = []byte(fmt.Sprintf("<i4>%s</i4>", strconv.FormatUint(val.Uint(), 10)))
|
||||
case reflect.Float32, reflect.Float64:
|
||||
b = []byte(fmt.Sprintf("<double>%s</double>",
|
||||
strconv.FormatFloat(val.Float(), 'f', -1, val.Type().Bits())))
|
||||
case reflect.Bool:
|
||||
if val.Bool() {
|
||||
b = []byte("<boolean>1</boolean>")
|
||||
} else {
|
||||
b = []byte("<boolean>0</boolean>")
|
||||
}
|
||||
case reflect.String:
|
||||
var buf bytes.Buffer
|
||||
|
||||
xml.Escape(&buf, []byte(val.String()))
|
||||
|
||||
if _, ok := val.Interface().(Base64); ok {
|
||||
b = []byte(fmt.Sprintf("<base64>%s</base64>", buf.String()))
|
||||
} else {
|
||||
b = []byte(fmt.Sprintf("<string>%s</string>", buf.String()))
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("xmlrpc encode error: unsupported type")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []byte(fmt.Sprintf("<value>%s</value>", string(b))), nil
|
||||
}
|
||||
|
||||
func encodeStruct(structVal reflect.Value) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<struct>")
|
||||
|
||||
structType := structVal.Type()
|
||||
for i := 0; i < structType.NumField(); i++ {
|
||||
fieldVal := structVal.Field(i)
|
||||
fieldType := structType.Field(i)
|
||||
|
||||
name := fieldType.Tag.Get("xmlrpc")
|
||||
// if the tag has the omitempty property, skip it
|
||||
if strings.HasSuffix(name, ",omitempty") && isZero(fieldVal) {
|
||||
continue
|
||||
}
|
||||
name = strings.TrimSuffix(name, ",omitempty")
|
||||
if name == "" {
|
||||
name = fieldType.Name
|
||||
}
|
||||
|
||||
p, err := encodeValue(fieldVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.WriteString("<member>")
|
||||
b.WriteString(fmt.Sprintf("<name>%s</name>", name))
|
||||
b.Write(p)
|
||||
b.WriteString("</member>")
|
||||
}
|
||||
|
||||
b.WriteString("</struct>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
var sortMapKeys bool
|
||||
|
||||
func encodeMap(val reflect.Value) ([]byte, error) {
|
||||
var t = val.Type()
|
||||
|
||||
if t.Key().Kind() != reflect.String {
|
||||
return nil, fmt.Errorf("xmlrpc encode error: only maps with string keys are supported")
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<struct>")
|
||||
|
||||
keys := val.MapKeys()
|
||||
|
||||
if sortMapKeys {
|
||||
sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() })
|
||||
}
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
key := keys[i]
|
||||
kval := val.MapIndex(key)
|
||||
|
||||
b.WriteString("<member>")
|
||||
b.WriteString(fmt.Sprintf("<name>%s</name>", key.String()))
|
||||
|
||||
p, err := encodeValue(kval)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.Write(p)
|
||||
b.WriteString("</member>")
|
||||
}
|
||||
|
||||
b.WriteString("</struct>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func encodeSlice(val reflect.Value) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
|
||||
b.WriteString("<array><data>")
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
p, err := encodeValue(val.Index(i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.Write(p)
|
||||
}
|
||||
|
||||
b.WriteString("</data></array>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
44
vendor/github.com/kolo/xmlrpc/is_zero.go
generated
vendored
Normal file
44
vendor/github.com/kolo/xmlrpc/is_zero.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"math"
|
||||
. "reflect"
|
||||
)
|
||||
|
||||
func isZero(v Value) bool {
|
||||
switch v.Kind() {
|
||||
case Bool:
|
||||
return !v.Bool()
|
||||
case Int, Int8, Int16, Int32, Int64:
|
||||
return v.Int() == 0
|
||||
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return v.Uint() == 0
|
||||
case Float32, Float64:
|
||||
return math.Float64bits(v.Float()) == 0
|
||||
case Complex64, Complex128:
|
||||
c := v.Complex()
|
||||
return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
|
||||
case Array:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
if !isZero(v.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case Chan, Func, Interface, Map, Ptr, Slice, UnsafePointer:
|
||||
return v.IsNil()
|
||||
case String:
|
||||
return v.Len() == 0
|
||||
case Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if !isZero(v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
// This should never happens, but will act as a safeguard for
|
||||
// later, as a default value doesn't makes sense here.
|
||||
panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
|
||||
}
|
||||
}
|
57
vendor/github.com/kolo/xmlrpc/request.go
generated
vendored
Normal file
57
vendor/github.com/kolo/xmlrpc/request.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func NewRequest(url string, method string, args interface{}) (*http.Request, error) {
|
||||
var t []interface{}
|
||||
var ok bool
|
||||
if t, ok = args.([]interface{}); !ok {
|
||||
if args != nil {
|
||||
t = []interface{}{args}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := EncodeMethodCall(method, t...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request.Header.Set("Content-Type", "text/xml")
|
||||
request.Header.Set("Content-Length", fmt.Sprintf("%d", len(body)))
|
||||
|
||||
return request, nil
|
||||
}
|
||||
|
||||
func EncodeMethodCall(method string, args ...interface{}) ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
b.WriteString(`<?xml version="1.0" encoding="UTF-8"?>`)
|
||||
b.WriteString(fmt.Sprintf("<methodCall><methodName>%s</methodName>", method))
|
||||
|
||||
if args != nil {
|
||||
b.WriteString("<params>")
|
||||
|
||||
for _, arg := range args {
|
||||
p, err := marshal(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.WriteString(fmt.Sprintf("<param>%s</param>", string(p)))
|
||||
}
|
||||
|
||||
b.WriteString("</params>")
|
||||
}
|
||||
|
||||
b.WriteString("</methodCall>")
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
42
vendor/github.com/kolo/xmlrpc/response.go
generated
vendored
Normal file
42
vendor/github.com/kolo/xmlrpc/response.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
faultRx = regexp.MustCompile(`<fault>(\s|\S)+</fault>`)
|
||||
)
|
||||
|
||||
// FaultError is returned from the server when an invalid call is made
|
||||
type FaultError struct {
|
||||
Code int `xmlrpc:"faultCode"`
|
||||
String string `xmlrpc:"faultString"`
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (e FaultError) Error() string {
|
||||
return fmt.Sprintf("Fault(%d): %s", e.Code, e.String)
|
||||
}
|
||||
|
||||
type Response []byte
|
||||
|
||||
func (r Response) Err() error {
|
||||
if !faultRx.Match(r) {
|
||||
return nil
|
||||
}
|
||||
var fault FaultError
|
||||
if err := unmarshal(r, &fault); err != nil {
|
||||
return err
|
||||
}
|
||||
return fault
|
||||
}
|
||||
|
||||
func (r Response) Unmarshal(v interface{}) error {
|
||||
if err := unmarshal(r, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
25
vendor/github.com/kolo/xmlrpc/test_server.rb
generated
vendored
Normal file
25
vendor/github.com/kolo/xmlrpc/test_server.rb
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
# encoding: utf-8
|
||||
|
||||
require "xmlrpc/server"
|
||||
|
||||
class Service
|
||||
def time
|
||||
Time.now
|
||||
end
|
||||
|
||||
def upcase(s)
|
||||
s.upcase
|
||||
end
|
||||
|
||||
def sum(x, y)
|
||||
x + y
|
||||
end
|
||||
|
||||
def error
|
||||
raise XMLRPC::FaultException.new(500, "Server error")
|
||||
end
|
||||
end
|
||||
|
||||
server = XMLRPC::Server.new 5001, 'localhost'
|
||||
server.add_handler "service", Service.new
|
||||
server.serve
|
3
vendor/github.com/masterzen/simplexml/dom/element.go
generated
vendored
3
vendor/github.com/masterzen/simplexml/dom/element.go
generated
vendored
@ -1,9 +1,9 @@
|
||||
package dom
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type Attr struct {
|
||||
@ -192,6 +192,7 @@ func (node *Element) namespacePrefix(uri string) string {
|
||||
return node.parent.namespacePrefix(uri)
|
||||
}
|
||||
|
||||
|
||||
func (node *Element) String() string {
|
||||
var b bytes.Buffer
|
||||
node.Bytes(&b, false, "", 0)
|
||||
|
4
vendor/github.com/mitchellh/go-fs/fat/directory_cluster.go
generated
vendored
4
vendor/github.com/mitchellh/go-fs/fat/directory_cluster.go
generated
vendored
@ -125,7 +125,7 @@ func NewDirectoryCluster(start uint32, parent uint32, t time.Time) *DirectoryClu
|
||||
|
||||
// Create the "." and ".." entries
|
||||
cluster.entries = []*DirectoryClusterEntry{
|
||||
{
|
||||
&DirectoryClusterEntry{
|
||||
accessTime: t,
|
||||
attr: AttrDirectory,
|
||||
cluster: start,
|
||||
@ -133,7 +133,7 @@ func NewDirectoryCluster(start uint32, parent uint32, t time.Time) *DirectoryClu
|
||||
name: ".",
|
||||
writeTime: t,
|
||||
},
|
||||
{
|
||||
&DirectoryClusterEntry{
|
||||
accessTime: t,
|
||||
attr: AttrDirectory,
|
||||
cluster: parent,
|
||||
|
4
vendor/github.com/mitchellh/go-fs/fat/short_name.go
generated
vendored
4
vendor/github.com/mitchellh/go-fs/fat/short_name.go
generated
vendored
@ -30,11 +30,11 @@ func generateShortName(longName string, used []string) (string, error) {
|
||||
if dotIdx == -1 {
|
||||
dotIdx = len(longName)
|
||||
} else {
|
||||
ext = longName[dotIdx+1:]
|
||||
ext = longName[dotIdx+1 : len(longName)]
|
||||
}
|
||||
|
||||
ext = cleanShortString(ext)
|
||||
ext = ext[0:]
|
||||
ext = ext[0:len(ext)]
|
||||
rawName := longName[0:dotIdx]
|
||||
name := cleanShortString(rawName)
|
||||
simpleName := fmt.Sprintf("%s.%s", name, ext)
|
||||
|
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Simon Eskildsen
|
||||
Copyright (c) 2013 Mitchell Hashimoto
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
16
vendor/github.com/mitchellh/go-vnc/README.md
generated
vendored
Normal file
16
vendor/github.com/mitchellh/go-vnc/README.md
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# VNC Library for Go
|
||||
|
||||
go-vnc is a VNC library for Go, initially supporting VNC clients but
|
||||
with the goal of eventually implementing a VNC server.
|
||||
|
||||
This library implements [RFC 6143](http://tools.ietf.org/html/rfc6143).
|
||||
|
||||
## Usage & Installation
|
||||
|
||||
The library is installable via standard `go get`. The package name is `vnc`.
|
||||
|
||||
```
|
||||
$ go get github.com/mitchellh/go-vnc
|
||||
```
|
||||
|
||||
Documentation is available on GoDoc: http://godoc.org/github.com/mitchellh/go-vnc
|
482
vendor/github.com/mitchellh/go-vnc/client.go
generated
vendored
Normal file
482
vendor/github.com/mitchellh/go-vnc/client.go
generated
vendored
Normal file
@ -0,0 +1,482 @@
|
||||
// Package vnc implements a VNC client.
|
||||
//
|
||||
// References:
|
||||
// [PROTOCOL]: http://tools.ietf.org/html/rfc6143
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type ClientConn struct {
|
||||
c net.Conn
|
||||
config *ClientConfig
|
||||
|
||||
// If the pixel format uses a color map, then this is the color
|
||||
// map that is used. This should not be modified directly, since
|
||||
// the data comes from the server.
|
||||
ColorMap [256]Color
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings should be used.
|
||||
Encs []Encoding
|
||||
|
||||
// Width of the frame buffer in pixels, sent from the server.
|
||||
FrameBufferWidth uint16
|
||||
|
||||
// Height of the frame buffer in pixels, sent from the server.
|
||||
FrameBufferHeight uint16
|
||||
|
||||
// Name associated with the desktop, sent from the server.
|
||||
DesktopName string
|
||||
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
PixelFormat PixelFormat
|
||||
}
|
||||
|
||||
// A ClientConfig structure is used to configure a ClientConn. After
|
||||
// one has been passed to initialize a connection, it must not be modified.
|
||||
type ClientConfig struct {
|
||||
// A slice of ClientAuth methods. Only the first instance that is
|
||||
// suitable by the server will be used to authenticate.
|
||||
Auth []ClientAuth
|
||||
|
||||
// Exclusive determines whether the connection is shared with other
|
||||
// clients. If true, then all other clients connected will be
|
||||
// disconnected when a connection is established to the VNC server.
|
||||
Exclusive bool
|
||||
|
||||
// The channel that all messages received from the server will be
|
||||
// sent on. If the channel blocks, then the goroutine reading data
|
||||
// from the VNC server may block indefinitely. It is up to the user
|
||||
// of the library to ensure that this channel is properly read.
|
||||
// If this is not set, then all messages will be discarded.
|
||||
ServerMessageCh chan<- ServerMessage
|
||||
|
||||
// A slice of supported messages that can be read from the server.
|
||||
// This only needs to contain NEW server messages, and doesn't
|
||||
// need to explicitly contain the RFC-required messages.
|
||||
ServerMessages []ServerMessage
|
||||
}
|
||||
|
||||
func Client(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||
conn := &ClientConn{
|
||||
c: c,
|
||||
config: cfg,
|
||||
}
|
||||
|
||||
if err := conn.handshake(); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go conn.mainLoop()
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *ClientConn) Close() error {
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
// CutText tells the server that the client has new text in its cut buffer.
|
||||
// The text string MUST only contain Latin-1 characters. This encoding
|
||||
// is compatible with Go's native string format, but can only use up to
|
||||
// unicode.MaxLatin values.
|
||||
//
|
||||
// See RFC 6143 Section 7.5.6
|
||||
func (c *ClientConn) CutText(text string) error {
|
||||
var buf bytes.Buffer
|
||||
|
||||
// This is the fixed size data we'll send
|
||||
fixedData := []interface{}{
|
||||
uint8(6),
|
||||
uint8(0),
|
||||
uint8(0),
|
||||
uint8(0),
|
||||
uint32(len(text)),
|
||||
}
|
||||
|
||||
for _, val := range fixedData {
|
||||
if err := binary.Write(&buf, binary.BigEndian, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, char := range text {
|
||||
if char > unicode.MaxLatin1 {
|
||||
return fmt.Errorf("Character '%s' is not valid Latin-1", char)
|
||||
}
|
||||
|
||||
if err := binary.Write(&buf, binary.BigEndian, uint8(char)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dataLength := 8 + len(text)
|
||||
if _, err := c.c.Write(buf.Bytes()[0:dataLength]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Requests a framebuffer update from the server. There may be an indefinite
|
||||
// time between the request and the actual framebuffer update being
|
||||
// received.
|
||||
//
|
||||
// See RFC 6143 Section 7.5.3
|
||||
func (c *ClientConn) FramebufferUpdateRequest(incremental bool, x, y, width, height uint16) error {
|
||||
var buf bytes.Buffer
|
||||
var incrementalByte uint8 = 0
|
||||
|
||||
if incremental {
|
||||
incrementalByte = 1
|
||||
}
|
||||
|
||||
data := []interface{}{
|
||||
uint8(3),
|
||||
incrementalByte,
|
||||
x, y, width, height,
|
||||
}
|
||||
|
||||
for _, val := range data {
|
||||
if err := binary.Write(&buf, binary.BigEndian, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := c.c.Write(buf.Bytes()[0:10]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// KeyEvent indiciates a key press or release and sends it to the server.
|
||||
// The key is indicated using the X Window System "keysym" value. Use
|
||||
// Google to find a reference of these values. To simulate a key press,
|
||||
// you must send a key with both a down event, and a non-down event.
|
||||
//
|
||||
// See 7.5.4.
|
||||
func (c *ClientConn) KeyEvent(keysym uint32, down bool) error {
|
||||
var downFlag uint8 = 0
|
||||
if down {
|
||||
downFlag = 1
|
||||
}
|
||||
|
||||
data := []interface{}{
|
||||
uint8(4),
|
||||
downFlag,
|
||||
uint8(0),
|
||||
uint8(0),
|
||||
keysym,
|
||||
}
|
||||
|
||||
for _, val := range data {
|
||||
if err := binary.Write(c.c, binary.BigEndian, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PointerEvent indicates that pointer movement or a pointer button
|
||||
// press or release.
|
||||
//
|
||||
// The mask is a bitwise mask of various ButtonMask values. When a button
|
||||
// is set, it is pressed, when it is unset, it is released.
|
||||
//
|
||||
// See RFC 6143 Section 7.5.5
|
||||
func (c *ClientConn) PointerEvent(mask ButtonMask, x, y uint16) error {
|
||||
var buf bytes.Buffer
|
||||
|
||||
data := []interface{}{
|
||||
uint8(5),
|
||||
uint8(mask),
|
||||
x,
|
||||
y,
|
||||
}
|
||||
|
||||
for _, val := range data {
|
||||
if err := binary.Write(&buf, binary.BigEndian, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := c.c.Write(buf.Bytes()[0:6]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetEncodings sets the encoding types in which the pixel data can
|
||||
// be sent from the server. After calling this method, the encs slice
|
||||
// given should not be modified.
|
||||
//
|
||||
// See RFC 6143 Section 7.5.2
|
||||
func (c *ClientConn) SetEncodings(encs []Encoding) error {
|
||||
data := make([]interface{}, 3+len(encs))
|
||||
data[0] = uint8(2)
|
||||
data[1] = uint8(0)
|
||||
data[2] = uint16(len(encs))
|
||||
|
||||
for i, enc := range encs {
|
||||
data[3+i] = int32(enc.Type())
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
for _, val := range data {
|
||||
if err := binary.Write(&buf, binary.BigEndian, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dataLength := 4 + (4 * len(encs))
|
||||
if _, err := c.c.Write(buf.Bytes()[0:dataLength]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Encs = encs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPixelFormat sets the format in which pixel values should be sent
|
||||
// in FramebufferUpdate messages from the server.
|
||||
//
|
||||
// See RFC 6143 Section 7.5.1
|
||||
func (c *ClientConn) SetPixelFormat(format *PixelFormat) error {
|
||||
var keyEvent [20]byte
|
||||
keyEvent[0] = 0
|
||||
|
||||
pfBytes, err := writePixelFormat(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy the pixel format bytes into the proper slice location
|
||||
copy(keyEvent[4:], pfBytes)
|
||||
|
||||
// Send the data down the connection
|
||||
if _, err := c.c.Write(keyEvent[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Reset the color map as according to RFC.
|
||||
var newColorMap [256]Color
|
||||
c.ColorMap = newColorMap
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const pvLen = 12 // ProtocolVersion message length.
|
||||
|
||||
func parseProtocolVersion(pv []byte) (uint, uint, error) {
|
||||
var major, minor uint
|
||||
|
||||
if len(pv) < pvLen {
|
||||
return 0, 0, fmt.Errorf("ProtocolVersion message too short (%v < %v)", len(pv), pvLen)
|
||||
}
|
||||
|
||||
l, err := fmt.Sscanf(string(pv), "RFB %d.%d\n", &major, &minor)
|
||||
if l != 2 {
|
||||
return 0, 0, fmt.Errorf("error parsing ProtocolVersion.")
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return major, minor, nil
|
||||
}
|
||||
|
||||
func (c *ClientConn) handshake() error {
|
||||
var protocolVersion [pvLen]byte
|
||||
|
||||
// 7.1.1, read the ProtocolVersion message sent by the server.
|
||||
if _, err := io.ReadFull(c.c, protocolVersion[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maxMajor, maxMinor, err := parseProtocolVersion(protocolVersion[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maxMajor < 3 {
|
||||
return fmt.Errorf("unsupported major version, less than 3: %d", maxMajor)
|
||||
}
|
||||
if maxMinor < 8 {
|
||||
return fmt.Errorf("unsupported minor version, less than 8: %d", maxMinor)
|
||||
}
|
||||
|
||||
// Respond with the version we will support
|
||||
if _, err = c.c.Write([]byte("RFB 003.008\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 7.1.2 Security Handshake from server
|
||||
var numSecurityTypes uint8
|
||||
if err = binary.Read(c.c, binary.BigEndian, &numSecurityTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if numSecurityTypes == 0 {
|
||||
return fmt.Errorf("no security types: %s", c.readErrorReason())
|
||||
}
|
||||
|
||||
securityTypes := make([]uint8, numSecurityTypes)
|
||||
if err = binary.Read(c.c, binary.BigEndian, &securityTypes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientSecurityTypes := c.config.Auth
|
||||
if clientSecurityTypes == nil {
|
||||
clientSecurityTypes = []ClientAuth{new(ClientAuthNone)}
|
||||
}
|
||||
|
||||
var auth ClientAuth
|
||||
FindAuth:
|
||||
for _, curAuth := range clientSecurityTypes {
|
||||
for _, securityType := range securityTypes {
|
||||
if curAuth.SecurityType() == securityType {
|
||||
// We use the first matching supported authentication
|
||||
auth = curAuth
|
||||
break FindAuth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if auth == nil {
|
||||
return fmt.Errorf("no suitable auth schemes found. server supported: %#v", securityTypes)
|
||||
}
|
||||
|
||||
// Respond back with the security type we'll use
|
||||
if err = binary.Write(c.c, binary.BigEndian, auth.SecurityType()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = auth.Handshake(c.c); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 7.1.3 SecurityResult Handshake
|
||||
var securityResult uint32
|
||||
if err = binary.Read(c.c, binary.BigEndian, &securityResult); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if securityResult == 1 {
|
||||
return fmt.Errorf("security handshake failed: %s", c.readErrorReason())
|
||||
}
|
||||
|
||||
// 7.3.1 ClientInit
|
||||
var sharedFlag uint8 = 1
|
||||
if c.config.Exclusive {
|
||||
sharedFlag = 0
|
||||
}
|
||||
|
||||
if err = binary.Write(c.c, binary.BigEndian, sharedFlag); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 7.3.2 ServerInit
|
||||
if err = binary.Read(c.c, binary.BigEndian, &c.FrameBufferWidth); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = binary.Read(c.c, binary.BigEndian, &c.FrameBufferHeight); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read the pixel format
|
||||
if err = readPixelFormat(c.c, &c.PixelFormat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var nameLength uint32
|
||||
if err = binary.Read(c.c, binary.BigEndian, &nameLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nameBytes := make([]uint8, nameLength)
|
||||
if err = binary.Read(c.c, binary.BigEndian, &nameBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.DesktopName = string(nameBytes)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mainLoop reads messages sent from the server and routes them to the
|
||||
// proper channels for users of the client to read.
|
||||
func (c *ClientConn) mainLoop() {
|
||||
defer c.Close()
|
||||
|
||||
// Build the map of available server messages
|
||||
typeMap := make(map[uint8]ServerMessage)
|
||||
|
||||
defaultMessages := []ServerMessage{
|
||||
new(FramebufferUpdateMessage),
|
||||
new(SetColorMapEntriesMessage),
|
||||
new(BellMessage),
|
||||
new(ServerCutTextMessage),
|
||||
}
|
||||
|
||||
for _, msg := range defaultMessages {
|
||||
typeMap[msg.Type()] = msg
|
||||
}
|
||||
|
||||
if c.config.ServerMessages != nil {
|
||||
for _, msg := range c.config.ServerMessages {
|
||||
typeMap[msg.Type()] = msg
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
var messageType uint8
|
||||
if err := binary.Read(c.c, binary.BigEndian, &messageType); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
msg, ok := typeMap[messageType]
|
||||
if !ok {
|
||||
// Unsupported message type! Bad!
|
||||
break
|
||||
}
|
||||
|
||||
parsedMsg, err := msg.Read(c, c.c)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if c.config.ServerMessageCh == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
c.config.ServerMessageCh <- parsedMsg
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClientConn) readErrorReason() string {
|
||||
var reasonLen uint32
|
||||
if err := binary.Read(c.c, binary.BigEndian, &reasonLen); err != nil {
|
||||
return "<error>"
|
||||
}
|
||||
|
||||
reason := make([]uint8, reasonLen)
|
||||
if err := binary.Read(c.c, binary.BigEndian, &reason); err != nil {
|
||||
return "<error>"
|
||||
}
|
||||
|
||||
return string(reason)
|
||||
}
|
124
vendor/github.com/mitchellh/go-vnc/client_auth.go
generated
vendored
Normal file
124
vendor/github.com/mitchellh/go-vnc/client_auth.go
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"crypto/des"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// A ClientAuth implements a method of authenticating with a remote server.
|
||||
type ClientAuth interface {
|
||||
// SecurityType returns the byte identifier sent by the server to
|
||||
// identify this authentication scheme.
|
||||
SecurityType() uint8
|
||||
|
||||
// Handshake is called when the authentication handshake should be
|
||||
// performed, as part of the general RFB handshake. (see 7.2.1)
|
||||
Handshake(net.Conn) error
|
||||
}
|
||||
|
||||
// ClientAuthNone is the "none" authentication. See 7.2.1
|
||||
type ClientAuthNone byte
|
||||
|
||||
func (*ClientAuthNone) SecurityType() uint8 {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (*ClientAuthNone) Handshake(net.Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PasswordAuth is VNC authentication, 7.2.2
|
||||
type PasswordAuth struct {
|
||||
Password string
|
||||
}
|
||||
|
||||
func (p *PasswordAuth) SecurityType() uint8 {
|
||||
return 2
|
||||
}
|
||||
|
||||
func (p *PasswordAuth) Handshake(c net.Conn) error {
|
||||
randomValue := make([]uint8, 16)
|
||||
if err := binary.Read(c, binary.BigEndian, &randomValue); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
crypted, err := p.encrypt(p.Password, randomValue)
|
||||
|
||||
if (err != nil) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, &crypted); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PasswordAuth) reverseBits(b byte) byte {
|
||||
var reverse = [256]int{
|
||||
0, 128, 64, 192, 32, 160, 96, 224,
|
||||
16, 144, 80, 208, 48, 176, 112, 240,
|
||||
8, 136, 72, 200, 40, 168, 104, 232,
|
||||
24, 152, 88, 216, 56, 184, 120, 248,
|
||||
4, 132, 68, 196, 36, 164, 100, 228,
|
||||
20, 148, 84, 212, 52, 180, 116, 244,
|
||||
12, 140, 76, 204, 44, 172, 108, 236,
|
||||
28, 156, 92, 220, 60, 188, 124, 252,
|
||||
2, 130, 66, 194, 34, 162, 98, 226,
|
||||
18, 146, 82, 210, 50, 178, 114, 242,
|
||||
10, 138, 74, 202, 42, 170, 106, 234,
|
||||
26, 154, 90, 218, 58, 186, 122, 250,
|
||||
6, 134, 70, 198, 38, 166, 102, 230,
|
||||
22, 150, 86, 214, 54, 182, 118, 246,
|
||||
14, 142, 78, 206, 46, 174, 110, 238,
|
||||
30, 158, 94, 222, 62, 190, 126, 254,
|
||||
1, 129, 65, 193, 33, 161, 97, 225,
|
||||
17, 145, 81, 209, 49, 177, 113, 241,
|
||||
9, 137, 73, 201, 41, 169, 105, 233,
|
||||
25, 153, 89, 217, 57, 185, 121, 249,
|
||||
5, 133, 69, 197, 37, 165, 101, 229,
|
||||
21, 149, 85, 213, 53, 181, 117, 245,
|
||||
13, 141, 77, 205, 45, 173, 109, 237,
|
||||
29, 157, 93, 221, 61, 189, 125, 253,
|
||||
3, 131, 67, 195, 35, 163, 99, 227,
|
||||
19, 147, 83, 211, 51, 179, 115, 243,
|
||||
11, 139, 75, 203, 43, 171, 107, 235,
|
||||
27, 155, 91, 219, 59, 187, 123, 251,
|
||||
7, 135, 71, 199, 39, 167, 103, 231,
|
||||
23, 151, 87, 215, 55, 183, 119, 247,
|
||||
15, 143, 79, 207, 47, 175, 111, 239,
|
||||
31, 159, 95, 223, 63, 191, 127, 255,
|
||||
}
|
||||
|
||||
return byte(reverse[int(b)])
|
||||
}
|
||||
|
||||
func (p *PasswordAuth) encrypt(key string, bytes []byte) ([]byte, error) {
|
||||
keyBytes := []byte{0,0,0,0,0,0,0,0}
|
||||
|
||||
if len(key) > 8 {
|
||||
key = key[:8]
|
||||
}
|
||||
|
||||
for i := 0; i < len(key); i++ {
|
||||
keyBytes[i] = p.reverseBits(key[i])
|
||||
}
|
||||
|
||||
block, err := des.NewCipher(keyBytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result1 := make([]byte, 8)
|
||||
block.Encrypt(result1, bytes)
|
||||
result2 := make([]byte, 8)
|
||||
block.Encrypt(result2, bytes[8:])
|
||||
|
||||
crypted := append(result1, result2...)
|
||||
|
||||
return crypted, nil
|
||||
}
|
6
vendor/github.com/mitchellh/go-vnc/color.go
generated
vendored
Normal file
6
vendor/github.com/mitchellh/go-vnc/color.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
package vnc
|
||||
|
||||
// Color represents a single color in a color map.
|
||||
type Color struct {
|
||||
R, G, B uint16
|
||||
}
|
69
vendor/github.com/mitchellh/go-vnc/encoding.go
generated
vendored
Normal file
69
vendor/github.com/mitchellh/go-vnc/encoding.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
// An Encoding implements a method for encoding pixel data that is
|
||||
// sent by the server to the client.
|
||||
type Encoding interface {
|
||||
// The number that uniquely identifies this encoding type.
|
||||
Type() int32
|
||||
|
||||
// Read reads the contents of the encoded pixel data from the reader.
|
||||
// This should return a new Encoding implementation that contains
|
||||
// the proper data.
|
||||
Read(*ClientConn, *Rectangle, io.Reader) (Encoding, error)
|
||||
}
|
||||
|
||||
// RawEncoding is raw pixel data sent by the server.
|
||||
//
|
||||
// See RFC 6143 Section 7.7.1
|
||||
type RawEncoding struct {
|
||||
Colors []Color
|
||||
}
|
||||
|
||||
func (*RawEncoding) Type() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
|
||||
bytesPerPixel := c.PixelFormat.BPP / 8
|
||||
pixelBytes := make([]uint8, bytesPerPixel)
|
||||
|
||||
var byteOrder binary.ByteOrder = binary.LittleEndian
|
||||
if c.PixelFormat.BigEndian {
|
||||
byteOrder = binary.BigEndian
|
||||
}
|
||||
|
||||
colors := make([]Color, int(rect.Height)*int(rect.Width))
|
||||
|
||||
for y := uint16(0); y < rect.Height; y++ {
|
||||
for x := uint16(0); x < rect.Width; x++ {
|
||||
if _, err := io.ReadFull(r, pixelBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rawPixel uint32
|
||||
if c.PixelFormat.BPP == 8 {
|
||||
rawPixel = uint32(pixelBytes[0])
|
||||
} else if c.PixelFormat.BPP == 16 {
|
||||
rawPixel = uint32(byteOrder.Uint16(pixelBytes))
|
||||
} else if c.PixelFormat.BPP == 32 {
|
||||
rawPixel = byteOrder.Uint32(pixelBytes)
|
||||
}
|
||||
|
||||
color := &colors[int(y)*int(rect.Width)+int(x)]
|
||||
if c.PixelFormat.TrueColor {
|
||||
color.R = uint16((rawPixel >> c.PixelFormat.RedShift) & uint32(c.PixelFormat.RedMax))
|
||||
color.G = uint16((rawPixel >> c.PixelFormat.GreenShift) & uint32(c.PixelFormat.GreenMax))
|
||||
color.B = uint16((rawPixel >> c.PixelFormat.BlueShift) & uint32(c.PixelFormat.BlueMax))
|
||||
} else {
|
||||
*color = c.ColorMap[rawPixel]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &RawEncoding{colors}, nil
|
||||
}
|
151
vendor/github.com/mitchellh/go-vnc/pixel_format.go
generated
vendored
Normal file
151
vendor/github.com/mitchellh/go-vnc/pixel_format.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
// PixelFormat describes the way a pixel is formatted for a VNC connection.
|
||||
//
|
||||
// See RFC 6143 Section 7.4 for information on each of the fields.
|
||||
type PixelFormat struct {
|
||||
BPP uint8
|
||||
Depth uint8
|
||||
BigEndian bool
|
||||
TrueColor bool
|
||||
RedMax uint16
|
||||
GreenMax uint16
|
||||
BlueMax uint16
|
||||
RedShift uint8
|
||||
GreenShift uint8
|
||||
BlueShift uint8
|
||||
}
|
||||
|
||||
func readPixelFormat(r io.Reader, result *PixelFormat) error {
|
||||
var rawPixelFormat [16]byte
|
||||
if _, err := io.ReadFull(r, rawPixelFormat[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pfBoolByte uint8
|
||||
brPF := bytes.NewReader(rawPixelFormat[:])
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.BPP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.Depth); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if pfBoolByte != 0 {
|
||||
// Big endian is true
|
||||
result.BigEndian = true
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if pfBoolByte != 0 {
|
||||
// True Color is true. So we also have to read all the color max & shifts.
|
||||
result.TrueColor = true
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.RedMax); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.GreenMax); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.BlueMax); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.RedShift); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.GreenShift); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(brPF, binary.BigEndian, &result.BlueShift); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writePixelFormat(format *PixelFormat) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Byte 1
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.BPP); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Byte 2
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.Depth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var boolByte byte
|
||||
if format.BigEndian {
|
||||
boolByte = 1
|
||||
} else {
|
||||
boolByte = 0
|
||||
}
|
||||
|
||||
// Byte 3 (BigEndian)
|
||||
if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if format.TrueColor {
|
||||
boolByte = 1
|
||||
} else {
|
||||
boolByte = 0
|
||||
}
|
||||
|
||||
// Byte 4 (TrueColor)
|
||||
if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If we have true color enabled then we have to fill in the rest of the
|
||||
// structure with the color values.
|
||||
if format.TrueColor {
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.RedMax); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.GreenMax); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.BlueMax); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.RedShift); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.GreenShift); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := binary.Write(&buf, binary.BigEndian, format.BlueShift); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return buf.Bytes()[0:16], nil
|
||||
}
|
16
vendor/github.com/mitchellh/go-vnc/pointer.go
generated
vendored
Normal file
16
vendor/github.com/mitchellh/go-vnc/pointer.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package vnc
|
||||
|
||||
// ButtonMask represents a mask of pointer presses/releases.
|
||||
type ButtonMask uint8
|
||||
|
||||
// All available button mask components.
|
||||
const (
|
||||
ButtonLeft ButtonMask = 1 << iota
|
||||
ButtonMiddle
|
||||
ButtonRight
|
||||
Button4
|
||||
Button5
|
||||
Button6
|
||||
Button7
|
||||
Button8
|
||||
)
|
192
vendor/github.com/mitchellh/go-vnc/server_messages.go
generated
vendored
Normal file
192
vendor/github.com/mitchellh/go-vnc/server_messages.go
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A ServerMessage implements a message sent from the server to the client.
|
||||
type ServerMessage interface {
|
||||
// The type of the message that is sent down on the wire.
|
||||
Type() uint8
|
||||
|
||||
// Read reads the contents of the message from the reader. At the point
|
||||
// this is called, the message type has already been read from the reader.
|
||||
// This should return a new ServerMessage that is the appropriate type.
|
||||
Read(*ClientConn, io.Reader) (ServerMessage, error)
|
||||
}
|
||||
|
||||
// FramebufferUpdateMessage consists of a sequence of rectangles of
|
||||
// pixel data that the client should put into its framebuffer.
|
||||
type FramebufferUpdateMessage struct {
|
||||
Rectangles []Rectangle
|
||||
}
|
||||
|
||||
// Rectangle represents a rectangle of pixel data.
|
||||
type Rectangle struct {
|
||||
X uint16
|
||||
Y uint16
|
||||
Width uint16
|
||||
Height uint16
|
||||
Enc Encoding
|
||||
}
|
||||
|
||||
func (*FramebufferUpdateMessage) Type() uint8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (*FramebufferUpdateMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) {
|
||||
// Read off the padding
|
||||
var padding [1]byte
|
||||
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var numRects uint16
|
||||
if err := binary.Read(r, binary.BigEndian, &numRects); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build the map of encodings supported
|
||||
encMap := make(map[int32]Encoding)
|
||||
for _, enc := range c.Encs {
|
||||
encMap[enc.Type()] = enc
|
||||
}
|
||||
|
||||
// We must always support the raw encoding
|
||||
rawEnc := new(RawEncoding)
|
||||
encMap[rawEnc.Type()] = rawEnc
|
||||
|
||||
rects := make([]Rectangle, numRects)
|
||||
for i := uint16(0); i < numRects; i++ {
|
||||
var encodingType int32
|
||||
|
||||
rect := &rects[i]
|
||||
data := []interface{}{
|
||||
&rect.X,
|
||||
&rect.Y,
|
||||
&rect.Width,
|
||||
&rect.Height,
|
||||
&encodingType,
|
||||
}
|
||||
|
||||
for _, val := range data {
|
||||
if err := binary.Read(r, binary.BigEndian, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
enc, ok := encMap[encodingType]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported encoding type: %d", encodingType)
|
||||
}
|
||||
|
||||
var err error
|
||||
rect.Enc, err = enc.Read(c, rect, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &FramebufferUpdateMessage{rects}, nil
|
||||
}
|
||||
|
||||
// SetColorMapEntriesMessage is sent by the server to set values into
|
||||
// the color map. This message will automatically update the color map
|
||||
// for the associated connection, but contains the color change data
|
||||
// if the consumer wants to read it.
|
||||
//
|
||||
// See RFC 6143 Section 7.6.2
|
||||
type SetColorMapEntriesMessage struct {
|
||||
FirstColor uint16
|
||||
Colors []Color
|
||||
}
|
||||
|
||||
func (*SetColorMapEntriesMessage) Type() uint8 {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (*SetColorMapEntriesMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) {
|
||||
// Read off the padding
|
||||
var padding [1]byte
|
||||
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result SetColorMapEntriesMessage
|
||||
if err := binary.Read(r, binary.BigEndian, &result.FirstColor); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var numColors uint16
|
||||
if err := binary.Read(r, binary.BigEndian, &numColors); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Colors = make([]Color, numColors)
|
||||
for i := uint16(0); i < numColors; i++ {
|
||||
|
||||
color := &result.Colors[i]
|
||||
data := []interface{}{
|
||||
&color.R,
|
||||
&color.G,
|
||||
&color.B,
|
||||
}
|
||||
|
||||
for _, val := range data {
|
||||
if err := binary.Read(r, binary.BigEndian, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Update the connection's color map
|
||||
c.ColorMap[result.FirstColor+i] = *color
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// Bell signals that an audible bell should be made on the client.
|
||||
//
|
||||
// See RFC 6143 Section 7.6.3
|
||||
type BellMessage byte
|
||||
|
||||
func (*BellMessage) Type() uint8 {
|
||||
return 2
|
||||
}
|
||||
|
||||
func (*BellMessage) Read(*ClientConn, io.Reader) (ServerMessage, error) {
|
||||
return new(BellMessage), nil
|
||||
}
|
||||
|
||||
// ServerCutTextMessage indicates the server has new text in the cut buffer.
|
||||
//
|
||||
// See RFC 6143 Section 7.6.4
|
||||
type ServerCutTextMessage struct {
|
||||
Text string
|
||||
}
|
||||
|
||||
func (*ServerCutTextMessage) Type() uint8 {
|
||||
return 3
|
||||
}
|
||||
|
||||
func (*ServerCutTextMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) {
|
||||
// Read off the padding
|
||||
var padding [1]byte
|
||||
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var textLength uint32
|
||||
if err := binary.Read(r, binary.BigEndian, &textLength); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
textBytes := make([]uint8, textLength)
|
||||
if err := binary.Read(r, binary.BigEndian, &textBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ServerCutTextMessage{string(textBytes)}, nil
|
||||
}
|
6
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
6
vendor/github.com/mitchellh/mapstructure/mapstructure.go
generated
vendored
@ -653,7 +653,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
||||
if !rawMapVal.IsValid() {
|
||||
// Do a slower search by iterating over each key and
|
||||
// doing case-insensitive search.
|
||||
for dataValKey := range dataValKeys {
|
||||
for dataValKey, _ := range dataValKeys {
|
||||
mK, ok := dataValKey.Interface().(string)
|
||||
if !ok {
|
||||
// Not a string key
|
||||
@ -701,7 +701,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
||||
|
||||
if d.config.ErrorUnused && len(dataValKeysUnused) > 0 {
|
||||
keys := make([]string, 0, len(dataValKeysUnused))
|
||||
for rawKey := range dataValKeysUnused {
|
||||
for rawKey, _ := range dataValKeysUnused {
|
||||
keys = append(keys, rawKey.(string))
|
||||
}
|
||||
sort.Strings(keys)
|
||||
@ -716,7 +716,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
|
||||
|
||||
// Add the unused keys to the list of unused keys if we're tracking metadata
|
||||
if d.config.Metadata != nil {
|
||||
for rawKey := range dataValKeysUnused {
|
||||
for rawKey, _ := range dataValKeysUnused {
|
||||
key := rawKey.(string)
|
||||
if name != "" {
|
||||
key = fmt.Sprintf("%s.%s", name, key)
|
||||
|
20
vendor/github.com/mitchellh/osext/LICENSE
generated
vendored
20
vendor/github.com/mitchellh/osext/LICENSE
generated
vendored
@ -1,20 +0,0 @@
|
||||
Copyright (c) 2012 Daniel Theophanes
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
3
vendor/github.com/mitchellh/osext/README.md
generated
vendored
3
vendor/github.com/mitchellh/osext/README.md
generated
vendored
@ -1,3 +0,0 @@
|
||||
# osext
|
||||
|
||||
**Don't use this anymore! Use the official library at: https://github.com/kardianos/osext**
|
32
vendor/github.com/mitchellh/osext/osext.go
generated
vendored
32
vendor/github.com/mitchellh/osext/osext.go
generated
vendored
@ -1,32 +0,0 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Extensions to the standard "os" package.
|
||||
package osext
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
// Executable returns an absolute path that can be used to
|
||||
// re-invoke the current program.
|
||||
// It may not be valid after the current program exits.
|
||||
func Executable() (string, error) {
|
||||
p, err := executable()
|
||||
return filepath.Clean(p), err
|
||||
}
|
||||
|
||||
// Returns same path as Executable, returns just the folder
|
||||
// path. Excludes the executable name.
|
||||
func ExecutableFolder() (string, error) {
|
||||
p, err := Executable()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
folder, _ := filepath.Split(p)
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
// Depricated. Same as Executable().
|
||||
func GetExePath() (exePath string, err error) {
|
||||
return Executable()
|
||||
}
|
16
vendor/github.com/mitchellh/osext/osext_plan9.go
generated
vendored
16
vendor/github.com/mitchellh/osext/osext_plan9.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package osext
|
||||
|
||||
import "syscall"
|
||||
|
||||
func executable() (string, error) {
|
||||
f, err := Open("/proc/" + itoa(Getpid()) + "/text")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
return syscall.Fd2path(int(f.Fd()))
|
||||
}
|
25
vendor/github.com/mitchellh/osext/osext_procfs.go
generated
vendored
25
vendor/github.com/mitchellh/osext/osext_procfs.go
generated
vendored
@ -1,25 +0,0 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux netbsd openbsd
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func executable() (string, error) {
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
return os.Readlink("/proc/self/exe")
|
||||
case "netbsd":
|
||||
return os.Readlink("/proc/curproc/exe")
|
||||
case "openbsd":
|
||||
return os.Readlink("/proc/curproc/file")
|
||||
}
|
||||
return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
|
||||
}
|
64
vendor/github.com/mitchellh/osext/osext_sysctl.go
generated
vendored
64
vendor/github.com/mitchellh/osext/osext_sysctl.go
generated
vendored
@ -1,64 +0,0 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin freebsd
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var startUpcwd, getwdError = os.Getwd()
|
||||
|
||||
func executable() (string, error) {
|
||||
var mib [4]int32
|
||||
switch runtime.GOOS {
|
||||
case "freebsd":
|
||||
mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
|
||||
case "darwin":
|
||||
mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
|
||||
}
|
||||
|
||||
n := uintptr(0)
|
||||
// get length
|
||||
_, _, err := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
|
||||
if err != 0 {
|
||||
return "", err
|
||||
}
|
||||
if n == 0 { // shouldn't happen
|
||||
return "", nil
|
||||
}
|
||||
buf := make([]byte, n)
|
||||
_, _, err = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
|
||||
if err != 0 {
|
||||
return "", err
|
||||
}
|
||||
if n == 0 { // shouldn't happen
|
||||
return "", nil
|
||||
}
|
||||
for i, v := range buf {
|
||||
if v == 0 {
|
||||
buf = buf[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
if buf[0] != '/' {
|
||||
if getwdError != nil {
|
||||
return string(buf), getwdError
|
||||
} else {
|
||||
if buf[0] == '.' {
|
||||
buf = buf[1:]
|
||||
}
|
||||
if startUpcwd[len(startUpcwd)-1] != '/' {
|
||||
return startUpcwd + "/" + string(buf), nil
|
||||
}
|
||||
return startUpcwd + string(buf), nil
|
||||
}
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
34
vendor/github.com/mitchellh/osext/osext_windows.go
generated
vendored
34
vendor/github.com/mitchellh/osext/osext_windows.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||
getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW")
|
||||
)
|
||||
|
||||
// GetModuleFileName() with hModule = NULL
|
||||
func executable() (exePath string, err error) {
|
||||
return getModuleFileName()
|
||||
}
|
||||
|
||||
func getModuleFileName() (string, error) {
|
||||
var n uint32
|
||||
b := make([]uint16, syscall.MAX_PATH)
|
||||
size := uint32(len(b))
|
||||
|
||||
r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size))
|
||||
n = uint32(r0)
|
||||
if n == 0 {
|
||||
return "", e1
|
||||
}
|
||||
return string(utf16.Decode(b[0:n])), nil
|
||||
}
|
2
vendor/github.com/mitchellh/packer/common/download.go
generated
vendored
2
vendor/github.com/mitchellh/packer/common/download.go
generated
vendored
@ -124,7 +124,7 @@ func (d *DownloadClient) Get() (string, error) {
|
||||
|
||||
// Remove forward slash on absolute Windows file URLs before processing
|
||||
if runtime.GOOS == "windows" && len(finalPath) > 0 && finalPath[0] == '/' {
|
||||
finalPath = finalPath[1:]
|
||||
finalPath = finalPath[1:len(finalPath)]
|
||||
}
|
||||
// Keep track of the source so we can make sure not to delete this later
|
||||
sourcePath = finalPath
|
||||
|
4
vendor/github.com/mitchellh/packer/communicator/ssh/communicator.go
generated
vendored
4
vendor/github.com/mitchellh/packer/communicator/ssh/communicator.go
generated
vendored
@ -175,7 +175,7 @@ func (c *comm) DownloadDir(src string, dst string, excl []string) error {
|
||||
|
||||
switch fi[0] {
|
||||
case '\x01', '\x02':
|
||||
return fmt.Errorf("%s", fi[1:])
|
||||
return fmt.Errorf("%s", fi[1:len(fi)])
|
||||
case 'C', 'D':
|
||||
break
|
||||
default:
|
||||
@ -591,7 +591,7 @@ func (c *comm) scpDownloadSession(path string, output io.Writer) error {
|
||||
|
||||
switch fi[0] {
|
||||
case '\x01', '\x02':
|
||||
return fmt.Errorf("%s", fi[1:])
|
||||
return fmt.Errorf("%s", fi[1:len(fi)])
|
||||
case 'C':
|
||||
case 'D':
|
||||
return fmt.Errorf("remote file is directory")
|
||||
|
2
vendor/github.com/mitchellh/packer/communicator/ssh/password.go
generated
vendored
2
vendor/github.com/mitchellh/packer/communicator/ssh/password.go
generated
vendored
@ -18,7 +18,7 @@ func PasswordKeyboardInteractive(password string) ssh.KeyboardInteractiveChallen
|
||||
|
||||
// Just send the password back for all questions
|
||||
answers := make([]string, len(questions))
|
||||
for i := range answers {
|
||||
for i, _ := range answers {
|
||||
answers[i] = string(password)
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/mitchellh/packer/packer/core.go
generated
vendored
2
vendor/github.com/mitchellh/packer/packer/core.go
generated
vendored
@ -87,7 +87,7 @@ func NewCore(c *CoreConfig) (*Core, error) {
|
||||
// BuildNames returns the builds that are available in this configured core.
|
||||
func (c *Core) BuildNames() []string {
|
||||
r := make([]string, 0, len(c.builds))
|
||||
for n := range c.builds {
|
||||
for n, _ := range c.builds {
|
||||
r = append(r, n)
|
||||
}
|
||||
sort.Strings(r)
|
||||
|
2
vendor/github.com/mitchellh/packer/packer/plugin/client.go
generated
vendored
2
vendor/github.com/mitchellh/packer/packer/plugin/client.go
generated
vendored
@ -291,7 +291,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
// so they dont' block since it is an io.Pipe
|
||||
defer func() {
|
||||
go func() {
|
||||
for range linesCh {
|
||||
for _ = range linesCh {
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
2
vendor/github.com/mitchellh/packer/template/template.go
generated
vendored
2
vendor/github.com/mitchellh/packer/template/template.go
generated
vendored
@ -107,7 +107,7 @@ func (t *Template) Validate() error {
|
||||
}
|
||||
|
||||
// Validate overrides
|
||||
for name := range p.Override {
|
||||
for name, _ := range p.Override {
|
||||
if _, ok := t.Builders[name]; !ok {
|
||||
err = multierror.Append(err, fmt.Errorf(
|
||||
"provisioner %d: override '%s' doesn't exist",
|
||||
|
27
vendor/github.com/nilshell/xmlrpc/xmlrpc.go
generated
vendored
27
vendor/github.com/nilshell/xmlrpc/xmlrpc.go
generated
vendored
@ -1,27 +0,0 @@
|
||||
package xmlrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Struct presents hash type used in xmlprc requests and responses.
|
||||
type Struct map[string]interface{}
|
||||
|
||||
// Base64 represents base64 data
|
||||
type Base64 string
|
||||
|
||||
// Params represents a list of parameters to a method.
|
||||
type Params struct {
|
||||
Params []interface{}
|
||||
}
|
||||
|
||||
// xmlrpcError represents errors returned on xmlrpc request.
|
||||
type xmlrpcError struct {
|
||||
code string
|
||||
message string
|
||||
}
|
||||
|
||||
// Error() method implements Error interface
|
||||
func (e *xmlrpcError) Error() string {
|
||||
return fmt.Sprintf("Error: \"%s\" Code: %s", e.message, e.code)
|
||||
}
|
2
vendor/github.com/packer-community/winrmcp/winrmcp/psobject.go
generated
vendored
2
vendor/github.com/packer-community/winrmcp/winrmcp/psobject.go
generated
vendored
@ -13,3 +13,5 @@ type psproperty struct {
|
||||
Name string `xml:"Name,attr"`
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
|
||||
|
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
@ -1,24 +0,0 @@
|
||||
# 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
|
10
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
10
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
@ -1,10 +0,0 @@
|
||||
language: go
|
||||
go_import_path: github.com/pkg/errors
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.4
|
||||
- 1.6.2
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
@ -1,23 +0,0 @@
|
||||
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
50
vendor/github.com/pkg/errors/README.md
generated
vendored
50
vendor/github.com/pkg/errors/README.md
generated
vendored
@ -1,50 +0,0 @@
|
||||
# errors [](https://travis-ci.org/pkg/errors) [](https://ci.appveyor.com/project/davecheney/errors/branch/master) [](http://godoc.org/github.com/pkg/errors) [](https://goreportcard.com/report/github.com/pkg/errors)
|
||||
|
||||
Package errors provides simple error handling primitives.
|
||||
|
||||
The traditional error handling idiom in Go is roughly akin to
|
||||
```go
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
|
||||
|
||||
## Adding context to an error
|
||||
|
||||
The errors.Wrap function returns a new error that adds context to the original error. For example
|
||||
```go
|
||||
_, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read failed")
|
||||
}
|
||||
```
|
||||
## Retrieving the cause of an error
|
||||
|
||||
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
|
||||
```go
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
```
|
||||
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
|
||||
```go
|
||||
switch err := errors.Cause(err).(type) {
|
||||
case *MyError:
|
||||
// handle specifically
|
||||
default:
|
||||
// unknown error
|
||||
}
|
||||
```
|
||||
|
||||
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
|
||||
|
||||
Before proposing a change, please discuss your change by raising an issue.
|
||||
|
||||
## Licence
|
||||
|
||||
BSD-2-Clause
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user