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()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not destroy VBD '%s': %s", vbd.Ref, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
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, 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"
|
||||
)
|
||||
|
||||
@ -20,10 +20,10 @@ type config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
xscommon.CommonConfig `mapstructure:",squash"`
|
||||
|
||||
SourcePath string `mapstructure:"source_path"`
|
||||
VCPUsMax uint `mapstructure:"vcpus_max"`
|
||||
VCPUsAtStartup uint `mapstructure:"vcpus_atstartup"`
|
||||
VMMemory uint `mapstructure:"vm_memory"`
|
||||
SourcePath string `mapstructure:"source_path"`
|
||||
VCPUsMax uint `mapstructure:"vcpus_max"`
|
||||
VCPUsAtStartup uint `mapstructure:"vcpus_atstartup"`
|
||||
VMMemory uint `mapstructure:"vm_memory"`
|
||||
|
||||
PlatformArgs map[string]string `mapstructure:"platform_args"`
|
||||
|
||||
@ -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:"/> [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](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):
|
||||
|
||||
![Colored](http://i.imgur.com/PY7qMwd.png)
|
||||
|
||||
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 @@
|
||||
[![GoDoc](https://godoc.org/github.com/kolo/xmlrpc?status.svg)](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
|
12
vendor/github.com/masterzen/simplexml/dom/document.go
generated
vendored
12
vendor/github.com/masterzen/simplexml/dom/document.go
generated
vendored
@ -6,14 +6,14 @@ import (
|
||||
)
|
||||
|
||||
type Document struct {
|
||||
root *Element
|
||||
root *Element
|
||||
PrettyPrint bool
|
||||
Indentation string
|
||||
DocType bool
|
||||
DocType bool
|
||||
}
|
||||
|
||||
func CreateDocument() *Document {
|
||||
return &Document{PrettyPrint: false, Indentation: " ", DocType: true}
|
||||
return &Document{ PrettyPrint: false, Indentation: " ", DocType: true }
|
||||
}
|
||||
|
||||
func (doc *Document) SetRoot(node *Element) {
|
||||
@ -26,10 +26,10 @@ func (doc *Document) String() string {
|
||||
if doc.DocType {
|
||||
fmt.Fprintln(&b, `<?xml version="1.0" encoding="utf-8" ?>`)
|
||||
}
|
||||
|
||||
|
||||
if doc.root != nil {
|
||||
doc.root.Bytes(&b, doc.PrettyPrint, doc.Indentation, 0)
|
||||
}
|
||||
|
||||
|
||||
return string(b.Bytes())
|
||||
}
|
||||
}
|
53
vendor/github.com/masterzen/simplexml/dom/element.go
generated
vendored
53
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 {
|
||||
@ -12,20 +12,20 @@ type Attr struct {
|
||||
}
|
||||
|
||||
type Element struct {
|
||||
name xml.Name
|
||||
children []*Element
|
||||
parent *Element
|
||||
content string
|
||||
name xml.Name
|
||||
children []*Element
|
||||
parent *Element
|
||||
content string
|
||||
attributes []*Attr
|
||||
namespaces []*Namespace
|
||||
document *Document
|
||||
document *Document
|
||||
}
|
||||
|
||||
func CreateElement(n string) *Element {
|
||||
element := &Element{name: xml.Name{Local: n}}
|
||||
element := &Element { name: xml.Name { Local: n } }
|
||||
element.children = make([]*Element, 0, 5)
|
||||
element.attributes = make([]*Attr, 0, 10)
|
||||
element.namespaces = make([]*Namespace, 0, 10)
|
||||
element.namespaces = make([]*Namespace, 0, 10)
|
||||
return element
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ func (node *Element) RemoveChild(child *Element) *Element {
|
||||
|
||||
func (node *Element) SetAttr(name string, value string) *Element {
|
||||
// namespaces?
|
||||
attr := &Attr{Name: xml.Name{Local: name}, Value: value}
|
||||
attr := &Attr{ Name: xml.Name { Local: name }, Value: value }
|
||||
node.attributes = append(node.attributes, attr)
|
||||
return node
|
||||
}
|
||||
@ -67,18 +67,18 @@ func (node *Element) SetAttr(name string, value string) *Element {
|
||||
func (node *Element) SetParent(parent *Element) *Element {
|
||||
node.parent = parent
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
func (node *Element) SetContent(content string) *Element {
|
||||
node.content = content
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
// Add a namespace declaration to this node
|
||||
func (node *Element) DeclareNamespace(ns Namespace) *Element {
|
||||
// check if we already have it
|
||||
prefix := node.namespacePrefix(ns.Uri)
|
||||
if prefix == ns.Prefix {
|
||||
if prefix == ns.Prefix {
|
||||
return node
|
||||
}
|
||||
// add it
|
||||
@ -94,7 +94,7 @@ func (node *Element) SetNamespace(prefix string, uri string) {
|
||||
resolved := node.namespacePrefix(uri)
|
||||
if resolved == "" {
|
||||
// we couldn't find the namespace, let's declare it at this node
|
||||
node.namespaces = append(node.namespaces, &Namespace{Prefix: prefix, Uri: uri})
|
||||
node.namespaces = append(node.namespaces, &Namespace { Prefix: prefix, Uri: uri })
|
||||
}
|
||||
node.name.Space = uri
|
||||
}
|
||||
@ -102,19 +102,19 @@ func (node *Element) SetNamespace(prefix string, uri string) {
|
||||
func (node *Element) Bytes(out *bytes.Buffer, indent bool, indentType string, level int) {
|
||||
empty := len(node.children) == 0 && node.content == ""
|
||||
content := node.content != ""
|
||||
// children := len(node.children) > 0
|
||||
// ns := len(node.namespaces) > 0
|
||||
// attrs := len(node.attributes) > 0
|
||||
|
||||
// children := len(node.children) > 0
|
||||
// ns := len(node.namespaces) > 0
|
||||
// attrs := len(node.attributes) > 0
|
||||
|
||||
indentStr := ""
|
||||
nextLine := ""
|
||||
if indent {
|
||||
nextLine = "\n"
|
||||
for i := 0; i < level; i++ {
|
||||
indentStr += indentType
|
||||
indentStr += indentType
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if node.name.Local != "" {
|
||||
if len(node.name.Space) > 0 {
|
||||
// first find if ns has been declared, otherwise
|
||||
@ -124,7 +124,7 @@ func (node *Element) Bytes(out *bytes.Buffer, indent bool, indentType string, le
|
||||
fmt.Fprintf(out, "%s<%s", indentStr, node.name.Local)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// declared namespaces
|
||||
for _, v := range node.namespaces {
|
||||
prefix := node.namespacePrefix(v.Uri)
|
||||
@ -140,7 +140,7 @@ func (node *Element) Bytes(out *bytes.Buffer, indent bool, indentType string, le
|
||||
fmt.Fprintf(out, ` %s="%s"`, v.Name.Local, v.Value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// close tag
|
||||
if empty {
|
||||
fmt.Fprintf(out, "/>%s", nextLine)
|
||||
@ -148,20 +148,20 @@ func (node *Element) Bytes(out *bytes.Buffer, indent bool, indentType string, le
|
||||
if content {
|
||||
out.WriteRune('>')
|
||||
} else {
|
||||
fmt.Fprintf(out, ">%s", nextLine)
|
||||
fmt.Fprintf(out, ">%s", nextLine)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if len(node.children) > 0 {
|
||||
for _, child := range node.children {
|
||||
child.Bytes(out, indent, indentType, level+1)
|
||||
child.Bytes(out, indent, indentType, level + 1)
|
||||
}
|
||||
} else if node.content != "" {
|
||||
//val := []byte(node.content)
|
||||
//xml.EscapeText(out, val)
|
||||
out.WriteString(node.content)
|
||||
}
|
||||
|
||||
|
||||
if !empty && len(node.name.Local) > 0 {
|
||||
var indentation string
|
||||
if content {
|
||||
@ -192,8 +192,9 @@ 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)
|
||||
return string(b.Bytes())
|
||||
}
|
||||
}
|
6
vendor/github.com/masterzen/xmlpath/doc.go
generated
vendored
6
vendor/github.com/masterzen/xmlpath/doc.go
generated
vendored
@ -73,8 +73,8 @@
|
||||
//
|
||||
// To use xmlpath with namespaces, it is required to give the supported set of namespace
|
||||
// when compiling:
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// var namespaces = []xmlpath.Namespace {
|
||||
// { "s", "http://www.w3.org/2003/05/soap-envelope" },
|
||||
// { "a", "http://schemas.xmlsoap.org/ws/2004/08/addressing" },
|
||||
@ -90,6 +90,6 @@
|
||||
// if value, ok := path.String(root); ok {
|
||||
// fmt.Println("Found:", value)
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
package xmlpath
|
||||
|
14
vendor/github.com/masterzen/xmlpath/path.go
generated
vendored
14
vendor/github.com/masterzen/xmlpath/path.go
generated
vendored
@ -372,7 +372,7 @@ func MustCompile(path string) *Path {
|
||||
|
||||
// Compile returns the compiled path.
|
||||
func Compile(path string) (*Path, error) {
|
||||
c := pathCompiler{path, 0, []Namespace{}}
|
||||
c := pathCompiler{path, 0, []Namespace{} }
|
||||
if path == "" {
|
||||
return nil, c.errorf("empty path")
|
||||
}
|
||||
@ -397,9 +397,9 @@ func CompileWithNamespace(path string, ns []Namespace) (*Path, error) {
|
||||
}
|
||||
|
||||
type pathCompiler struct {
|
||||
path string
|
||||
i int
|
||||
ns []Namespace
|
||||
path string
|
||||
i int
|
||||
ns []Namespace
|
||||
}
|
||||
|
||||
func (c *pathCompiler) errorf(format string, args ...interface{}) error {
|
||||
@ -575,14 +575,14 @@ func (c *pathCompiler) parseLiteral() (string, error) {
|
||||
if !c.skipByteFind('"') {
|
||||
return "", fmt.Errorf(`missing '"'`)
|
||||
}
|
||||
return c.path[mark : c.i-1], nil
|
||||
return c.path[mark:c.i-1], nil
|
||||
}
|
||||
if c.skipByte('\'') {
|
||||
mark := c.i
|
||||
if !c.skipByteFind('\'') {
|
||||
return "", fmt.Errorf(`missing "'"`)
|
||||
}
|
||||
return c.path[mark : c.i-1], nil
|
||||
return c.path[mark:c.i-1], nil
|
||||
}
|
||||
return "", errNoLiteral
|
||||
}
|
||||
@ -611,7 +611,7 @@ func (c *pathCompiler) skipByte(b byte) bool {
|
||||
func (c *pathCompiler) skipByteFind(b byte) bool {
|
||||
for i := c.i; i < len(c.path); i++ {
|
||||
if c.path[i] == b {
|
||||
c.i = i + 1
|
||||
c.i = i+1
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
8
vendor/github.com/mitchellh/go-fs/fat/directory_cluster.go
generated
vendored
8
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,
|
||||
@ -159,8 +159,8 @@ func NewFat16RootDirectoryCluster(bs *BootSectorCommon, label string) (*Director
|
||||
|
||||
// Create the volume ID entry
|
||||
result.entries[0] = &DirectoryClusterEntry{
|
||||
attr: AttrVolumeId,
|
||||
name: label,
|
||||
attr: AttrVolumeId,
|
||||
name: label,
|
||||
cluster: 0,
|
||||
}
|
||||
|
||||
|
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/nu7hatch/gouuid/uuid.go
generated
vendored
2
vendor/github.com/nu7hatch/gouuid/uuid.go
generated
vendored
@ -16,7 +16,7 @@ import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// The UUID reserved variants.
|
||||
// The UUID reserved variants.
|
||||
const (
|
||||
ReservedNCS byte = 0x80
|
||||
ReservedRFC4122 byte = 0x40
|
||||
|
4
vendor/github.com/packer-community/winrmcp/winrmcp/psobject.go
generated
vendored
4
vendor/github.com/packer-community/winrmcp/winrmcp/psobject.go
generated
vendored
@ -6,10 +6,12 @@ type pslist struct {
|
||||
|
||||
type psobject struct {
|
||||
Properties []psproperty `xml:"Property"`
|
||||
Value string `xml:",innerxml"`
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
type psproperty struct {
|
||||
Name string `xml:"Name,attr"`
|
||||
Value string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user