<commit_before>package main

import (
	"fmt"
	"log"
	"github.com/hashicorp/terraform/helper/schema"
    "golang.org/x/net/context"
    "github.com/vmware/govmomi/find"
    "github.com/vmware/govmomi/object"
    "github.com/vmware/govmomi/property"
    "github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
    "strings"
)

func resourceVirtualMachine() *schema.Resource {
	return &schema.Resource{
		Create: resourceVirtualMachineCreate,
		Read:   resourceVirtualMachineRead,
		Delete: resourceVirtualMachineDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
                ForceNew: true,
			},
			"image": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
                ForceNew: true,
			},

			"datacenter": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"folder": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"host": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
                Computed: true,
			},
			"resource_pool": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
                Computed: true,
            },

			"linked_clone": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
                Default: false,
                ForceNew: true,
			},
			"cpus": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
                Computed: true,
			},
			"memory": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
                Computed: true,
			},
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
                ForceNew: true,
			},
            "ip_address": &schema.Schema{
                Type:     schema.TypeString,
                Optional: true,
                Computed: true,
            },
            "subnet_mask": &schema.Schema{
                Type:     schema.TypeString,
                Optional: true,
                ForceNew: true,
            },
            "gateway": &schema.Schema{
                Type:     schema.TypeString,
                Optional: true,
                ForceNew: true,
            },
            "configuration_parameters": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
                ForceNew: true,
			},
			"power_on": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
                Default:  true,
                ForceNew: true,
			},
        },
	}
}

func resourceVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*vim25.Client)

    dc_name := d.Get("datacenter").(string)
    if dc_name == "" {
        finder := find.NewFinder(client, false)
        dc, err := finder.DefaultDatacenter(context.TODO())
        if err != nil {
            return fmt.Errorf("Error reading default datacenter: %s", err)
        }
        var dc_mo mo.Datacenter
        err = dc.Properties(context.TODO(), dc.Reference(), []string{"name"}, &dc_mo)
        if err != nil {
            return fmt.Errorf("Error reading datacenter name: %s", err)
        }
        dc_name = dc_mo.Name
        d.Set("datacenter", dc_name)
    }

	image_name := d.Get("image").(string)
    image_ref, err := object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%s/vm/%s", dc_name, image_name))
	if err != nil {
		return fmt.Errorf("Error reading vm: %s", err)
	}
    if image_ref == nil {
        return fmt.Errorf("Cannot find image %s", image_name)
    }
    image := image_ref.(*object.VirtualMachine)

    var image_mo mo.VirtualMachine
    err = image.Properties(context.TODO(), image.Reference(), []string{"parent", "config.template", "resourcePool", "snapshot", "guest.toolsVersionStatus2", "config.guestFullName"}, &image_mo)
    if err != nil {
        return fmt.Errorf("Error reading base VM properties: %s", err)
    }

	var folder_ref object.Reference
    var folder *object.Folder
    if d.Get("folder").(string) != "" {
        folder_ref, err = object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%v/vm/%v", dc_name, d.Get("folder").(string)))
        if err != nil {
            return fmt.Errorf("Error reading folder: %s", err)
        }
        if folder_ref == nil {
            return fmt.Errorf("Cannot find folder %s", d.Get("folder").(string))
        }

        folder = folder_ref.(*object.Folder)
    } else {
        folder = object.NewFolder(client, *image_mo.Parent)
    }

    host_name := d.Get("host").(string)
    if host_name == "" {
        if image_mo.Config.Template == true {
            return fmt.Errorf("Image is a template, 'host' is a required")
        } else {
            var pool_mo mo.ResourcePool
            err = property.DefaultCollector(client).RetrieveOne(context.TODO(), *image_mo.ResourcePool, []string{"owner"}, &pool_mo)
            if err != nil {
                return fmt.Errorf("Error reading resource pool of base VM: %s", err)
            }

            if strings.Contains(pool_mo.Owner.Value, "domain-s") {
                var host_mo mo.ComputeResource
                err = property.DefaultCollector(client).RetrieveOne(context.TODO(), pool_mo.Owner, []string{"name"}, &host_mo)
                if err != nil {
                    return fmt.Errorf("Error reading host of base VM: %s", err)
                }
                host_name = host_mo.Name
            } else if strings.Contains(pool_mo.Owner.Value, "domain-c") {
                var cluster_mo mo.ClusterComputeResource
                err = property.DefaultCollector(client).RetrieveOne(context.TODO(), pool_mo.Owner, []string{"name"}, &cluster_mo)
                if err != nil {
                    return fmt.Errorf("Error reading cluster of base VM: %s", err)
                }
                host_name = cluster_mo.Name
            } else {
                return fmt.Errorf("Unknown compute resource format of base VM: %s", pool_mo.Owner.Value)
            }
        }
    }

    pool_name := d.Get("resource_pool").(string)
    pool_ref, err := object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%v/host/%v/Resources/%v", dc_name, host_name, pool_name))
    if err != nil {
        return fmt.Errorf("Error reading resource pool: %s", err)
    }
    if pool_ref == nil {
        return fmt.Errorf("Cannot find resource pool %s", pool_name)
    }

	var relocateSpec types.VirtualMachineRelocateSpec
    var pool_mor types.ManagedObjectReference
    pool_mor = pool_ref.Reference()
    relocateSpec.Pool = &pool_mor

	if d.Get("linked_clone").(bool) {
		relocateSpec.DiskMoveType = "createNewChildDiskBacking"
	}
    var confSpec types.VirtualMachineConfigSpec
    if d.Get("cpus") != nil {
        confSpec.NumCPUs = d.Get("cpus").(int)
    }
    if d.Get("memory") != nil {
        confSpec.MemoryMB = int64(d.Get("memory").(int))
    }

    params := d.Get("configuration_parameters").(map[string]interface{})
    var ov []types.BaseOptionValue
    if len(params) > 0 {
        for k, v := range params {
            key := strings.Replace(k, "_",".", -1)
            value := v
            o := types.OptionValue{
                Key:   key,
                Value: &value,
            }
            ov = append(ov, &o)
        }
        confSpec.ExtraConfig = ov
    }

	cloneSpec := types.VirtualMachineCloneSpec{
		Location: relocateSpec,
        Config:   &confSpec,
        PowerOn:  d.Get("power_on").(bool),
	}
    if d.Get("linked_clone").(bool) {
        if image_mo.Snapshot == nil {
            return fmt.Errorf("`linked_clone=true`, but image VM has no snapshots")
        }
        cloneSpec.Snapshot = image_mo.Snapshot.CurrentSnapshot
    }

    domain := d.Get("domain").(string)
    ip_address := d.Get("ip_address").(string)
    if domain != "" {
        if image_mo.Guest.ToolsVersionStatus2 == "guestToolsNotInstalled" {
            return fmt.Errorf("VMware tools are not installed in base VM")
        }
        if !strings.Contains(image_mo.Config.GuestFullName, "Linux") && !strings.Contains(image_mo.Config.GuestFullName, "CentOS") {
            return fmt.Errorf("Guest customization is supported only for Linux. Base image OS is: %s", image_mo.Config.GuestFullName)
        }
        customizationSpec := types.CustomizationSpec{
            GlobalIPSettings: types.CustomizationGlobalIPSettings{},
            Identity: &types.CustomizationLinuxPrep{
                HostName: &types.CustomizationVirtualMachineName{},
                Domain: domain,
            },
            NicSettingMap: []types.CustomizationAdapterMapping {
                {
                    Adapter: types.CustomizationIPSettings{},
                },
            },
        }
        if ip_address != "" {
            mask := d.Get("subnet_mask").(string)
            if mask == "" {
                return fmt.Errorf("'subnet_mask' must be set, if static 'ip_address' is specified")
            }
            customizationSpec.NicSettingMap[0].Adapter.Ip = &types.CustomizationFixedIp{
                IpAddress: ip_address,
            }
            customizationSpec.NicSettingMap[0].Adapter.SubnetMask = d.Get("subnet_mask").(string)
            gateway := d.Get("gateway").(string)
            if gateway != "" {
                customizationSpec.NicSettingMap[0].Adapter.Gateway = []string{gateway}
            }
        } else {
            customizationSpec.NicSettingMap[0].Adapter.Ip = &types.CustomizationDhcpIpGenerator{}
        }
        cloneSpec.Customization = &customizationSpec
    } else if ip_address != "" {
        return fmt.Errorf("'domain' must be set, if static 'ip_address' is specified")
    }

	task, err := image.Clone(context.TODO(), folder, d.Get("name").(string), cloneSpec)
	if err != nil {
		return fmt.Errorf("Error clonning vm: %s", err)
	}
	info, err := task.WaitForResult(context.TODO(), nil)
	if err != nil {
		return fmt.Errorf("Error clonning vm: %s", err)
	}

	vm_mor := info.Result.(types.ManagedObjectReference)
    d.SetId(vm_mor.Value)
    vm := object.NewVirtualMachine(client, vm_mor)
    // workaround for https://github.com/vmware/govmomi/issues/218
    if ip_address=="" && d.Get("power_on").(bool) {
        ip, err := vm.WaitForIP(context.TODO())
        if err != nil {
            log.Printf("[ERROR] Cannot read ip address: %s", err)
        } else {
            d.Set("ip_address", ip)
            d.SetConnInfo(map[string]string{
                "type": "ssh",
                "host": ip,
            })
        }
    }

    return nil
}

func resourceVirtualMachineRead(d *schema.ResourceData, meta interface{}) error {
    client := meta.(*vim25.Client)
    vm_mor := types.ManagedObjectReference{Type: "VirtualMachine", Value: d.Id() }
    vm := object.NewVirtualMachine(client, vm_mor)

    var vm_mo mo.VirtualMachine
    err := vm.Properties(context.TODO(), vm.Reference(), []string{"summary"}, &vm_mo)
    if err != nil {
        log.Printf("[INFO] Cannot read VM properties: %s", err)
        d.SetId("")
        return nil
    }
    d.Set("name", vm_mo.Summary.Config.Name)
    d.Set("cpus", vm_mo.Summary.Config.NumCpu)
    d.Set("memory", vm_mo.Summary.Config.MemorySizeMB)

    if vm_mo.Summary.Runtime.PowerState == "poweredOn" {
        d.Set("power_on", true)
    } else {
        d.Set("power_on", false)
    }

    if d.Get("power_on").(bool) {
        ip, err := vm.WaitForIP(context.TODO())
        if err != nil {
            log.Printf("[ERROR] Cannot read ip address: %s", err)
        } else {
            d.Set("ip_address", ip)
        }
    }

	return nil
}

func resourceVirtualMachineDelete(d *schema.ResourceData, meta interface{}) error {
    client := meta.(*vim25.Client)
    vm_mor := types.ManagedObjectReference{Type: "VirtualMachine", Value: d.Id() }
    vm := object.NewVirtualMachine(client, vm_mor)

    task, err := vm.PowerOff(context.TODO())
    if err != nil {
        return fmt.Errorf("Error powering vm off: %s", err)
    }
    task.WaitForResult(context.TODO(), nil)

    task, err = vm.Destroy(context.TODO())
    if err != nil {
        return fmt.Errorf("Error deleting vm: %s", err)
    }
    _, err = task.WaitForResult(context.TODO(), nil)
    if err != nil {
        return fmt.Errorf("Error deleting vm: %s", err)
    }

    return nil
}
<commit_msg>Fix compatibility with current govmomi version<commit_after>package main

import (
	"fmt"
	"log"
	"github.com/hashicorp/terraform/helper/schema"
    "golang.org/x/net/context"
    "github.com/vmware/govmomi/find"
    "github.com/vmware/govmomi/object"
    "github.com/vmware/govmomi/property"
    "github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
    "strings"
)

func resourceVirtualMachine() *schema.Resource {
	return &schema.Resource{
		Create: resourceVirtualMachineCreate,
		Read:   resourceVirtualMachineRead,
		Delete: resourceVirtualMachineDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
                ForceNew: true,
			},
			"image": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
                ForceNew: true,
			},

			"datacenter": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"folder": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"host": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
                Computed: true,
			},
			"resource_pool": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
                Computed: true,
            },

			"linked_clone": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
                Default: false,
                ForceNew: true,
			},
			"cpus": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
                Computed: true,
			},
			"memory": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
                Computed: true,
			},
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
                ForceNew: true,
			},
            "ip_address": &schema.Schema{
                Type:     schema.TypeString,
                Optional: true,
                Computed: true,
            },
            "subnet_mask": &schema.Schema{
                Type:     schema.TypeString,
                Optional: true,
                ForceNew: true,
            },
            "gateway": &schema.Schema{
                Type:     schema.TypeString,
                Optional: true,
                ForceNew: true,
            },
            "configuration_parameters": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
                ForceNew: true,
			},
			"power_on": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
                Default:  true,
                ForceNew: true,
			},
        },
	}
}

func resourceVirtualMachineCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*vim25.Client)

    dc_name := d.Get("datacenter").(string)
    if dc_name == "" {
        finder := find.NewFinder(client, false)
        dc, err := finder.DefaultDatacenter(context.TODO())
        if err != nil {
            return fmt.Errorf("Error reading default datacenter: %s", err)
        }
        var dc_mo mo.Datacenter
        err = dc.Properties(context.TODO(), dc.Reference(), []string{"name"}, &dc_mo)
        if err != nil {
            return fmt.Errorf("Error reading datacenter name: %s", err)
        }
        dc_name = dc_mo.Name
        d.Set("datacenter", dc_name)
    }

	image_name := d.Get("image").(string)
    image_ref, err := object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%s/vm/%s", dc_name, image_name))
	if err != nil {
		return fmt.Errorf("Error reading vm: %s", err)
	}
    if image_ref == nil {
        return fmt.Errorf("Cannot find image %s", image_name)
    }
    image := image_ref.(*object.VirtualMachine)

    var image_mo mo.VirtualMachine
    err = image.Properties(context.TODO(), image.Reference(), []string{"parent", "config.template", "resourcePool", "snapshot", "guest.toolsVersionStatus2", "config.guestFullName"}, &image_mo)
    if err != nil {
        return fmt.Errorf("Error reading base VM properties: %s", err)
    }

	var folder_ref object.Reference
    var folder *object.Folder
    if d.Get("folder").(string) != "" {
        folder_ref, err = object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%v/vm/%v", dc_name, d.Get("folder").(string)))
        if err != nil {
            return fmt.Errorf("Error reading folder: %s", err)
        }
        if folder_ref == nil {
            return fmt.Errorf("Cannot find folder %s", d.Get("folder").(string))
        }

        folder = folder_ref.(*object.Folder)
    } else {
        folder = object.NewFolder(client, *image_mo.Parent)
    }

    host_name := d.Get("host").(string)
    if host_name == "" {
        if image_mo.Config.Template == true {
            return fmt.Errorf("Image is a template, 'host' is a required")
        } else {
            var pool_mo mo.ResourcePool
            err = property.DefaultCollector(client).RetrieveOne(context.TODO(), *image_mo.ResourcePool, []string{"owner"}, &pool_mo)
            if err != nil {
                return fmt.Errorf("Error reading resource pool of base VM: %s", err)
            }

            if strings.Contains(pool_mo.Owner.Value, "domain-s") {
                var host_mo mo.ComputeResource
                err = property.DefaultCollector(client).RetrieveOne(context.TODO(), pool_mo.Owner, []string{"name"}, &host_mo)
                if err != nil {
                    return fmt.Errorf("Error reading host of base VM: %s", err)
                }
                host_name = host_mo.Name
            } else if strings.Contains(pool_mo.Owner.Value, "domain-c") {
                var cluster_mo mo.ClusterComputeResource
                err = property.DefaultCollector(client).RetrieveOne(context.TODO(), pool_mo.Owner, []string{"name"}, &cluster_mo)
                if err != nil {
                    return fmt.Errorf("Error reading cluster of base VM: %s", err)
                }
                host_name = cluster_mo.Name
            } else {
                return fmt.Errorf("Unknown compute resource format of base VM: %s", pool_mo.Owner.Value)
            }
        }
    }

    pool_name := d.Get("resource_pool").(string)
    pool_ref, err := object.NewSearchIndex(client).FindByInventoryPath(context.TODO(), fmt.Sprintf("%v/host/%v/Resources/%v", dc_name, host_name, pool_name))
    if err != nil {
        return fmt.Errorf("Error reading resource pool: %s", err)
    }
    if pool_ref == nil {
        return fmt.Errorf("Cannot find resource pool %s", pool_name)
    }

	var relocateSpec types.VirtualMachineRelocateSpec
    var pool_mor types.ManagedObjectReference
    pool_mor = pool_ref.Reference()
    relocateSpec.Pool = &pool_mor

	if d.Get("linked_clone").(bool) {
		relocateSpec.DiskMoveType = "createNewChildDiskBacking"
	}
    var confSpec types.VirtualMachineConfigSpec
    if d.Get("cpus") != nil {
        confSpec.NumCPUs = d.Get("cpus").(int32)
    }
    if d.Get("memory") != nil {
        confSpec.MemoryMB = d.Get("memory").(int64)
    }

    params := d.Get("configuration_parameters").(map[string]interface{})
    var ov []types.BaseOptionValue
    if len(params) > 0 {
        for k, v := range params {
            key := strings.Replace(k, "_",".", -1)
            value := v
            o := types.OptionValue{
                Key:   key,
                Value: &value,
            }
            ov = append(ov, &o)
        }
        confSpec.ExtraConfig = ov
    }

	cloneSpec := types.VirtualMachineCloneSpec{
		Location: relocateSpec,
        Config:   &confSpec,
        PowerOn:  d.Get("power_on").(bool),
	}
    if d.Get("linked_clone").(bool) {
        if image_mo.Snapshot == nil {
            return fmt.Errorf("`linked_clone=true`, but image VM has no snapshots")
        }
        cloneSpec.Snapshot = image_mo.Snapshot.CurrentSnapshot
    }

    domain := d.Get("domain").(string)
    ip_address := d.Get("ip_address").(string)
    if domain != "" {
        if image_mo.Guest.ToolsVersionStatus2 == "guestToolsNotInstalled" {
            return fmt.Errorf("VMware tools are not installed in base VM")
        }
        if !strings.Contains(image_mo.Config.GuestFullName, "Linux") && !strings.Contains(image_mo.Config.GuestFullName, "CentOS") {
            return fmt.Errorf("Guest customization is supported only for Linux. Base image OS is: %s", image_mo.Config.GuestFullName)
        }
        customizationSpec := types.CustomizationSpec{
            GlobalIPSettings: types.CustomizationGlobalIPSettings{},
            Identity: &types.CustomizationLinuxPrep{
                HostName: &types.CustomizationVirtualMachineName{},
                Domain: domain,
            },
            NicSettingMap: []types.CustomizationAdapterMapping {
                {
                    Adapter: types.CustomizationIPSettings{},
                },
            },
        }
        if ip_address != "" {
            mask := d.Get("subnet_mask").(string)
            if mask == "" {
                return fmt.Errorf("'subnet_mask' must be set, if static 'ip_address' is specified")
            }
            customizationSpec.NicSettingMap[0].Adapter.Ip = &types.CustomizationFixedIp{
                IpAddress: ip_address,
            }
            customizationSpec.NicSettingMap[0].Adapter.SubnetMask = d.Get("subnet_mask").(string)
            gateway := d.Get("gateway").(string)
            if gateway != "" {
                customizationSpec.NicSettingMap[0].Adapter.Gateway = []string{gateway}
            }
        } else {
            customizationSpec.NicSettingMap[0].Adapter.Ip = &types.CustomizationDhcpIpGenerator{}
        }
        cloneSpec.Customization = &customizationSpec
    } else if ip_address != "" {
        return fmt.Errorf("'domain' must be set, if static 'ip_address' is specified")
    }

	task, err := image.Clone(context.TODO(), folder, d.Get("name").(string), cloneSpec)
	if err != nil {
		return fmt.Errorf("Error clonning vm: %s", err)
	}
	info, err := task.WaitForResult(context.TODO(), nil)
	if err != nil {
		return fmt.Errorf("Error clonning vm: %s", err)
	}

	vm_mor := info.Result.(types.ManagedObjectReference)
    d.SetId(vm_mor.Value)
    vm := object.NewVirtualMachine(client, vm_mor)
    // workaround for https://github.com/vmware/govmomi/issues/218
    if ip_address=="" && d.Get("power_on").(bool) {
        ip, err := vm.WaitForIP(context.TODO())
        if err != nil {
            log.Printf("[ERROR] Cannot read ip address: %s", err)
        } else {
            d.Set("ip_address", ip)
            d.SetConnInfo(map[string]string{
                "type": "ssh",
                "host": ip,
            })
        }
    }

    return nil
}

func resourceVirtualMachineRead(d *schema.ResourceData, meta interface{}) error {
    client := meta.(*vim25.Client)
    vm_mor := types.ManagedObjectReference{Type: "VirtualMachine", Value: d.Id() }
    vm := object.NewVirtualMachine(client, vm_mor)

    var vm_mo mo.VirtualMachine
    err := vm.Properties(context.TODO(), vm.Reference(), []string{"summary"}, &vm_mo)
    if err != nil {
        log.Printf("[INFO] Cannot read VM properties: %s", err)
        d.SetId("")
        return nil
    }
    d.Set("name", vm_mo.Summary.Config.Name)
    d.Set("cpus", vm_mo.Summary.Config.NumCpu)
    d.Set("memory", vm_mo.Summary.Config.MemorySizeMB)

    if vm_mo.Summary.Runtime.PowerState == "poweredOn" {
        d.Set("power_on", true)
    } else {
        d.Set("power_on", false)
    }

    if d.Get("power_on").(bool) {
        ip, err := vm.WaitForIP(context.TODO())
        if err != nil {
            log.Printf("[ERROR] Cannot read ip address: %s", err)
        } else {
            d.Set("ip_address", ip)
        }
    }

	return nil
}

func resourceVirtualMachineDelete(d *schema.ResourceData, meta interface{}) error {
    client := meta.(*vim25.Client)
    vm_mor := types.ManagedObjectReference{Type: "VirtualMachine", Value: d.Id() }
    vm := object.NewVirtualMachine(client, vm_mor)

    task, err := vm.PowerOff(context.TODO())
    if err != nil {
        return fmt.Errorf("Error powering vm off: %s", err)
    }
    task.WaitForResult(context.TODO(), nil)

    task, err = vm.Destroy(context.TODO())
    if err != nil {
        return fmt.Errorf("Error deleting vm: %s", err)
    }
    _, err = task.WaitForResult(context.TODO(), nil)
    if err != nil {
        return fmt.Errorf("Error deleting vm: %s", err)
    }

    return nil
}
<|endoftext|>


<commit_before>package coderwall

import (
  "net/http"
  "io"
  "io/ioutil"
  "encoding/json"
)

const BaseUrl = "http://coderwall.com"

type client struct {
  httpClient HttpClient
}

type HttpClient interface {
  Get(string) (resp *http.Response, err error)
}

type Profile struct {
  Username string
  Name string
  Location string
  Endorsements int
  Team string
  Accounts map[string]string
  Badges []struct {
    Name string
    Description string
    Created string
    Badge string
  }
}

func (c client)  PerformRequest(url string) (resp *http.Response, err error) {
  return c.httpClient.Get(url)
}

func (c client) ProfileUrl(username string) string {
  return BaseUrl + "/" + username + ".json"
}

func (c client) LoadProfileFromJSON(profile *Profile, jsonContent []byte) (error) {
  err := json.Unmarshal(jsonContent, &profile)

  return err
}

func (c client) ParseBody(profile *Profile, body io.ReadCloser) (error) {
  defer body.Close()
  content, err := ioutil.ReadAll(body)
  if err != nil {
    return err
  }
  c.LoadProfileFromJSON(profile, content)

  return nil
}

func (c client) GetProfile(username string) (Profile, error) {
  var profile Profile
  url := c.ProfileUrl(username)
  res, err := c.PerformRequest(url)
  if err != nil {
    return profile, err
  }
  err = c.ParseBody(&profile, res.Body)

  return profile, err
}

func NewClient() client {
  var c client
  c.httpClient = &http.Client{}

  return c
}
<commit_msg>spaces<commit_after>package coderwall

import (
  "net/http"
  "io"
  "io/ioutil"
  "encoding/json"
)

const BaseUrl = "http://coderwall.com"

type client struct {
  httpClient HttpClient
}

type HttpClient interface {
  Get(string) (resp *http.Response, err error)
}

type Profile struct {
  Username string
  Name string
  Location string
  Endorsements int
  Team string
  Accounts map[string]string
  Badges []struct {
    Name string
    Description string
    Created string
    Badge string
  }
}

func (c client) PerformRequest(url string) (resp *http.Response, err error) {
  return c.httpClient.Get(url)
}

func (c client) ProfileUrl(username string) string {
  return BaseUrl + "/" + username + ".json"
}

func (c client) LoadProfileFromJSON(profile *Profile, jsonContent []byte) (error) {
  err := json.Unmarshal(jsonContent, &profile)

  return err
}

func (c client) ParseBody(profile *Profile, body io.ReadCloser) (error) {
  defer body.Close()
  content, err := ioutil.ReadAll(body)
  if err != nil {
    return err
  }
  c.LoadProfileFromJSON(profile, content)

  return nil
}

func (c client) GetProfile(username string) (Profile, error) {
  var profile Profile
  url := c.ProfileUrl(username)
  res, err := c.PerformRequest(url)
  if err != nil {
    return profile, err
  }
  err = c.ParseBody(&profile, res.Body)

  return profile, err
}

func NewClient() client {
  var c client
  c.httpClient = &http.Client{}

  return c
}
<|endoftext|>


<commit_before>// Copyright (c) 2022 Uber Technologies, Inc.
//
// 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.

package zanzibar

import (
	"context"
	"time"

	jsonschema "github.com/mcuadros/go-jsonschema-generator"
	"github.com/uber-go/tally"
)

const (
	middlewareRequestLatencyTag  = "middleware.request.latency"
	middlewareResponseLatencyTag = "middleware.response.latency"
	middlewareRequestStatusTag   = "middleware.request.status"
)

// MiddlewareStack is a stack of Middleware Handlers that can be invoked as an Handle.
// MiddlewareStack middlewares are evaluated for requests in the order that they are added to the stack
// followed by the underlying HandlerFn. The middleware responses are then executed in reverse.
type MiddlewareStack struct {
	middlewares []MiddlewareHandle
	handle      HandlerFn
}

// NewStack returns a new MiddlewareStack instance with no middleware preconfigured.
func NewStack(middlewares []MiddlewareHandle,
	handle HandlerFn) *MiddlewareStack {
	return &MiddlewareStack{
		handle:      handle,
		middlewares: middlewares,
	}
}

// Middlewares returns a list of all the handlers in the current MiddlewareStack.
func (m *MiddlewareStack) Middlewares() []MiddlewareHandle {
	return m.middlewares
}

// MiddlewareHandle used to define middleware
type MiddlewareHandle interface {
	// implement HandleRequest for your middleware. Return false
	// if the handler writes to the response body.
	HandleRequest(
		ctx context.Context,
		req *ServerHTTPRequest,
		res *ServerHTTPResponse,
		shared SharedState,
	) (context.Context, bool)
	// implement HandleResponse for your middleware. Return false
	// if the handler writes to the response body.
	HandleResponse(
		ctx context.Context,
		res *ServerHTTPResponse,
		shared SharedState,
	) context.Context
	// return any shared state for this middleware.
	JSONSchema() *jsonschema.Document
	Name() string
}

// SharedState used to access other middlewares in the chain.
type SharedState struct {
	middlewareDict map[string]interface{}
}

// NewSharedState constructs a ShardState
func NewSharedState(middlewares []MiddlewareHandle) SharedState {
	sharedState := SharedState{}
	sharedState.middlewareDict = make(map[string]interface{})

	for i := 0; i < len(middlewares); i++ {
		sharedState.middlewareDict[middlewares[i].Name()] = nil
	}
	return sharedState
}

// GetState returns the state from a different middleware
func (s SharedState) GetState(name string) interface{} {
	return s.middlewareDict[name]
}

// SetState sets value of a middleware shared state
func (s SharedState) SetState(m MiddlewareHandle, state interface{}) {
	s.middlewareDict[m.Name()] = state
}

// Handle executes the middlewares in a stack and underlying handler.
func (m *MiddlewareStack) Handle(
	ctx context.Context,
	req *ServerHTTPRequest,
	res *ServerHTTPResponse) context.Context {

	shared := NewSharedState(m.middlewares)
	middlewareRequestStartTime := time.Now()

	for i := 0; i < len(m.middlewares); i++ {
		ctx, ok := m.middlewares[i].HandleRequest(ctx, req, res, shared)
		// If a middleware errors and writes to the response header
		// then abort the rest of the stack and evaluate the response
		// handlers for the middlewares seen so far.
		if ok == false {
			//record latency for middlewares requests in unsuccesful case as the middleware requests calls are terminated
			m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

			middlewareResponseStartTime := time.Now() // start the timer for middleware responses
			for j := i; j >= 0; j-- {
				m.middlewares[j].HandleResponse(ctx, res, shared)
			}
			//record latency for middlewares responses in unsuccesful case
			m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)

			//for error metrics only emit when there is gateway error and not request error
			// the percentage can be calculated via error_count/total_request
			if res.pendingStatusCode >= 500 {
				m.emitAvailabilityError(middlewareRequestStatusTag, req.scope)
			}
			return ctx
		}
	}
	// record latency for middlewares requests in successful case
	m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

	ctx = m.handle(ctx, req, res)

	middlewareResponseStartTime := time.Now()
	for i := len(m.middlewares) - 1; i >= 0; i-- {
		m.middlewares[i].HandleResponse(ctx, res, shared)
	}
	// record latency for middlewares responses in successful case
	m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)
	return ctx
}

// recordLatency measures the latency as per the tagName and start time given.
func (m *MiddlewareStack) recordLatency(tagName string, startTime time.Time, scope tally.Scope) {
	elapsed := time.Now().Sub(startTime)
	scope.Timer(tagName).Record(elapsed)
}

// emitAvailability is used to increment the error counter for a particular tagName.
func (m *MiddlewareStack) emitAvailabilityError(tagName string, scope tally.Scope) {
	tagged := scope.Tagged(map[string]string{
		scopeTagStatus: "error",
	})
	tagged.Counter(tagName).Inc(1)
}
<commit_msg>changed metric to histogram<commit_after>// Copyright (c) 2022 Uber Technologies, Inc.
//
// 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.

package zanzibar

import (
	"context"
	"time"

	jsonschema "github.com/mcuadros/go-jsonschema-generator"
	"github.com/uber-go/tally"
)

const (
	middlewareRequestLatencyTag  = "middleware.request.latency"
	middlewareResponseLatencyTag = "middleware.response.latency"
	middlewareRequestStatusTag   = "middleware.request.status"
)

// MiddlewareStack is a stack of Middleware Handlers that can be invoked as an Handle.
// MiddlewareStack middlewares are evaluated for requests in the order that they are added to the stack
// followed by the underlying HandlerFn. The middleware responses are then executed in reverse.
type MiddlewareStack struct {
	middlewares []MiddlewareHandle
	handle      HandlerFn
}

// NewStack returns a new MiddlewareStack instance with no middleware preconfigured.
func NewStack(middlewares []MiddlewareHandle,
	handle HandlerFn) *MiddlewareStack {
	return &MiddlewareStack{
		handle:      handle,
		middlewares: middlewares,
	}
}

// Middlewares returns a list of all the handlers in the current MiddlewareStack.
func (m *MiddlewareStack) Middlewares() []MiddlewareHandle {
	return m.middlewares
}

// MiddlewareHandle used to define middleware
type MiddlewareHandle interface {
	// implement HandleRequest for your middleware. Return false
	// if the handler writes to the response body.
	HandleRequest(
		ctx context.Context,
		req *ServerHTTPRequest,
		res *ServerHTTPResponse,
		shared SharedState,
	) (context.Context, bool)
	// implement HandleResponse for your middleware. Return false
	// if the handler writes to the response body.
	HandleResponse(
		ctx context.Context,
		res *ServerHTTPResponse,
		shared SharedState,
	) context.Context
	// return any shared state for this middleware.
	JSONSchema() *jsonschema.Document
	Name() string
}

// SharedState used to access other middlewares in the chain.
type SharedState struct {
	middlewareDict map[string]interface{}
}

// NewSharedState constructs a ShardState
func NewSharedState(middlewares []MiddlewareHandle) SharedState {
	sharedState := SharedState{}
	sharedState.middlewareDict = make(map[string]interface{})

	for i := 0; i < len(middlewares); i++ {
		sharedState.middlewareDict[middlewares[i].Name()] = nil
	}
	return sharedState
}

// GetState returns the state from a different middleware
func (s SharedState) GetState(name string) interface{} {
	return s.middlewareDict[name]
}

// SetState sets value of a middleware shared state
func (s SharedState) SetState(m MiddlewareHandle, state interface{}) {
	s.middlewareDict[m.Name()] = state
}

// Handle executes the middlewares in a stack and underlying handler.
func (m *MiddlewareStack) Handle(
	ctx context.Context,
	req *ServerHTTPRequest,
	res *ServerHTTPResponse) context.Context {

	shared := NewSharedState(m.middlewares)
	middlewareRequestStartTime := time.Now()

	for i := 0; i < len(m.middlewares); i++ {
		ctx, ok := m.middlewares[i].HandleRequest(ctx, req, res, shared)
		// If a middleware errors and writes to the response header
		// then abort the rest of the stack and evaluate the response
		// handlers for the middlewares seen so far.
		if ok == false {
			//record latency for middlewares requests in unsuccesful case as the middleware requests calls are terminated
			m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

			middlewareResponseStartTime := time.Now() // start the timer for middleware responses
			for j := i; j >= 0; j-- {
				m.middlewares[j].HandleResponse(ctx, res, shared)
			}
			//record latency for middlewares responses in unsuccesful case
			m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)

			//for error metrics only emit when there is gateway error and not request error
			// the percentage can be calculated via error_count/total_request
			if res.pendingStatusCode >= 500 {
				m.emitAvailabilityError(middlewareRequestStatusTag, req.scope)
			}
			return ctx
		}
	}
	// record latency for middlewares requests in successful case
	m.recordLatency(middlewareRequestLatencyTag, middlewareRequestStartTime, req.scope)

	ctx = m.handle(ctx, req, res)

	middlewareResponseStartTime := time.Now()
	for i := len(m.middlewares) - 1; i >= 0; i-- {
		m.middlewares[i].HandleResponse(ctx, res, shared)
	}
	// record latency for middlewares responses in successful case
	m.recordLatency(middlewareResponseLatencyTag, middlewareResponseStartTime, req.scope)
	return ctx
}

// recordLatency measures the latency as per the tagName and start time given.
func (m *MiddlewareStack) recordLatency(tagName string, startTime time.Time, scope tally.Scope) {
	elapsed := time.Now().Sub(startTime)
	scope.Histogram(tagName, tally.DefaultBuckets).RecordDuration(elapsed)
}

// emitAvailability is used to increment the error counter for a particular tagName.
func (m *MiddlewareStack) emitAvailabilityError(tagName string, scope tally.Scope) {
	tagged := scope.Tagged(map[string]string{
		scopeTagStatus: "error",
	})
	tagged.Counter(tagName).Inc(1)
}
<|endoftext|>


<commit_before>//Package safeQueue implements a thread safe queue in go.
package safeQueue

//SafeQueue is the structure that contains the channel used to
//communicate with the queue.
type SafeQueue struct {
	op chan (func(*queue))
}

//Len will get return the number of items in the queue.
func (s *SafeQueue) Len() int64 {
	lChan := make(chan int64)
	s.op <- func(curr *queue) {
		lChan <- curr.size
	}
	return <-lChan
}

//Dequeue removes the next item in the queue and returns it's value
func (s *SafeQueue) Dequeue() interface{} {
	vChan := make(chan interface{})
	s.op <- func(curr *queue) {
		if curr.size == 0 {
			vChan <- nil
			return
		}
		val := curr.head.value
		if curr.size == 1 {
			curr.tail = nil
		}
		curr.head = curr.head.next
		curr.size--
		vChan <- val
		return
	}
	return <-vChan
}

//Enqueue places a new item at the end of the queue
func (s *SafeQueue) Enqueue(v interface{}) {
	s.op <- func(curr *queue) {
		newElem := &elem{v, nil}
		if curr.size == 0 {
			curr.head = newElem
		} else {
			curr.tail.next = newElem
		}
		curr.tail = newElem
		curr.size++
		return
	}
}

//Front returns the value from the front of the queue.
//It does not remove it from the queue.
func (s *SafeQueue) Front() interface{} {
	vChan := make(chan interface{})
	s.op <- func(curr *queue) {
		if curr.size == 0 {
			vChan <- nil
			return
		}
		vChan <- curr.head.value
		return
	}
	return <-vChan
}

//Back returns the value from the back of the queue.
//It does not remove it from the queue.
func (s *SafeQueue) Back() interface{} {
	vChan := make(chan interface{})
	s.op <- func(curr *queue) {
		if curr.size == 0 {
			vChan <- nil
			return
		}
		vChan <- curr.tail.value
		return
	}
	return <-vChan
}

//Destroy closes the primary channel thus stopping
//the running go-routine.
func (s *SafeQueue) Destroy() {
	close(s.op)
}

//New creates a new Safe Stack, this also starts the go-routine
//so once this is called, you need to clean up after yourself
//by using the Destroy method.
func New() (s *SafeQueue) {
	s = &SafeQueue{make(chan func(*queue))}
	go s.loop()
	return
}

//stack is the basic container for the queue
type queue struct {
	head *elem
	tail *elem
	size int64
}

//elem is the element structure
type elem struct {
	value interface{}
	next  *elem
}

//loop creates the guarded data structure and listens for
//methods on the op channel. loop terminates when the op
//channel is closed.
func (s *SafeQueue) loop() {
	st := &queue{}
	for op := range s.op {
		op(st)
	}
}
<commit_msg>Refactored safeQueue to reduce memory overhead<commit_after>//Package safeQueue implements a thread safe queue in go.
package safeQueue

//SafeQueue is the structure that contains the channel used to
//communicate with the queue.
type SafeQueue struct {
	op chan (func(*queue))
}

//Len will get return the number of items in the queue.
func (s *SafeQueue) Len() int64 {
	lChan := make(chan int64)
	s.op <- func(curr *queue) {
		lChan <- int64(len(*curr))
	}
	return <-lChan
}

//Dequeue removes the next item in the queue and returns it's value
func (s *SafeQueue) Dequeue() interface{} {
	vChan := make(chan interface{})
	s.op <- func(curr *queue) {
		if len(*curr) == 0 {
			vChan <- nil
			return
		}
		old := *curr
		n := len(old)
		val := old[0]
		*curr = old[1:n]
		vChan <- val
		return
	}
	return <-vChan
}

//Enqueue places a new item at the end of the queue
func (s *SafeQueue) Enqueue(v interface{}) {
	s.op <- func(curr *queue) {
		*curr = append(*curr, v)
		return
	}
}

//Front returns the value from the front of the queue.
//It does not remove it from the queue.
func (s *SafeQueue) Front() interface{} {
	vChan := make(chan interface{})
	s.op <- func(curr *queue) {
		if len(*curr) == 0 {
			vChan <- nil
			return
		}
		tmp := *curr
		vChan <- tmp[0]
		return
	}
	return <-vChan
}

//Back returns the value from the back of the queue.
//It does not remove it from the queue.
func (s *SafeQueue) Back() interface{} {
	vChan := make(chan interface{})
	s.op <- func(curr *queue) {
		if len(*curr) == 0 {
			vChan <- nil
			return
		}
		tmp := *curr
		vChan <- tmp[len(tmp)]
		return
	}
	return <-vChan
}

//Destroy closes the primary channel thus stopping
//the running go-routine.
func (s *SafeQueue) Destroy() {
	close(s.op)
}

//New creates a new Safe Stack, this also starts the go-routine
//so once this is called, you need to clean up after yourself
//by using the Destroy method.
func New() (s *SafeQueue) {
	s = &SafeQueue{make(chan func(*queue))}
	go s.loop()
	return
}

//queue contains the queue represented as a slice of interfaces.
type queue []interface{}

//loop creates the guarded data structure and listens for
//methods on the op channel. loop terminates when the op
//channel is closed.
func (s *SafeQueue) loop() {
	st := &queue{}
	for op := range s.op {
		op(st)
	}
}
<|endoftext|>


<commit_before>package brain_test

import (
	"encoding/json"
	"testing"

	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	brainMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/brain"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil/assert"
)

func TestGetMigrationJob(t *testing.T) {
	testName := testutil.Name(0)

	testMigrationJob := brain.MigrationJob{
		ID: 123,
		Args: brain.MigrationJobSpec{
			Sources: brain.MigrationJobLocations{
				Discs: []json.Number{"3"},
			},
			Destinations: brain.MigrationJobLocations{
				Pools: []json.Number{"pool.21"},
			},
		},
		Queue: brain.MigrationJobQueue{
			Discs: []int{3},
		},
		Destinations: brain.MigrationJobDestinations{
			Pools: []int{21},
		},
		Status: brain.MigrationJobStatus{
			Discs: brain.MigrationJobDiscStatus{
				Done:      []int{},
				Errored:   []int{},
				Cancelled: []int{},
				Skipped:   []int{},
			},
		},
		Priority:  5,
		CreatedAt: "2018-03-15T14:23:00.579Z",
		UpdatedAt: "2018-03-15T15:28:28.244Z",
	}

	rts := testutil.RequestTestSpec{
		Method:   "GET",
		URL:      "/admin/migration_jobs/123",
		Endpoint: lib.BrainEndpoint,
		Response: json.RawMessage(`{
		"id": 123,
		"args": {
		    "options": {},
		    "sources": {
			"discs": [3]
		    },
		    "destinations": {
			"pools": ["pool.21"]
		    }
		},
		"queue": {
		    "discs": [3]
		},
		"destinations": {
		    "pools": [21]
		},
		"status": {
		    "discs": {
			"done": [],
			"errored": [],
			"cancelled": [],
			"skipped": []
		    }
		},
		"priority": 5,
		"started_at": null,
		"finished_at": null,
		"created_at": "2018-03-15T14:23:00.579Z",
		"updated_at": "2018-03-15T15:28:28.244Z"
	    }`),
	}

	rts.Run(t, testName, true, func(client lib.Client) {
		migrationJob, err := brainMethods.GetMigrationJob(client, 123)
		if err != nil {
			t.Fatal(err)
		}
		assert.Equal(t, testName, migrationJob, testMigrationJob)
	})
}
<commit_msg>fix tests to use util.NumberOrString<commit_after>package brain_test

import (
	"encoding/json"
	"testing"

	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/lib/util"
	brainMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/brain"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil"
	"github.com/BytemarkHosting/bytemark-client/lib/testutil/assert"
)

func TestGetMigrationJob(t *testing.T) {
	testName := testutil.Name(0)

	testMigrationJob := brain.MigrationJob{
		ID: 123,
		Args: brain.MigrationJobSpec{
			Sources: brain.MigrationJobLocations{
				Discs: []util.NumberOrString{"3"},
			},
			Destinations: brain.MigrationJobLocations{
				Pools: []util.NumberOrString{"pool.21"},
			},
		},
		Queue: brain.MigrationJobQueue{
			Discs: []int{3},
		},
		Destinations: brain.MigrationJobDestinations{
			Pools: []int{21},
		},
		Status: brain.MigrationJobStatus{
			Discs: brain.MigrationJobDiscStatus{
				Done:      []int{},
				Errored:   []int{},
				Cancelled: []int{},
				Skipped:   []int{},
			},
		},
		Priority:  5,
		CreatedAt: "2018-03-15T14:23:00.579Z",
		UpdatedAt: "2018-03-15T15:28:28.244Z",
	}

	rts := testutil.RequestTestSpec{
		Method:   "GET",
		URL:      "/admin/migration_jobs/123",
		Endpoint: lib.BrainEndpoint,
		Response: json.RawMessage(`{
		"id": 123,
		"args": {
		    "options": {},
		    "sources": {
			"discs": [3]
		    },
		    "destinations": {
			"pools": ["pool.21"]
		    }
		},
		"queue": {
		    "discs": [3]
		},
		"destinations": {
		    "pools": [21]
		},
		"status": {
		    "discs": {
			"done": [],
			"errored": [],
			"cancelled": [],
			"skipped": []
		    }
		},
		"priority": 5,
		"started_at": null,
		"finished_at": null,
		"created_at": "2018-03-15T14:23:00.579Z",
		"updated_at": "2018-03-15T15:28:28.244Z"
	    }`),
	}

	rts.Run(t, testName, true, func(client lib.Client) {
		migrationJob, err := brainMethods.GetMigrationJob(client, 123)
		if err != nil {
			t.Fatal(err)
		}
		assert.Equal(t, testName, migrationJob, testMigrationJob)
	})
}
<|endoftext|>


<commit_before>package bitbucketserver

import (
	"net/http"
	"bytes"
	"log"
	"io/ioutil"
	"fmt"
	"strings"
	"crypto/md5"
	log "github.com/Sirupsen/logrus"
)

func avatarLink(email string) (url string) {
	data := []byte(strings.ToLower(email))
	emailHash := md5.Sum(data)
	avatarURL := fmt.Sprintf("http://www.gravatar.com/avatar/%s.jpg",emailHash)
	log.Info(avatarURL)
	return avatarURL
}

func doPut(client *http.Client, url string, body []byte) {
	request, err := http.NewRequest("PUT", url, bytes.NewBuffer(body))
	request.Header.Add("Content-Type","application/json")
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("The calculated length is:", len(string(contents)), "for the url:", url)
		fmt.Println("   ", response.StatusCode)
		hdr := response.Header
		for key, value := range hdr {
			fmt.Println("   ", key, ":", value)
		}
		fmt.Println(string(contents))
	}
}

func doDelete(client *http.Client, url string) {
	request, err := http.NewRequest("DELETE", url, nil)
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("The calculated length is:", len(string(contents)), "for the url:", url)
		fmt.Println("   ", response.StatusCode)
		hdr := response.Header
		for key, value := range hdr {
			fmt.Println("   ", key, ":", value)
		}
		fmt.Println(string(contents))
	}
}
<commit_msg>Fixing the url to gravatar to have hex encoding<commit_after>package bitbucketserver

import (
	"net/http"
	"bytes"
	"io/ioutil"
	"fmt"
	"strings"
	"crypto/md5"
	log "github.com/Sirupsen/logrus"
	"encoding/hex"
)

func avatarLink(email string) (url string) {
	hasher := md5.New()
	hasher.Write([]byte(strings.ToLower(email)))
	emailHash := fmt.Sprintf("%v", hex.EncodeToString(hasher.Sum(nil)))
	avatarURL := fmt.Sprintf("http://www.gravatar.com/avatar/%s.jpg",emailHash)
	log.Info(avatarURL)
	return avatarURL
}

func doPut(client *http.Client, url string, body []byte) {
	request, err := http.NewRequest("PUT", url, bytes.NewBuffer(body))
	request.Header.Add("Content-Type","application/json")
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("The calculated length is:", len(string(contents)), "for the url:", url)
		fmt.Println("   ", response.StatusCode)
		hdr := response.Header
		for key, value := range hdr {
			fmt.Println("   ", key, ":", value)
		}
		fmt.Println(string(contents))
	}
}

func doDelete(client *http.Client, url string) {
	request, err := http.NewRequest("DELETE", url, nil)
	response, err := client.Do(request)
	if err != nil {
		log.Fatal(err)
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("The calculated length is:", len(string(contents)), "for the url:", url)
		fmt.Println("   ", response.StatusCode)
		hdr := response.Header
		for key, value := range hdr {
			fmt.Println("   ", key, ":", value)
		}
		fmt.Println(string(contents))
	}
}
<|endoftext|>


<commit_before>package handle

import (
	"net/url"
	"strconv"
	"strings"

	"github.com/polyglottis/platform/content"
	"github.com/polyglottis/platform/frontend"
	"github.com/polyglottis/platform/i18n"
)

type newFlavorArgs struct {
	Language     string
	MainComment  string
	OtherComment string
}

func (a *newFlavorArgs) CleanUp() {
	a.MainComment = strings.TrimSpace(a.MainComment)
	a.OtherComment = strings.TrimSpace(a.OtherComment)
}

func (w *Worker) NewFlavorPOST(context *frontend.Context, session *Session) ([]byte, error) {
	errors := make(frontend.ErrorMap)
	defaults := url.Values{}

	if !context.LoggedIn() {
		errors["FORM"] = i18n.Key("You must sign in to perform this action.")
	}

	e, err := w.readExtract(context)
	if err != nil {
		return nil, err
	}

	args := new(newFlavorArgs)
	err = decoder.Decode(args, context.Form)
	if err != nil {
		return nil, err
	}
	args.CleanUp()

	langCode, err := w.Language.GetCode(args.Language)
	if err == nil {
		defaults.Set("Language", args.Language)
	} else {
		defaults.Set("Language", "")
		errors["Language"] = i18n.Key("Please select an option.")
	}

	var mainComment string
	var otherFlavor *content.Flavor
	if fByType, ok := e.Flavors[langCode]; ok {
		if flavors, ok := fByType[content.Text]; ok {
			if len(flavors) > 0 {
				// MainComment only necessary if there are already other flavors.
				if valid, msg := content.ValidLanguageComment(args.MainComment); valid {
					mainComment = args.MainComment
				} else {
					errors["MainComment"] = msg
				}
			}
			if len(flavors) == 1 {
				// OtherComment only necessary if there is exactly one other flavor.
				if valid, msg := content.ValidLanguageComment(args.OtherComment); valid {
					otherFlavor = flavors[0]
					otherFlavor.LanguageComment = args.OtherComment
				} else {
					errors["OtherComment"] = msg
				}
			}
		}
	}

	if len(errors) != 0 {
		session.SaveFlashErrors(errors)
		defaults.Set("MainComment", args.MainComment)
		defaults.Set("OtherComment", args.OtherComment)
		session.SaveDefaults(defaults)
		return nil, redirectToOther(context.Url)
	}

	if otherFlavor != nil {
		err = w.Content.UpdateFlavor(context.User, otherFlavor)
		if err != nil {
			return nil, err
		}
	}

	f := &content.Flavor{
		ExtractId:       e.Id,
		Type:            content.Text,
		Language:        langCode,
		LanguageComment: mainComment,
	}

	err = w.Content.NewFlavor(context.User, f)
	if err != nil {
		return nil, err
	}

	session.ClearDefaults()
	query := "?a=" + args.Language + "&at=" + strconv.Itoa(int(f.Id))
	return nil, redirectToOther("/extract/edit/text/" + e.UrlSlug + query)
}

func (w *Worker) NewFlavor(context *frontend.Context) ([]byte, error) {
	extract, err := w.readExtract(context)
	if err != nil {
		return nil, err
	}
	// avoid sending too much over rpc
	// TODO do not read the blocks at all in the database
	for _, fByType := range extract.Flavors {
		for _, flavors := range fByType {
			for _, f := range flavors {
				f.Blocks = nil
			}
		}
	}

	return w.Server.NewFlavor(context, extract)
}
<commit_msg>Keep url query<commit_after>package handle

import (
	"net/url"
	"strconv"
	"strings"

	"github.com/polyglottis/platform/content"
	"github.com/polyglottis/platform/frontend"
	"github.com/polyglottis/platform/i18n"
)

type newFlavorArgs struct {
	Language     string
	MainComment  string
	OtherComment string
}

func (a *newFlavorArgs) CleanUp() {
	a.MainComment = strings.TrimSpace(a.MainComment)
	a.OtherComment = strings.TrimSpace(a.OtherComment)
}

func (w *Worker) NewFlavorPOST(context *frontend.Context, session *Session) ([]byte, error) {
	errors := make(frontend.ErrorMap)
	defaults := url.Values{}

	if !context.LoggedIn() {
		errors["FORM"] = i18n.Key("You must sign in to perform this action.")
	}

	e, err := w.readExtract(context)
	if err != nil {
		return nil, err
	}

	args := new(newFlavorArgs)
	err = decoder.Decode(args, context.Form)
	if err != nil {
		return nil, err
	}
	args.CleanUp()

	langCode, err := w.Language.GetCode(args.Language)
	if err == nil {
		defaults.Set("Language", args.Language)
	} else {
		defaults.Set("Language", "")
		errors["Language"] = i18n.Key("Please select an option.")
	}

	var mainComment string
	var otherFlavor *content.Flavor
	if fByType, ok := e.Flavors[langCode]; ok {
		if flavors, ok := fByType[content.Text]; ok {
			if len(flavors) > 0 {
				// MainComment only necessary if there are already other flavors.
				if valid, msg := content.ValidLanguageComment(args.MainComment); valid {
					mainComment = args.MainComment
				} else {
					errors["MainComment"] = msg
				}
			}
			if len(flavors) == 1 {
				// OtherComment only necessary if there is exactly one other flavor.
				if valid, msg := content.ValidLanguageComment(args.OtherComment); valid {
					otherFlavor = flavors[0]
					otherFlavor.LanguageComment = args.OtherComment
				} else {
					errors["OtherComment"] = msg
				}
			}
		}
	}

	if len(errors) != 0 {
		session.SaveFlashErrors(errors)
		defaults.Set("MainComment", args.MainComment)
		defaults.Set("OtherComment", args.OtherComment)
		session.SaveDefaults(defaults)
		return nil, redirectToOther(context.Url)
	}

	if otherFlavor != nil {
		err = w.Content.UpdateFlavor(context.User, otherFlavor)
		if err != nil {
			return nil, err
		}
	}

	f := &content.Flavor{
		ExtractId:       e.Id,
		Type:            content.Text,
		Language:        langCode,
		LanguageComment: mainComment,
	}

	err = w.Content.NewFlavor(context.User, f)
	if err != nil {
		return nil, err
	}

	session.ClearDefaults()
	context.Query.Set("a", args.Language)
	context.Query.Set("at", strconv.Itoa(int(f.Id)))
	return nil, redirectToOther("/extract/edit/text/" + e.UrlSlug + "?" + context.Query.Encode())
}

func (w *Worker) NewFlavor(context *frontend.Context) ([]byte, error) {
	extract, err := w.readExtract(context)
	if err != nil {
		return nil, err
	}
	// avoid sending too much over rpc
	// TODO do not read the blocks at all in the database
	for _, fByType := range extract.Flavors {
		for _, flavors := range fByType {
			for _, f := range flavors {
				f.Blocks = nil
			}
		}
	}

	return w.Server.NewFlavor(context, extract)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"html/template"
	"net/http"

	"github.com/elazarl/go-bindata-assetfs"
	"github.com/gorilla/websocket"
	bloomsky "github.com/patrickalin/bloomsky-api-go"
	"github.com/patrickalin/bloomsky-client-go/assembly-assetfs"
	"github.com/patrickalin/bloomsky-client-go/utils"
	"github.com/sirupsen/logrus"
)

var conn *websocket.Conn
var mybloomsky bloomsky.BloomskyStructure
var msgJSON []byte

type httpServer struct {
	bloomskyMessageToHTTP chan bloomsky.BloomskyStructure
	h                     *http.Server
}

func (h *httpServer) listen(context context.Context) {
	go func() {
		for {
			mybloomsky := <-h.bloomskyMessageToHTTP
			var err error
			msgJSON, err = json.Marshal(mybloomsky)
			log.Debugf("JSON : %s", msgJSON)

			if err != nil {
				log.Infof("Marshal json Error: %v", err)
				return
			}

			if conn != nil {
				err = conn.WriteMessage(websocket.TextMessage, msgJSON)
				if err != nil {
					log.Infof("Impossible to write to websocket : %v", err)
				}
			}
			log.Debug("Message send to browser")
		}
	}()
}

// Websocket handler
func (h *httpServer) refreshdata(w http.ResponseWriter, r *http.Request) {
	log.Debugf("Refresdata WS handle Send JSON : %s", msgJSON)

	upgrader := websocket.Upgrader{}
	var err error

	conn, err = upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Errorf("Upgrade upgrader : %v", err)
		return
	}

	err = conn.WriteMessage(websocket.TextMessage, msgJSON)
	if err != nil {
		log.Errorf("Impossible to write to websocket : %v", err)
	}

}

func (h *httpServer) home(w http.ResponseWriter, r *http.Request) {
	log.Debugf("Home Http handle Send JSON : %s", msgJSON)

	var err error
	var templateHeader *template.Template
	var templateBody *template.Template

	templateHeader = utils.GetHtmlTemplate("bloomsky_header.html", "tmpl/bloomsky_header.html", map[string]interface{}{"T": config.translateFunc}, config.dev)

	err = templateHeader.Execute(w, "ws://"+r.Host+"/refreshdata")
	if err != nil {
		log.Fatalf("Write part 1 : %v", err)
	}
	templateBody = utils.GetHtmlTemplate("bloomsky_body.html", "tmpl/bloomsky_body.html", map[string]interface{}{"T": config.translateFunc}, config.dev)

	err = templateBody.Execute(w, mybloomsky)
	if err != nil {
		log.Fatalf("Write part 2 : %v", err)
	}
}

//createWebServer create web server
func createWebServer(in chan bloomsky.BloomskyStructure, HTTPPort string) (*httpServer, error) {
	server := &httpServer{bloomskyMessageToHTTP: in}

	fs := http.FileServer(&assetfs.AssetFS{Asset: assemblyAssetfs.Asset, AssetDir: assemblyAssetfs.AssetDir, AssetInfo: assemblyAssetfs.AssetInfo, Prefix: "static"})

	s := http.NewServeMux()

	s.Handle("/static/", http.StripPrefix("/static/", fs))
	s.HandleFunc("/refreshdata", server.refreshdata)
	s.HandleFunc("/", server.home)

	h := &http.Server{Addr: HTTPPort, Handler: s}
	go func() {
		if err := h.ListenAndServe(); err != nil {
			log.Errorf("Error when I create the server : %v", err)
		}
	}()
	logrus.Infof("Server listen on port %s", HTTPPort)
	server.h = h
	return server, nil
}
<commit_msg>Add comment and rename var<commit_after>package main

import (
	"context"
	"encoding/json"
	"html/template"
	"net/http"

	"github.com/elazarl/go-bindata-assetfs"
	"github.com/gorilla/websocket"
	bloomsky "github.com/patrickalin/bloomsky-api-go"
	"github.com/patrickalin/bloomsky-client-go/assembly-assetfs"
	"github.com/patrickalin/bloomsky-client-go/utils"
	"github.com/sirupsen/logrus"
)

var (
	conn       *websocket.Conn
	mybloomsky bloomsky.BloomskyStructure
	msgJSON    []byte
)

type httpServer struct {
	bloomskyMessageToHTTP chan bloomsky.BloomskyStructure
	httpServ              *http.Server
}

func (httpServ *httpServer) listen(context context.Context) {
	go func() {
		for {
			var err error
			mybloomsky := <-httpServ.bloomskyMessageToHTTP
			msgJSON, err = json.Marshal(mybloomsky)
			log.Debugf("JSON : %s", msgJSON)

			if err != nil {
				log.Infof("Marshal json Error: %v", err)
				return
			}

			if conn != nil {
				err = conn.WriteMessage(websocket.TextMessage, msgJSON)
				if err != nil {
					log.Infof("Impossible to write to websocket : %v", err)
				}
			}
			log.Debug("Message send to browser")
		}
	}()
}

// Websocket handler to send data
func (httpServ *httpServer) refreshdata(w http.ResponseWriter, r *http.Request) {
	log.Debugf("Refresdata WS handle Send JSON : %s", msgJSON)

	upgrader := websocket.Upgrader{}
	var err error

	conn, err = upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Errorf("Upgrade upgrader : %v", err)
		return
	}

	if err = conn.WriteMessage(websocket.TextMessage, msgJSON); err != nil {
		log.Errorf("Impossible to write to websocket : %v", err)
	}

}

//Handler for the page without data
func (httpServ *httpServer) home(w http.ResponseWriter, r *http.Request) {
	log.Debugf("Home Http handle Send JSON : %s", msgJSON)

	var err error
	var templateHeader *template.Template
	var templateBody *template.Template

	templateHeader = utils.GetHtmlTemplate("bloomsky_header.html", "tmpl/bloomsky_header.html", map[string]interface{}{"T": config.translateFunc}, config.dev)

	err = templateHeader.Execute(w, "ws://"+r.Host+"/refreshdata")
	if err != nil {
		log.Fatalf("Write part 1 : %v", err)
	}
	templateBody = utils.GetHtmlTemplate("bloomsky_body.html", "tmpl/bloomsky_body.html", map[string]interface{}{"T": config.translateFunc}, config.dev)

	err = templateBody.Execute(w, mybloomsky)
	if err != nil {
		log.Fatalf("Write part 2 : %v", err)
	}
}

//createWebServer create web server
func createWebServer(in chan bloomsky.BloomskyStructure, HTTPPort string) (*httpServer, error) {
	server := &httpServer{bloomskyMessageToHTTP: in}

	fs := http.FileServer(&assetfs.AssetFS{Asset: assemblyAssetfs.Asset, AssetDir: assemblyAssetfs.AssetDir, AssetInfo: assemblyAssetfs.AssetInfo, Prefix: "static"})

	s := http.NewServeMux()

	s.Handle("/static/", http.StripPrefix("/static/", fs))
	s.HandleFunc("/refreshdata", server.refreshdata)
	s.HandleFunc("/", server.home)

	h := &http.Server{Addr: HTTPPort, Handler: s}
	go func() {
		if err := h.ListenAndServe(); err != nil {
			log.Errorf("Error when I create the server : %v", err)
		}
	}()
	logrus.Infof("Server listen on port %s", HTTPPort)
	server.h = h
	return server, nil
}
<|endoftext|>


<commit_before>package entity

// ParentTextIdentifier identifies an entity's parent via string ID.
type ParentTextIdentifier interface {

	// Parent returns the parent identifier.
	Parent() (kind string, id string)

	// SetParent sets the parent identifier.
	SetParent(kind string, id string)
}

// ParentTextID represents an entity's parent string identifier.
type ParentTextID struct {
	parentKind string
	parentID   string
}

// Parent returns the parent identifier.
func (mdl *ParentTextID) Parent() (kind string, id string) {
	return mdl.parentKind, mdl.parentID
}

// Parent sets the parent identifier.
func (mdl *ParentTextID) SetParent(kind string, id string) {
	mdl.parentKind = kind
	mdl.parentID = id
}

// ParentNumIdentifier identifies an entity's parent via numeric ID.
type ParentNumIdentifier interface {

	// Parent returns the parent identifier.
	Parent() (kind string, id int64)

	// SetParent sets the parent identifier.
	SetParent(kind string, id int64)
}

// ParentNumID represents an entity's parent numeric identifier.
type ParentNumID struct {
	parentKind string
	parentID   int64
}

// Parent returns the parent identifier.
func (mdl *ParentNumID) Parent() (kind string, id int64) {
	return mdl.parentKind, mdl.parentID
}

// Parent sets the parent identifier.
func (mdl *ParentNumID) SetParent(kind string, id int64) {
	mdl.parentKind = kind
	mdl.parentID = id
}
<commit_msg>golint<commit_after>package entity

// ParentTextIdentifier identifies an entity's parent via string ID.
type ParentTextIdentifier interface {

	// Parent returns the parent identifier.
	Parent() (kind string, id string)

	// SetParent sets the parent identifier.
	SetParent(kind string, id string)
}

// ParentTextID represents an entity's parent string identifier.
type ParentTextID struct {
	parentKind string
	parentID   string
}

// Parent returns the parent identifier.
func (mdl *ParentTextID) Parent() (kind string, id string) {
	return mdl.parentKind, mdl.parentID
}

// SetParent sets the parent identifier.
func (mdl *ParentTextID) SetParent(kind string, id string) {
	mdl.parentKind = kind
	mdl.parentID = id
}

// ParentNumIdentifier identifies an entity's parent via numeric ID.
type ParentNumIdentifier interface {

	// Parent returns the parent identifier.
	Parent() (kind string, id int64)

	// SetParent sets the parent identifier.
	SetParent(kind string, id int64)
}

// ParentNumID represents an entity's parent numeric identifier.
type ParentNumID struct {
	parentKind string
	parentID   int64
}

// Parent returns the parent identifier.
func (mdl *ParentNumID) Parent() (kind string, id int64) {
	return mdl.parentKind, mdl.parentID
}

// SetParent sets the parent identifier.
func (mdl *ParentNumID) SetParent(kind string, id int64) {
	mdl.parentKind = kind
	mdl.parentID = id
}
<|endoftext|>


<commit_before>package supervisor

import (
	"encoding/json"
	"fmt"
	"github.com/pborman/uuid"
	"github.com/starkandwayne/shield/db"
	"net/http"
	"regexp"
)

type ArchiveAPI struct {
	Data       *db.DB
	ResyncChan chan int
	AdhocChan  chan AdhocTask
}

func (self ArchiveAPI) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch {
	case match(req, `GET /v1/archives`):
		archives, err := self.Data.GetAllAnnotatedArchives(
			&db.ArchiveFilter{
				ForTarget: paramValue(req, "target", ""),
				ForStore:  paramValue(req, "store", ""),
				Before:    paramDate(req, "before"),
				After:     paramDate(req, "after"),
			},
		)
		if err != nil {
			bail(w, err)
			return
		}

		JSON(w, archives)
		return

	case match(req, `POST /v1/archive/[a-fA-F0-9-]+/restore`):
		if req.Body == nil {
			w.WriteHeader(400)
			return
		}

		var params struct {
			Target string `json:"target"`
			Owner  string `json:"owner"`
		}
		json.NewDecoder(req.Body).Decode(&params)

		if params.Owner == "" {
			params.Owner = "anon"
		}

		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)/restore`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		// find the archive
		archive, err := self.Data.GetAnnotatedArchive(id)
		if err != nil {
			w.WriteHeader(500)
			return
		}

		if params.Target == "" {
			params.Target = archive.TargetUUID
		}

		tid := uuid.Parse(params.Target)
		// find the target
		_, err = self.Data.GetAnnotatedTarget(id)
		if err != nil {
			w.WriteHeader(501)
			return
		}

		// tell the supervisor to schedule a task
		self.AdhocChan <- AdhocTask{
			Op:          RESTORE,
			Owner:       params.Owner,
			TargetUUID:  tid,
			ArchiveUUID: id,
		}

		w.WriteHeader(200)
		JSONLiteral(w, fmt.Sprintf(`{"ok":"scheduled"}`))
		return

	case match(req, `GET /v1/archive/[a-fA-F0-9-]+`):
		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		archive, err := self.Data.GetAnnotatedArchive(id)
		if err != nil {
			bail(w, err)
			return
		}

		if archive == nil {
			w.WriteHeader(404)
			return
		}

		JSON(w, archive)
		return

	case match(req, `PUT /v1/archive/[a-fA-F0-9-]+`):
		if req.Body == nil {
			w.WriteHeader(400)
			return
		}

		var params struct {
			Notes string `json:"notes"`
		}
		json.NewDecoder(req.Body).Decode(&params)

		if params.Notes == "" {
			w.WriteHeader(400)
			return
		}

		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		_ = self.Data.AnnotateArchive(id, params.Notes)
		self.ResyncChan <- 1
		JSONLiteral(w, fmt.Sprintf(`{"ok":"updated"}`))
		return

	case match(req, `DELETE /v1/archive/[a-fA-F0-9-]+`):
		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		deleted, err := self.Data.DeleteArchive(id)

		if err != nil {
			bail(w, err)
		}
		if !deleted {
			w.WriteHeader(403)
			return
		}

		self.ResyncChan <- 1
		JSONLiteral(w, fmt.Sprintf(`{"ok":"deleted"}`))
		return
	}

	w.WriteHeader(415)
	return
}
<commit_msg>Add restore key to restore job request<commit_after>package supervisor

import (
	"encoding/json"
	"fmt"
	"github.com/pborman/uuid"
	"github.com/starkandwayne/shield/db"
	"net/http"
	"regexp"
)

type ArchiveAPI struct {
	Data       *db.DB
	ResyncChan chan int
	AdhocChan  chan AdhocTask
}

func (self ArchiveAPI) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	switch {
	case match(req, `GET /v1/archives`):
		archives, err := self.Data.GetAllAnnotatedArchives(
			&db.ArchiveFilter{
				ForTarget: paramValue(req, "target", ""),
				ForStore:  paramValue(req, "store", ""),
				Before:    paramDate(req, "before"),
				After:     paramDate(req, "after"),
			},
		)
		if err != nil {
			bail(w, err)
			return
		}

		JSON(w, archives)
		return

	case match(req, `POST /v1/archive/[a-fA-F0-9-]+/restore`):
		if req.Body == nil {
			w.WriteHeader(400)
			return
		}

		var params struct {
			Target string `json:"target"`
			Owner  string `json:"owner"`
		}
		json.NewDecoder(req.Body).Decode(&params)

		if params.Owner == "" {
			params.Owner = "anon"
		}

		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)/restore`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		// find the archive
		archive, err := self.Data.GetAnnotatedArchive(id)
		if err != nil {
			w.WriteHeader(500)
			return
		}

		if params.Target == "" {
			params.Target = archive.TargetUUID
		}

		tid := uuid.Parse(params.Target)
		// find the target
		_, err = self.Data.GetAnnotatedTarget(id)
		if err != nil {
			w.WriteHeader(501)
			return
		}

		// tell the supervisor to schedule a task
		self.AdhocChan <- AdhocTask{
			Op:          RESTORE,
			Owner:       params.Owner,
			TargetUUID:  tid,
			ArchiveUUID: id,
			RestoreKey:  archive.StoreKey,
		}

		w.WriteHeader(200)
		JSONLiteral(w, fmt.Sprintf(`{"ok":"scheduled"}`))
		return

	case match(req, `GET /v1/archive/[a-fA-F0-9-]+`):
		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		archive, err := self.Data.GetAnnotatedArchive(id)
		if err != nil {
			bail(w, err)
			return
		}

		if archive == nil {
			w.WriteHeader(404)
			return
		}

		JSON(w, archive)
		return

	case match(req, `PUT /v1/archive/[a-fA-F0-9-]+`):
		if req.Body == nil {
			w.WriteHeader(400)
			return
		}

		var params struct {
			Notes string `json:"notes"`
		}
		json.NewDecoder(req.Body).Decode(&params)

		if params.Notes == "" {
			w.WriteHeader(400)
			return
		}

		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		_ = self.Data.AnnotateArchive(id, params.Notes)
		self.ResyncChan <- 1
		JSONLiteral(w, fmt.Sprintf(`{"ok":"updated"}`))
		return

	case match(req, `DELETE /v1/archive/[a-fA-F0-9-]+`):
		re := regexp.MustCompile(`^/v1/archive/([a-fA-F0-9-]+)`)
		id := uuid.Parse(re.FindStringSubmatch(req.URL.Path)[1])

		deleted, err := self.Data.DeleteArchive(id)

		if err != nil {
			bail(w, err)
		}
		if !deleted {
			w.WriteHeader(403)
			return
		}

		self.ResyncChan <- 1
		JSONLiteral(w, fmt.Sprintf(`{"ok":"deleted"}`))
		return
	}

	w.WriteHeader(415)
	return
}
<|endoftext|>


<commit_before>package center

import (
	"context"
	"github.com/ZhengHe-MD/agollo/v4"
	"github.com/ZhengHe-MD/properties"
	"github.com/opentracing/opentracing-go"
	"github.com/shawnfeng/sutil/slog/slog"
	"os"
	"strings"
	"sync"
)

const (
	envApolloCluster            = "APOLLO_CLUSTER"
	envApolloHostPort           = "APOLLO_HOST_PORT"
	defaultCluster              = "default"
	defaultHostPort             = "apollo-meta.ibanyu.com:30002"
	defaultCacheDir             = "/tmp/sconfcenter"
	defaultNamespaceApplication = "application"
	defaultChangeEventSize      = 32
)

type apolloConfigCenter struct {
	conf            *agollo.Conf
	ag              *agollo.Agollo
	watchUpdateOnce sync.Once
	changeEventChan chan *ChangeEvent
}

func newApolloConfigCenter() *apolloConfigCenter {
	return &apolloConfigCenter{
		changeEventChan: make(chan *ChangeEvent, defaultChangeEventSize),
	}
}

func getEnvWithDefault(key, defaultValue string) string {
	val := os.Getenv(key)
	if val == "" {
		return defaultValue
	}
	return val
}

func confFromEnv() *agollo.Conf {
	cluster := getEnvWithDefault(envApolloCluster, defaultCluster)
	hostport := getEnvWithDefault(envApolloHostPort, defaultHostPort)

	return &agollo.Conf{
		Cluster:  cluster,
		CacheDir: defaultCacheDir,
		IP:       hostport,
	}
}

// NOTE: apollo 不支持在项目名称中使用 '/'，因此规定用 '.' 代替 '/'
//       base/authapi => base.authapi
func normalizeServiceName(serviceName string) string {
	return strings.Replace(serviceName, "/", ".", -1)
}

func (ap *apolloConfigCenter) Init(ctx context.Context, serviceName string, namespaceNames []string) (err error) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.Init")
	defer span.Finish()

	fun := "apolloConfigCenter.Init-->"

	agollo.SetLogger(slog.GetLogger())

	conf := confFromEnv()
	conf.AppID = normalizeServiceName(serviceName)

	if len(namespaceNames) > 0 {
		conf.NameSpaceNames = namespaceNames
	} else {
		conf.NameSpaceNames = []string{defaultNamespaceApplication}
	}

	for i, namespace := range conf.NameSpaceNames {
		conf.NameSpaceNames[i] = normalizeServiceName(namespace)
	}

	ap.conf = conf
	ap.ag = agollo.NewAgollo(conf)

	slog.Infof(ctx, "%s start agollo with conf:%v", fun, ap.conf)

	if err = ap.ag.Start(); err != nil {
		slog.Warnf(ctx, "%s agollo starts err:%v", fun, err)
	} else {
		slog.Infof(ctx, "%s agollo starts succeed:%v", fun, err)
	}

	return
}

func (ap *apolloConfigCenter) Stop(ctx context.Context) error {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.Stop")
	defer span.Finish()
	return ap.ag.Stop()
}

func (ap *apolloConfigCenter) SubscribeNamespaces(ctx context.Context, namespaceNames []string) error {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.SubscribeNamespaces")
	defer span.Finish()
	return ap.ag.SubscribeToNamespaces(namespaceNames...)
}

func (ap *apolloConfigCenter) GetString(ctx context.Context, key string) (string, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetString")
	defer span.Finish()
	return ap.ag.GetString(key)
}

func (ap *apolloConfigCenter) GetStringWithNamespace(ctx context.Context, namespace, key string) (string, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetStringWithNamespace")
	defer span.Finish()

	return ap.ag.GetStringWithNamespace(namespace, key)
}

func (ap *apolloConfigCenter) GetBool(ctx context.Context, key string) (bool, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetBool")
	defer span.Finish()

	return ap.ag.GetBool(key)
}

func (ap *apolloConfigCenter) GetBoolWithNamespace(ctx context.Context, namespace, key string) (bool, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetBoolWithNamespace")
	defer span.Finish()

	return ap.ag.GetBoolWithNamespace(namespace, key)
}

func (ap *apolloConfigCenter) GetInt(ctx context.Context, key string) (int, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetInt")
	defer span.Finish()

	return ap.ag.GetInt(key)
}

func (ap *apolloConfigCenter) GetIntWithNamespace(ctx context.Context, namespace, key string) (int, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetIntWithNamespace")
	defer span.Finish()

	return ap.ag.GetIntWithNamespace(namespace, key)
}

func (ap *apolloConfigCenter) GetAllKeys(ctx context.Context) []string {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetAllKeys")
	defer span.Finish()

	return ap.ag.GetAllKeys("application")
}

func (ap *apolloConfigCenter) GetAllKeysWithNamespace(ctx context.Context, namespace string) []string {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetAllKeysWithNamespace")
	defer span.Finish()

	return ap.ag.GetAllKeys(namespace)
}

func (ap *apolloConfigCenter) StartWatchUpdate(ctx context.Context) {
	ap.ag.StartWatchUpdate()
}

type agolloObserver struct {
	observer ConfigObserver
}

func (o *agolloObserver) HandleChangeEvent(ce *agollo.ChangeEvent) {
	o.observer.HandleChangeEvent(fromAgolloChangeEvent(ce))
}

func (ap *apolloConfigCenter) RegisterObserver(ctx context.Context, observer ConfigObserver) func() {
	return ap.ag.RegisterObserver(&agolloObserver{observer})
}

func (ap *apolloConfigCenter) Unmarshal(ctx context.Context, v interface{}) error {
	return ap.UnmarshalWithNamespace(ctx, defaultNamespaceApplication, v)
}

func (ap *apolloConfigCenter) UnmarshalWithNamespace(ctx context.Context, namespace string, v interface{}) error {
	var kv = map[string]string{}

	ks := ap.GetAllKeysWithNamespace(ctx, namespace)
	for _, k := range ks {
		if v, ok := ap.GetStringWithNamespace(ctx, namespace, k); ok {
			kv[k] = v
		}
	}

	return properties.UnmarshalKV(kv, v)
}

func (ap *apolloConfigCenter) UnmarshalKey(ctx context.Context, key string, v interface{}) error {
	return ap.UnmarshalKeyWithNamespace(ctx, defaultNamespaceApplication, key, v)
}

func (ap *apolloConfigCenter) UnmarshalKeyWithNamespace(ctx context.Context, namespace string, key string, v interface{}) error {
	var kv = map[string]string{}

	ks := ap.GetAllKeysWithNamespace(ctx, namespace)
	for _, k := range ks {
		if v, ok := ap.GetStringWithNamespace(ctx, namespace, k); ok {
			kv[k] = v
		}
	}

	bs, err := properties.Marshal(&kv)
	if err != nil {
		return err
	}

	return properties.UnmarshalKey(key, bs, v)
}
<commit_msg>log level<commit_after>package center

import (
	"context"
	"github.com/ZhengHe-MD/agollo/v4"
	"github.com/ZhengHe-MD/properties"
	"github.com/opentracing/opentracing-go"
	"github.com/shawnfeng/sutil/slog/slog"
	"os"
	"strings"
	"sync"
)

const (
	envApolloCluster            = "APOLLO_CLUSTER"
	envApolloHostPort           = "APOLLO_HOST_PORT"
	defaultCluster              = "default"
	defaultHostPort             = "apollo-meta.ibanyu.com:30002"
	defaultCacheDir             = "/tmp/sconfcenter"
	defaultNamespaceApplication = "application"
	defaultChangeEventSize      = 32
)

type apolloConfigCenter struct {
	conf            *agollo.Conf
	ag              *agollo.Agollo
	watchUpdateOnce sync.Once
	changeEventChan chan *ChangeEvent
}

func newApolloConfigCenter() *apolloConfigCenter {
	return &apolloConfigCenter{
		changeEventChan: make(chan *ChangeEvent, defaultChangeEventSize),
	}
}

func getEnvWithDefault(key, defaultValue string) string {
	val := os.Getenv(key)
	if val == "" {
		return defaultValue
	}
	return val
}

func confFromEnv() *agollo.Conf {
	cluster := getEnvWithDefault(envApolloCluster, defaultCluster)
	hostport := getEnvWithDefault(envApolloHostPort, defaultHostPort)

	return &agollo.Conf{
		Cluster:  cluster,
		CacheDir: defaultCacheDir,
		IP:       hostport,
	}
}

// NOTE: apollo 不支持在项目名称中使用 '/'，因此规定用 '.' 代替 '/'
//       base/authapi => base.authapi
func normalizeServiceName(serviceName string) string {
	return strings.Replace(serviceName, "/", ".", -1)
}

func (ap *apolloConfigCenter) Init(ctx context.Context, serviceName string, namespaceNames []string) (err error) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.Init")
	defer span.Finish()

	fun := "apolloConfigCenter.Init-->"

	agollo.SetLogger(slog.GetLogger())

	conf := confFromEnv()
	conf.AppID = normalizeServiceName(serviceName)

	if len(namespaceNames) > 0 {
		conf.NameSpaceNames = namespaceNames
	} else {
		conf.NameSpaceNames = []string{defaultNamespaceApplication}
	}

	for i, namespace := range conf.NameSpaceNames {
		conf.NameSpaceNames[i] = normalizeServiceName(namespace)
	}

	ap.conf = conf
	ap.ag = agollo.NewAgollo(conf)

	slog.Infof(ctx, "%s start agollo with conf:%v", fun, ap.conf)

	if err = ap.ag.Start(); err != nil {
		slog.Errorf(ctx, "%s agollo starts err:%v", fun, err)
	} else {
		slog.Infof(ctx, "%s agollo starts succeed:%v", fun, err)
	}

	return
}

func (ap *apolloConfigCenter) Stop(ctx context.Context) error {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.Stop")
	defer span.Finish()
	return ap.ag.Stop()
}

func (ap *apolloConfigCenter) SubscribeNamespaces(ctx context.Context, namespaceNames []string) error {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.SubscribeNamespaces")
	defer span.Finish()
	return ap.ag.SubscribeToNamespaces(namespaceNames...)
}

func (ap *apolloConfigCenter) GetString(ctx context.Context, key string) (string, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetString")
	defer span.Finish()
	return ap.ag.GetString(key)
}

func (ap *apolloConfigCenter) GetStringWithNamespace(ctx context.Context, namespace, key string) (string, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetStringWithNamespace")
	defer span.Finish()

	return ap.ag.GetStringWithNamespace(namespace, key)
}

func (ap *apolloConfigCenter) GetBool(ctx context.Context, key string) (bool, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetBool")
	defer span.Finish()

	return ap.ag.GetBool(key)
}

func (ap *apolloConfigCenter) GetBoolWithNamespace(ctx context.Context, namespace, key string) (bool, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetBoolWithNamespace")
	defer span.Finish()

	return ap.ag.GetBoolWithNamespace(namespace, key)
}

func (ap *apolloConfigCenter) GetInt(ctx context.Context, key string) (int, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetInt")
	defer span.Finish()

	return ap.ag.GetInt(key)
}

func (ap *apolloConfigCenter) GetIntWithNamespace(ctx context.Context, namespace, key string) (int, bool) {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetIntWithNamespace")
	defer span.Finish()

	return ap.ag.GetIntWithNamespace(namespace, key)
}

func (ap *apolloConfigCenter) GetAllKeys(ctx context.Context) []string {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetAllKeys")
	defer span.Finish()

	return ap.ag.GetAllKeys("application")
}

func (ap *apolloConfigCenter) GetAllKeysWithNamespace(ctx context.Context, namespace string) []string {
	span, _ := opentracing.StartSpanFromContext(ctx, "apolloConfigCenter.GetAllKeysWithNamespace")
	defer span.Finish()

	return ap.ag.GetAllKeys(namespace)
}

func (ap *apolloConfigCenter) StartWatchUpdate(ctx context.Context) {
	ap.ag.StartWatchUpdate()
}

type agolloObserver struct {
	observer ConfigObserver
}

func (o *agolloObserver) HandleChangeEvent(ce *agollo.ChangeEvent) {
	o.observer.HandleChangeEvent(fromAgolloChangeEvent(ce))
}

func (ap *apolloConfigCenter) RegisterObserver(ctx context.Context, observer ConfigObserver) func() {
	return ap.ag.RegisterObserver(&agolloObserver{observer})
}

func (ap *apolloConfigCenter) Unmarshal(ctx context.Context, v interface{}) error {
	return ap.UnmarshalWithNamespace(ctx, defaultNamespaceApplication, v)
}

func (ap *apolloConfigCenter) UnmarshalWithNamespace(ctx context.Context, namespace string, v interface{}) error {
	var kv = map[string]string{}

	ks := ap.GetAllKeysWithNamespace(ctx, namespace)
	for _, k := range ks {
		if v, ok := ap.GetStringWithNamespace(ctx, namespace, k); ok {
			kv[k] = v
		}
	}

	return properties.UnmarshalKV(kv, v)
}

func (ap *apolloConfigCenter) UnmarshalKey(ctx context.Context, key string, v interface{}) error {
	return ap.UnmarshalKeyWithNamespace(ctx, defaultNamespaceApplication, key, v)
}

func (ap *apolloConfigCenter) UnmarshalKeyWithNamespace(ctx context.Context, namespace string, key string, v interface{}) error {
	var kv = map[string]string{}

	ks := ap.GetAllKeysWithNamespace(ctx, namespace)
	for _, k := range ks {
		if v, ok := ap.GetStringWithNamespace(ctx, namespace, k); ok {
			kv[k] = v
		}
	}

	bs, err := properties.Marshal(&kv)
	if err != nil {
		return err
	}

	return properties.UnmarshalKey(key, bs, v)
}
<|endoftext|>


<commit_before>// +build windows

package main

import (
	"flag"
	"fmt"
	"time"

	"gopkg.in/dfsr.v0/config"
	"gopkg.in/dfsr.v0/monitor"
	"gopkg.in/dfsr.v0/monitor/consumer/stathatconsumer"

	"golang.org/x/sys/windows/svc"
	"golang.org/x/sys/windows/svc/debug"
	"golang.org/x/sys/windows/svc/eventlog"
)

var elog debug.Log

type dfsrmonitor struct{}

const acceptedCmds = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue

func (m *dfsrmonitor) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
	changes <- svc.Status{State: svc.StartPending}

	// TODO: Move all of this initialization code into its own goroutine with a context for cancellation

	// Step 1: Parse settings
	settings := environment.Settings
	if !environment.IsInteractive {
		elog.Info(1, fmt.Sprintf("Service Args: %v", args))
		settings.Parse(args[1:], flag.ExitOnError)
		elog.Info(1, fmt.Sprintf("Service Settings: %+v", settings))
	}

	// Step 2: Create and start configuration monitor
	elog.Info(EventInitProgress, "Creating configuration monitor.")
	cfg := config.NewDomainMonitor(settings.Domain, settings.ConfigPollingInterval)
	if err := cfg.Start(); err != nil {
		elog.Error(EventInitFailure, fmt.Sprintf("Configuration initialization failure: %v", err))
		return true, ErrConfigInitFailure
	}
	defer cfg.Close()

	cfg.Update()
	if err := cfg.WaitReady(); err != nil { // TODO: Support some sort of timeout
		elog.Error(EventInitFailure, fmt.Sprintf("Configuration initialization failure: %v", err))
		return true, ErrConfigInitFailure
	}

	// Step 3: Create backlog monitor
	elog.Info(EventInitProgress, "Creating backlog monitor.")
	mon := monitor.New(cfg, settings.BacklogPollingInterval, settings.VectorCacheDuration, settings.Limit)
	monChan := mon.Listen(16)

	// Step 4: Create backlog consumers
	if settings.StatHatKey != "" {
		stathatconsumer.New(settings.StatHatKey, settings.StatHatFormat, mon.Listen(16))
	}

	// Step 5: Start backlog monitor
	if err := mon.Start(); err != nil {
		elog.Error(EventInitFailure, fmt.Sprintf("Monitor initialization failure: %v", err))
		return true, 1
	}
	defer mon.Close()

	elog.Info(EventInitComplete, "Initialization complete.")

	changes <- svc.Status{State: svc.Running, Accepts: acceptedCmds}

	mon.Update() // Kick off an initial poll right away

	for {
		select {
		case update, running := <-monChan:
			if !running {
				return
			}
			go watchUpdate(update)
		case c := <-r:
			switch c.Cmd {
			case svc.Interrogate:
				changes <- c.CurrentStatus
				// Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4
				time.Sleep(100 * time.Millisecond)
				changes <- c.CurrentStatus
			case svc.Stop, svc.Shutdown:
				changes <- svc.Status{State: svc.StopPending}
				elog.Info(1, "Received stop command. Stopping service.")
				go func() {
					mon.Close()
					elog.Info(1, "Service stopped.")
				}()
			case svc.Pause:
				changes <- svc.Status{State: svc.Paused, Accepts: acceptedCmds}
				elog.Info(1, "Received pause command. Pausing service.")
				go func() {
					mon.Stop()
					elog.Info(1, "Service paused.")
				}()
			case svc.Continue:
				changes <- svc.Status{State: svc.Running, Accepts: acceptedCmds}
				//elog.Info(1, "Continued")
				elog.Info(1, "Received continue command. Unpausing service.")
				go func() {
					mon.Start()
					elog.Info(1, "Service unpaused.")
				}()
			default:
				elog.Error(1, fmt.Sprintf("Unexpected control request #%d", c))
			}
		}
	}
}

func runService(env *Environment) {
	var err error
	if env.IsDebug {
		elog = debug.New(env.ServiceName)
	} else {
		elog, err = eventlog.Open(env.ServiceName)
		if err != nil {
			return
		}
	}
	defer elog.Close()

	elog.Info(1, fmt.Sprintf("Starting %s service.", env.ServiceName))
	run := svc.Run
	if env.IsDebug {
		run = debug.Run
	}
	err = run(env.ServiceName, &dfsrmonitor{})
	if err != nil {
		elog.Error(1, fmt.Sprintf("Failed to start %s service: %v", env.ServiceName, err))
		return
	}
	elog.Info(1, fmt.Sprintf("Stopped %s service.", env.ServiceName))
}

func watchUpdate(update *monitor.Update) {
	elog.Info(1, fmt.Sprintf("Polling started at %v", update.Start()))
	for backlog := range update.Listen() {
		if backlog.Err != nil {
			elog.Warning(1, fmt.Sprintf("[%s] Backlog from %s to %s: %v", backlog.Group.Name, backlog.From, backlog.To, backlog.Err))
			continue
		}
		if !backlog.IsZero() {
			elog.Info(1, fmt.Sprintf("[%s] Backlog from %s to %s: %v", backlog.Group.Name, backlog.From, backlog.To, backlog.Sum()))
		}
	}
	elog.Info(1, fmt.Sprintf("Polling finished at %v. Total wall time: %v", update.End(), update.Duration()))
}
<commit_msg>dfsrmonitor no longer logs canceled queries<commit_after>// +build windows

package main

import (
	"context"
	"flag"
	"fmt"
	"time"

	"gopkg.in/dfsr.v0/config"
	"gopkg.in/dfsr.v0/monitor"
	"gopkg.in/dfsr.v0/monitor/consumer/stathatconsumer"

	"golang.org/x/sys/windows/svc"
	"golang.org/x/sys/windows/svc/debug"
	"golang.org/x/sys/windows/svc/eventlog"
)

var elog debug.Log

type dfsrmonitor struct{}

const acceptedCmds = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue

func (m *dfsrmonitor) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
	changes <- svc.Status{State: svc.StartPending}

	// TODO: Move all of this initialization code into its own goroutine with a context for cancellation

	// Step 1: Parse settings
	settings := environment.Settings
	if !environment.IsInteractive {
		elog.Info(1, fmt.Sprintf("Service Args: %v", args))
		settings.Parse(args[1:], flag.ExitOnError)
		elog.Info(1, fmt.Sprintf("Service Settings: %+v", settings))
	}

	// Step 2: Create and start configuration monitor
	elog.Info(EventInitProgress, "Creating configuration monitor.")
	cfg := config.NewDomainMonitor(settings.Domain, settings.ConfigPollingInterval)
	if err := cfg.Start(); err != nil {
		elog.Error(EventInitFailure, fmt.Sprintf("Configuration initialization failure: %v", err))
		return true, ErrConfigInitFailure
	}
	defer cfg.Close()

	cfg.Update()
	if err := cfg.WaitReady(); err != nil { // TODO: Support some sort of timeout
		elog.Error(EventInitFailure, fmt.Sprintf("Configuration initialization failure: %v", err))
		return true, ErrConfigInitFailure
	}

	// Step 3: Create backlog monitor
	elog.Info(EventInitProgress, "Creating backlog monitor.")
	mon := monitor.New(cfg, settings.BacklogPollingInterval, settings.VectorCacheDuration, settings.Limit)
	monChan := mon.Listen(16)

	// Step 4: Create backlog consumers
	if settings.StatHatKey != "" {
		stathatconsumer.New(settings.StatHatKey, settings.StatHatFormat, mon.Listen(16))
	}

	// Step 5: Start backlog monitor
	if err := mon.Start(); err != nil {
		elog.Error(EventInitFailure, fmt.Sprintf("Monitor initialization failure: %v", err))
		return true, 1
	}
	defer mon.Close()

	elog.Info(EventInitComplete, "Initialization complete.")

	changes <- svc.Status{State: svc.Running, Accepts: acceptedCmds}

	mon.Update() // Kick off an initial poll right away

	for {
		select {
		case update, running := <-monChan:
			if !running {
				return
			}
			go watchUpdate(update)
		case c := <-r:
			switch c.Cmd {
			case svc.Interrogate:
				changes <- c.CurrentStatus
				// Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4
				time.Sleep(100 * time.Millisecond)
				changes <- c.CurrentStatus
			case svc.Stop, svc.Shutdown:
				changes <- svc.Status{State: svc.StopPending}
				elog.Info(1, "Received stop command. Stopping service.")
				go func() {
					mon.Close()
					elog.Info(1, "Service stopped.")
				}()
			case svc.Pause:
				changes <- svc.Status{State: svc.Paused, Accepts: acceptedCmds}
				elog.Info(1, "Received pause command. Pausing service.")
				go func() {
					mon.Stop()
					elog.Info(1, "Service paused.")
				}()
			case svc.Continue:
				changes <- svc.Status{State: svc.Running, Accepts: acceptedCmds}
				//elog.Info(1, "Continued")
				elog.Info(1, "Received continue command. Unpausing service.")
				go func() {
					mon.Start()
					elog.Info(1, "Service unpaused.")
				}()
			default:
				elog.Error(1, fmt.Sprintf("Unexpected control request #%d", c))
			}
		}
	}
}

func runService(env *Environment) {
	var err error
	if env.IsDebug {
		elog = debug.New(env.ServiceName)
	} else {
		elog, err = eventlog.Open(env.ServiceName)
		if err != nil {
			return
		}
	}
	defer elog.Close()

	elog.Info(1, fmt.Sprintf("Starting %s service.", env.ServiceName))
	run := svc.Run
	if env.IsDebug {
		run = debug.Run
	}
	err = run(env.ServiceName, &dfsrmonitor{})
	if err != nil {
		elog.Error(1, fmt.Sprintf("Failed to start %s service: %v", env.ServiceName, err))
		return
	}
	elog.Info(1, fmt.Sprintf("Stopped %s service.", env.ServiceName))
}

func watchUpdate(update *monitor.Update) {
	elog.Info(1, fmt.Sprintf("Polling started at %v", update.Start()))
	for backlog := range update.Listen() {
		if backlog.Err != nil {
			if !isCancellationErr(backlog.Err) {
				elog.Warning(1, fmt.Sprintf("[%s] Backlog from %s to %s: %v", backlog.Group.Name, backlog.From, backlog.To, backlog.Err))
			}
			continue
		}
		if !backlog.IsZero() {
			elog.Info(1, fmt.Sprintf("[%s] Backlog from %s to %s: %v", backlog.Group.Name, backlog.From, backlog.To, backlog.Sum()))
		}
	}
	elog.Info(1, fmt.Sprintf("Polling finished at %v. Total wall time: %v", update.End(), update.Duration()))
}

func isCancellationErr(err error) bool {
	switch err {
	case context.Canceled, context.DeadlineExceeded:
		return true
	default:
		return false
	}
}
<|endoftext|>


<commit_before>package main

import (
	"reflect"
	"testing"
)

func TestMatchLongest(t *testing.T) {
	tests := []struct {
		fst string
		snd string
		res string
	}{
		{"", "", ""},
		{"", "foo", ""},
		{"foo", "", ""},
		{"foo", "bar", ""},
		{"foo", "foobar", "foo"},
		{"foo", "barfoo", ""},
		{"foobar", "foobaz", "fooba"},
	}

	for _, test := range tests {
		if l := matchLongest(test.fst, test.snd); l != test.res {
			t.Errorf("at input '%s' and '%s' expected '%s' but got '%s'", test.fst, test.snd, test.res, l)
		}
	}
}

func TestMatchWord(t *testing.T) {
	tests := []struct {
		s       string
		words   []string
		matches []string
		longest string
	}{
		{"fo", []string{"foo", "bar", "baz"}, []string{"foo"}, "foo "},
		{"ba", []string{"foo", "bar", "baz"}, []string{"bar", "baz"}, "ba"},
		{"fo", []string{"bar", "baz"}, nil, "fo"},
	}

	for _, test := range tests {
		m, l := matchWord(test.s, test.words)

		if !reflect.DeepEqual(m, test.matches) {
			t.Errorf("at input '%s' with '%s' expected '%s' but got '%s'", test.s, test.words, test.matches, m)
		}

		if l != test.longest {
			t.Errorf("at input '%s' with '%s' expected '%s' but got '%s'", test.s, test.words, test.longest, l)
		}
	}
}
<commit_msg>add empty match tests<commit_after>package main

import (
	"reflect"
	"testing"
)

func TestMatchLongest(t *testing.T) {
	tests := []struct {
		fst string
		snd string
		res string
	}{
		{"", "", ""},
		{"", "foo", ""},
		{"foo", "", ""},
		{"foo", "bar", ""},
		{"foo", "foobar", "foo"},
		{"foo", "barfoo", ""},
		{"foobar", "foobaz", "fooba"},
	}

	for _, test := range tests {
		if l := matchLongest(test.fst, test.snd); l != test.res {
			t.Errorf("at input '%s' and '%s' expected '%s' but got '%s'", test.fst, test.snd, test.res, l)
		}
	}
}

func TestMatchWord(t *testing.T) {
	tests := []struct {
		s       string
		words   []string
		matches []string
		longest string
	}{
		{"", nil, nil, ""},
		{"", []string{"foo", "bar", "baz"}, []string{"foo", "bar", "baz"}, ""},
		{"fo", []string{"foo", "bar", "baz"}, []string{"foo"}, "foo "},
		{"ba", []string{"foo", "bar", "baz"}, []string{"bar", "baz"}, "ba"},
		{"fo", []string{"bar", "baz"}, nil, "fo"},
	}

	for _, test := range tests {
		m, l := matchWord(test.s, test.words)

		if !reflect.DeepEqual(m, test.matches) {
			t.Errorf("at input '%s' with '%s' expected '%s' but got '%s'", test.s, test.words, test.matches, m)
		}

		if l != test.longest {
			t.Errorf("at input '%s' with '%s' expected '%s' but got '%s'", test.s, test.words, test.longest, l)
		}
	}
}
<|endoftext|>