<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/client"
	"github.com/docker/docker/cli"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
)

var (
	commonFlags = cliflags.InitCommonFlags()
	clientFlags = initClientFlags(commonFlags)
	flHelp      = flag.Bool([]string{"h", "-help"}, false, "Print usage")
	flVersion   = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
)

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()

	logrus.SetOutput(stderr)

	flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)

	flag.Usage = func() {
		fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n       docker [ --help | -v | --version ]\n\n")
		fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")

		flag.CommandLine.SetOutput(stdout)
		flag.PrintDefaults()

		help := "\nCommands:\n"

		dockerCommands := sortCommands(cli.DockerCommandUsage)
		for _, cmd := range dockerCommands {
			help += fmt.Sprintf("    %-10.10s%s\n", cmd.Name, cmd.Description)
		}

		help += "\nRun 'docker COMMAND --help' for more information on a command."
		fmt.Fprintf(stdout, "%s\n", help)
	}

	flag.Parse()

	if *flVersion {
		showVersion()
		return
	}

	if *flHelp {
		// if global flag --help is present, regardless of what other options and commands there are,
		// just print the usage.
		flag.Usage()
		return
	}

	clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)

	c := cli.New(clientCli, NewDaemonProxy())
	if err := c.Run(flag.Args()...); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	if utils.ExperimentalBuild() {
		fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.Version, dockerversion.GitCommit)
	} else {
		fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
	}
}

func initClientFlags(commonFlags *cliflags.CommonFlags) *cliflags.ClientFlags {
	clientFlags := &cliflags.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
	client := clientFlags.FlagSet
	client.StringVar(&clientFlags.ConfigDir, []string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")

	clientFlags.PostParse = func() {
		clientFlags.Common.PostParse()

		if clientFlags.ConfigDir != "" {
			cliconfig.SetConfigDir(clientFlags.ConfigDir)
		}

		if clientFlags.Common.TrustKey == "" {
			clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile)
		}

		if clientFlags.Common.Debug {
			utils.EnableDebug()
		}
	}
	return clientFlags
}
<commit_msg>Migrate volume commands to cobra.<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/client"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/cobraadaptor"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
)

var (
	commonFlags = cliflags.InitCommonFlags()
	clientFlags = initClientFlags(commonFlags)
	flHelp      = flag.Bool([]string{"h", "-help"}, false, "Print usage")
	flVersion   = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
)

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()

	logrus.SetOutput(stderr)

	flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)

	cobraAdaptor := cobraadaptor.NewCobraAdaptor(clientFlags)

	flag.Usage = func() {
		fmt.Fprint(stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n       docker [ --help | -v | --version ]\n\n")
		fmt.Fprint(stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")

		flag.CommandLine.SetOutput(stdout)
		flag.PrintDefaults()

		help := "\nCommands:\n"

		dockerCommands := append(cli.DockerCommandUsage, cobraAdaptor.Usage()...)
		for _, cmd := range sortCommands(dockerCommands) {
			help += fmt.Sprintf("    %-10.10s%s\n", cmd.Name, cmd.Description)
		}

		help += "\nRun 'docker COMMAND --help' for more information on a command."
		fmt.Fprintf(stdout, "%s\n", help)
	}

	flag.Parse()

	if *flVersion {
		showVersion()
		return
	}

	if *flHelp {
		// if global flag --help is present, regardless of what other options and commands there are,
		// just print the usage.
		flag.Usage()
		return
	}

	clientCli := client.NewDockerCli(stdin, stdout, stderr, clientFlags)

	c := cli.New(clientCli, NewDaemonProxy(), cobraAdaptor)
	if err := c.Run(flag.Args()...); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	if utils.ExperimentalBuild() {
		fmt.Printf("Docker version %s, build %s, experimental\n", dockerversion.Version, dockerversion.GitCommit)
	} else {
		fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
	}
}

func initClientFlags(commonFlags *cliflags.CommonFlags) *cliflags.ClientFlags {
	clientFlags := &cliflags.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
	client := clientFlags.FlagSet
	client.StringVar(&clientFlags.ConfigDir, []string{"-config"}, cliconfig.ConfigDir(), "Location of client config files")

	clientFlags.PostParse = func() {
		clientFlags.Common.PostParse()

		if clientFlags.ConfigDir != "" {
			cliconfig.SetConfigDir(clientFlags.ConfigDir)
		}

		if clientFlags.Common.TrustKey == "" {
			clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile)
		}

		if clientFlags.Common.Debug {
			utils.EnableDebug()
		}
	}
	return clientFlags
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Rohith All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package marathon

import (
	"errors"
	"fmt"
)

// Container is the definition for a container type in marathon
type Container struct {
	Type    string    `json:"type,omitempty"`
	Docker  *Docker   `json:"docker,omitempty"`
	Volumes *[]Volume `json:"volumes,omitempty"`
}

// PortMapping is the portmapping structure between container and mesos
type PortMapping struct {
	ContainerPort int                `json:"containerPort,omitempty"`
	HostPort      int                `json:"hostPort"`
	Labels        *map[string]string `json:"labels,omitempty"`
	Name          string             `json:"name,omitempty"`
	ServicePort   int                `json:"servicePort,omitempty"`
	Protocol      string             `json:"protocol,omitempty"`
}

// Parameters is the parameters to pass to the docker client when creating the container
type Parameters struct {
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

// Volume is the docker volume details associated to the container
type Volume struct {
	ContainerPath string          `json:"containerPath,omitempty"`
	HostPath      string          `json:"hostPath,omitempty"`
	External      *ExternalVolume `json:"external,omitempty"`
	Mode          string          `json:"mode,omitempty"`
}

// An external volume definition
type ExternalVolume struct {
	Name     string             `json:"name,omitempty"`
	Provider string             `json:"provider,omitempty"`
	Options  *map[string]string `json:"options,omitempty"`
}

// Docker is the docker definition from a marathon application
type Docker struct {
	ForcePullImage *bool          `json:"forcePullImage,omitempty"`
	Image          string         `json:"image,omitempty"`
	Network        string         `json:"network,omitempty"`
	Parameters     *[]Parameters  `json:"parameters,omitempty"`
	PortMappings   *[]PortMapping `json:"portMappings,omitempty"`
	Privileged     *bool          `json:"privileged,omitempty"`
}

// Volume attachs a volume to the container
//		host_path:			the path on the docker host to map
//		container_path:		the path inside the container to map the host volume
//		mode:				the mode to map the container
func (container *Container) Volume(hostPath, containerPath, mode string) *Container {
	if container.Volumes == nil {
		container.EmptyVolumes()
	}

	volumes := *container.Volumes
	volumes = append(volumes, Volume{
		ContainerPath: containerPath,
		HostPath:      hostPath,
		Mode:          mode,
	})

	container.Volumes = &volumes

	return container
}

// EmptyVolumes explicitly empties the volumes -- use this if you need to empty
// volumes of an application that already has volumes set (setting volumes to nil will
// keep the current value)
func (container *Container) EmptyVolumes() *Container {
	container.Volumes = &[]Volume{}
	return container
}

// Define external elements for a volume
//      name: the name of the volume
//      provider: the provider of the volume (e.g. dvdi)
func (v *Volume) SetExternalVolume(name, provider string) *ExternalVolume {
	ev := &ExternalVolume{
		Name:     name,
		Provider: provider,
	}
	v.External = ev
	return ev
}

// Empty the external volume definition
func (v *Volume) EmptyExternalVolume() *Volume {
	v.External = &ExternalVolume{}
	return v
}

// AddOption adds an option to an ExternalVolume
//		name:  the name of the option
//		value: value for the option
func (ev *ExternalVolume) AddOption(name, value string) *ExternalVolume {
	if ev.Options == nil {
		ev.EmptyOptions()
	}
	(*ev.Options)[name] = value

	return ev
}

// EmptyOptions explicitly empties the options
func (ev *ExternalVolume) EmptyOptions() *ExternalVolume {
	ev.Options = &map[string]string{}

	return ev
}

// NewDockerContainer creates a default docker container for you
func NewDockerContainer() *Container {
	container := &Container{}
	container.Type = "DOCKER"
	container.Docker = &Docker{}

	return container
}

// SetForcePullImage sets whether the docker image should always be force pulled before
// starting an instance
//		forcePull:			true / false
func (docker *Docker) SetForcePullImage(forcePull bool) *Docker {
	docker.ForcePullImage = &forcePull

	return docker
}

// SetPrivileged sets whether the docker image should be started
// with privilege turned on
//		priv:			true / false
func (docker *Docker) SetPrivileged(priv bool) *Docker {
	docker.Privileged = &priv

	return docker
}

// Container sets the image of the container
//		image:			the image name you are using
func (docker *Docker) Container(image string) *Docker {
	docker.Image = image
	return docker
}

// Bridged sets the networking mode to bridged
func (docker *Docker) Bridged() *Docker {
	docker.Network = "BRIDGE"
	return docker
}

// Host sets the networking mode to host
func (docker *Docker) Host() *Docker {
	docker.Network = "HOST"
	return docker
}

// Expose sets the container to expose the following TCP ports
//		ports:			the TCP ports the container is exposing
func (docker *Docker) Expose(ports ...int) *Docker {
	for _, port := range ports {
		docker.ExposePort(PortMapping{
			ContainerPort: port,
			HostPort:      0,
			ServicePort:   0,
			Protocol:      "tcp"})
	}
	return docker
}

// ExposeUDP sets the container to expose the following UDP ports
//		ports:			the UDP ports the container is exposing
func (docker *Docker) ExposeUDP(ports ...int) *Docker {
	for _, port := range ports {
		docker.ExposePort(PortMapping{
			ContainerPort: port,
			HostPort:      0,
			ServicePort:   0,
			Protocol:      "udp"})
	}
	return docker
}

// ExposePort exposes an port in the container
func (docker *Docker) ExposePort(portMapping PortMapping) *Docker {
	if docker.PortMappings == nil {
		docker.EmptyPortMappings()
	}

	portMappings := *docker.PortMappings
	portMappings = append(portMappings, portMapping)
	docker.PortMappings = &portMappings

	return docker
}

// EmptyPortMappings explicitly empties the port mappings -- use this if you need to empty
// port mappings of an application that already has port mappings set (setting port mappings to nil will
// keep the current value)
func (docker *Docker) EmptyPortMappings() *Docker {
	docker.PortMappings = &[]PortMapping{}
	return docker
}

// AddLabel adds a label to a PortMapping
//		name:	the name of the label
//		value: value for this label
func (p *PortMapping) AddLabel(name, value string) *PortMapping {
	if p.Labels == nil {
		p.EmptyLabels()
	}
	(*p.Labels)[name] = value

	return p
}

// EmptyLabels explicitly empties the labels -- use this if you need to empty
// the labels of a port mapping that already has labels set (setting labels to
// nil will keep the current value)
func (p *PortMapping) EmptyLabels() *PortMapping {
	p.Labels = &map[string]string{}

	return p
}

// AddParameter adds a parameter to the docker execution line when creating the container
//		key:			the name of the option to add
//		value:		the value of the option
func (docker *Docker) AddParameter(key string, value string) *Docker {
	if docker.Parameters == nil {
		docker.EmptyParameters()
	}

	parameters := *docker.Parameters
	parameters = append(parameters, Parameters{
		Key:   key,
		Value: value})

	docker.Parameters = &parameters

	return docker
}

// EmptyParameters explicitly empties the parameters -- use this if you need to empty
// parameters of an application that already has parameters set (setting parameters to nil will
// keep the current value)
func (docker *Docker) EmptyParameters() *Docker {
	docker.Parameters = &[]Parameters{}
	return docker
}

// ServicePortIndex finds the service port index of the exposed port
//		port:			the port you are looking for
func (docker *Docker) ServicePortIndex(port int) (int, error) {
	if docker.PortMappings == nil || len(*docker.PortMappings) == 0 {
		return 0, errors.New("The docker does not contain any port mappings to search")
	}

	// step: iterate and find the port
	for index, containerPort := range *docker.PortMappings {
		if containerPort.ContainerPort == port {
			return index, nil
		}
	}

	// step: we didn't find the port in the mappings
	return 0, fmt.Errorf("The container port required was not found in the container port mappings")
}
<commit_msg>Go Vetting<commit_after>/*
Copyright 2014 Rohith All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package marathon

import (
	"errors"
	"fmt"
)

// Container is the definition for a container type in marathon
type Container struct {
	Type    string    `json:"type,omitempty"`
	Docker  *Docker   `json:"docker,omitempty"`
	Volumes *[]Volume `json:"volumes,omitempty"`
}

// PortMapping is the portmapping structure between container and mesos
type PortMapping struct {
	ContainerPort int                `json:"containerPort,omitempty"`
	HostPort      int                `json:"hostPort"`
	Labels        *map[string]string `json:"labels,omitempty"`
	Name          string             `json:"name,omitempty"`
	ServicePort   int                `json:"servicePort,omitempty"`
	Protocol      string             `json:"protocol,omitempty"`
}

// Parameters is the parameters to pass to the docker client when creating the container
type Parameters struct {
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

// Volume is the docker volume details associated to the container
type Volume struct {
	ContainerPath string          `json:"containerPath,omitempty"`
	HostPath      string          `json:"hostPath,omitempty"`
	External      *ExternalVolume `json:"external,omitempty"`
	Mode          string          `json:"mode,omitempty"`
}

// ExternalVolume is an external volume definition
type ExternalVolume struct {
	Name     string             `json:"name,omitempty"`
	Provider string             `json:"provider,omitempty"`
	Options  *map[string]string `json:"options,omitempty"`
}

// Docker is the docker definition from a marathon application
type Docker struct {
	ForcePullImage *bool          `json:"forcePullImage,omitempty"`
	Image          string         `json:"image,omitempty"`
	Network        string         `json:"network,omitempty"`
	Parameters     *[]Parameters  `json:"parameters,omitempty"`
	PortMappings   *[]PortMapping `json:"portMappings,omitempty"`
	Privileged     *bool          `json:"privileged,omitempty"`
}

// Volume attachs a volume to the container
//		host_path:			the path on the docker host to map
//		container_path:		the path inside the container to map the host volume
//		mode:				the mode to map the container
func (container *Container) Volume(hostPath, containerPath, mode string) *Container {
	if container.Volumes == nil {
		container.EmptyVolumes()
	}

	volumes := *container.Volumes
	volumes = append(volumes, Volume{
		ContainerPath: containerPath,
		HostPath:      hostPath,
		Mode:          mode,
	})

	container.Volumes = &volumes

	return container
}

// EmptyVolumes explicitly empties the volumes -- use this if you need to empty
// volumes of an application that already has volumes set (setting volumes to nil will
// keep the current value)
func (container *Container) EmptyVolumes() *Container {
	container.Volumes = &[]Volume{}
	return container
}

// SetExternalVolume define external elements for a volume
//      name: the name of the volume
//      provider: the provider of the volume (e.g. dvdi)
func (v *Volume) SetExternalVolume(name, provider string) *ExternalVolume {
	ev := &ExternalVolume{
		Name:     name,
		Provider: provider,
	}
	v.External = ev
	return ev
}

// EmptyExternalVolume emptys the external volume definition
func (v *Volume) EmptyExternalVolume() *Volume {
	v.External = &ExternalVolume{}
	return v
}

// AddOption adds an option to an ExternalVolume
//		name:  the name of the option
//		value: value for the option
func (ev *ExternalVolume) AddOption(name, value string) *ExternalVolume {
	if ev.Options == nil {
		ev.EmptyOptions()
	}
	(*ev.Options)[name] = value

	return ev
}

// EmptyOptions explicitly empties the options
func (ev *ExternalVolume) EmptyOptions() *ExternalVolume {
	ev.Options = &map[string]string{}

	return ev
}

// NewDockerContainer creates a default docker container for you
func NewDockerContainer() *Container {
	container := &Container{}
	container.Type = "DOCKER"
	container.Docker = &Docker{}

	return container
}

// SetForcePullImage sets whether the docker image should always be force pulled before
// starting an instance
//		forcePull:			true / false
func (docker *Docker) SetForcePullImage(forcePull bool) *Docker {
	docker.ForcePullImage = &forcePull

	return docker
}

// SetPrivileged sets whether the docker image should be started
// with privilege turned on
//		priv:			true / false
func (docker *Docker) SetPrivileged(priv bool) *Docker {
	docker.Privileged = &priv

	return docker
}

// Container sets the image of the container
//		image:			the image name you are using
func (docker *Docker) Container(image string) *Docker {
	docker.Image = image
	return docker
}

// Bridged sets the networking mode to bridged
func (docker *Docker) Bridged() *Docker {
	docker.Network = "BRIDGE"
	return docker
}

// Host sets the networking mode to host
func (docker *Docker) Host() *Docker {
	docker.Network = "HOST"
	return docker
}

// Expose sets the container to expose the following TCP ports
//		ports:			the TCP ports the container is exposing
func (docker *Docker) Expose(ports ...int) *Docker {
	for _, port := range ports {
		docker.ExposePort(PortMapping{
			ContainerPort: port,
			HostPort:      0,
			ServicePort:   0,
			Protocol:      "tcp"})
	}
	return docker
}

// ExposeUDP sets the container to expose the following UDP ports
//		ports:			the UDP ports the container is exposing
func (docker *Docker) ExposeUDP(ports ...int) *Docker {
	for _, port := range ports {
		docker.ExposePort(PortMapping{
			ContainerPort: port,
			HostPort:      0,
			ServicePort:   0,
			Protocol:      "udp"})
	}
	return docker
}

// ExposePort exposes an port in the container
func (docker *Docker) ExposePort(portMapping PortMapping) *Docker {
	if docker.PortMappings == nil {
		docker.EmptyPortMappings()
	}

	portMappings := *docker.PortMappings
	portMappings = append(portMappings, portMapping)
	docker.PortMappings = &portMappings

	return docker
}

// EmptyPortMappings explicitly empties the port mappings -- use this if you need to empty
// port mappings of an application that already has port mappings set (setting port mappings to nil will
// keep the current value)
func (docker *Docker) EmptyPortMappings() *Docker {
	docker.PortMappings = &[]PortMapping{}
	return docker
}

// AddLabel adds a label to a PortMapping
//		name:	the name of the label
//		value: value for this label
func (p *PortMapping) AddLabel(name, value string) *PortMapping {
	if p.Labels == nil {
		p.EmptyLabels()
	}
	(*p.Labels)[name] = value

	return p
}

// EmptyLabels explicitly empties the labels -- use this if you need to empty
// the labels of a port mapping that already has labels set (setting labels to
// nil will keep the current value)
func (p *PortMapping) EmptyLabels() *PortMapping {
	p.Labels = &map[string]string{}

	return p
}

// AddParameter adds a parameter to the docker execution line when creating the container
//		key:			the name of the option to add
//		value:		the value of the option
func (docker *Docker) AddParameter(key string, value string) *Docker {
	if docker.Parameters == nil {
		docker.EmptyParameters()
	}

	parameters := *docker.Parameters
	parameters = append(parameters, Parameters{
		Key:   key,
		Value: value})

	docker.Parameters = &parameters

	return docker
}

// EmptyParameters explicitly empties the parameters -- use this if you need to empty
// parameters of an application that already has parameters set (setting parameters to nil will
// keep the current value)
func (docker *Docker) EmptyParameters() *Docker {
	docker.Parameters = &[]Parameters{}
	return docker
}

// ServicePortIndex finds the service port index of the exposed port
//		port:			the port you are looking for
func (docker *Docker) ServicePortIndex(port int) (int, error) {
	if docker.PortMappings == nil || len(*docker.PortMappings) == 0 {
		return 0, errors.New("The docker does not contain any port mappings to search")
	}

	// step: iterate and find the port
	for index, containerPort := range *docker.PortMappings {
		if containerPort.ContainerPort == port {
			return index, nil
		}
	}

	// step: we didn't find the port in the mappings
	return 0, fmt.Errorf("The container port required was not found in the container port mappings")
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"time"
)

type StepShutdown struct{}

func (StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
	config := state.Get("commonconfig").(CommonConfig)
	ui := state.Get("ui").(packer.Ui)
	client := state.Get("client").(XenAPIClient)
	instance_uuid := state.Get("instance_uuid").(string)

	instance, err := client.GetVMByUuid(instance_uuid)
	if err != nil {
		ui.Error(fmt.Sprintf("Could not get VM with UUID '%s': %s", instance_uuid, err.Error()))
		return multistep.ActionHalt
	}

	ui.Say("Step: Shutdown and export")

	// Shutdown the VM
	success := func() bool {
		if config.ShutdownCommand != "" {
			ui.Message("Executing shutdown command...")

			_, err := ExecuteGuestSSHCmd(state, config.ShutdownCommand)
			if err != nil {
				ui.Error(fmt.Sprintf("Shutdown command failed: %s", err.Error()))
				return false
			}

			ui.Message("Waiting for VM to enter Halted state...")

			err = InterruptibleWait{
				Predicate: func() (bool, error) {
					power_state, err := instance.GetPowerState()
					return power_state == "Halted", err
				},
				PredicateInterval: 5 * time.Second,
				Timeout:           300 * time.Second,
			}.Wait(state)

			if err != nil {
				ui.Error(fmt.Sprintf("Error waiting for VM to halt: %s", err.Error()))
				return false
			}

		} else {
			ui.Message("Attempting to cleanly shutdown the VM...")

			err = instance.CleanShutdown()
			if err != nil {
				ui.Error(fmt.Sprintf("Could not shut down VM: %s", err.Error()))
				return false
			}

		}
		return true
	}()

	if !success {
		ui.Say("WARNING: Forcing hard shutdown of the VM...")
		err = instance.HardShutdown()
		if err != nil {
			ui.Error(fmt.Sprintf("Could not hard shut down VM -- giving up: %s", err.Error()))
			return multistep.ActionHalt
		}
	}

	ui.Message("Successfully shut down VM")
	return multistep.ActionContinue
}

func (StepShutdown) Cleanup(state multistep.StateBag) {}
<commit_msg>Fix Shutdown step message<commit_after>package common

import (
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"time"
)

type StepShutdown struct{}

func (StepShutdown) Run(state multistep.StateBag) multistep.StepAction {
	config := state.Get("commonconfig").(CommonConfig)
	ui := state.Get("ui").(packer.Ui)
	client := state.Get("client").(XenAPIClient)
	instance_uuid := state.Get("instance_uuid").(string)

	instance, err := client.GetVMByUuid(instance_uuid)
	if err != nil {
		ui.Error(fmt.Sprintf("Could not get VM with UUID '%s': %s", instance_uuid, err.Error()))
		return multistep.ActionHalt
	}

	ui.Say("Step: Shutting down VM")

	// Shutdown the VM
	success := func() bool {
		if config.ShutdownCommand != "" {
			ui.Message("Executing shutdown command...")

			_, err := ExecuteGuestSSHCmd(state, config.ShutdownCommand)
			if err != nil {
				ui.Error(fmt.Sprintf("Shutdown command failed: %s", err.Error()))
				return false
			}

			ui.Message("Waiting for VM to enter Halted state...")

			err = InterruptibleWait{
				Predicate: func() (bool, error) {
					power_state, err := instance.GetPowerState()
					return power_state == "Halted", err
				},
				PredicateInterval: 5 * time.Second,
				Timeout:           300 * time.Second,
			}.Wait(state)

			if err != nil {
				ui.Error(fmt.Sprintf("Error waiting for VM to halt: %s", err.Error()))
				return false
			}

		} else {
			ui.Message("Attempting to cleanly shutdown the VM...")

			err = instance.CleanShutdown()
			if err != nil {
				ui.Error(fmt.Sprintf("Could not shut down VM: %s", err.Error()))
				return false
			}

		}
		return true
	}()

	if !success {
		ui.Say("WARNING: Forcing hard shutdown of the VM...")
		err = instance.HardShutdown()
		if err != nil {
			ui.Error(fmt.Sprintf("Could not hard shut down VM -- giving up: %s", err.Error()))
			return multistep.ActionHalt
		}
	}

	ui.Message("Successfully shut down VM")
	return multistep.ActionContinue
}

func (StepShutdown) Cleanup(state multistep.StateBag) {}
<|endoftext|>


<commit_before>// Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.

package nvidia

import (
	"os/exec"

	"cuda"
	"nvml"
)

func Init() error {
	return nvml.Init()
}

func Shutdown() error {
	return nvml.Shutdown()
}

func LoadUVM() error {
	return exec.Command("nvidia-modprobe", "-u", "-c=0").Run()
}

func GetDriverVersion() (string, error) {
	return nvml.GetDriverVersion()
}

func GetCUDAVersion() (string, error) {
	return cuda.GetDriverVersion()
}
<commit_msg>Avoid loading UVM if already loaded<commit_after>// Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.

package nvidia

import (
	"os"
	"os/exec"

	"cuda"
	"nvml"
)

func Init() error {
	return nvml.Init()
}

func Shutdown() error {
	return nvml.Shutdown()
}

func LoadUVM() error {
	if _, err := os.Stat("/dev/nvidia-uvm"); err == nil {
		return nil
	}
	return exec.Command("nvidia-modprobe", "-u", "-c=0").Run()
}

func GetDriverVersion() (string, error) {
	return nvml.GetDriverVersion()
}

func GetCUDAVersion() (string, error) {
	return cuda.GetDriverVersion()
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pipelinerun

import (
	"context"
	"testing"

	tb "github.com/tektoncd/pipeline/internal/builder/v1beta1"
	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
	ttesting "github.com/tektoncd/pipeline/pkg/reconciler/testing"
	"github.com/tektoncd/pipeline/test"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/pkg/apis"
	logtesting "knative.dev/pkg/logging/testing"
)

func TestCancelPipelineRun(t *testing.T) {
	testCases := []struct {
		name        string
		pipelineRun *v1beta1.PipelineRun
		taskRuns    []*v1beta1.TaskRun
	}{{
		name: "no-resolved-taskrun",
		pipelineRun: &v1beta1.PipelineRun{
			ObjectMeta: metav1.ObjectMeta{Name: "test-pipeline-run-cancelled"},
			Spec: v1beta1.PipelineRunSpec{
				Status: v1beta1.PipelineRunSpecStatusCancelled,
			},
		},
	}, {
		name: "1-taskrun",
		pipelineRun: tb.PipelineRun("test-pipeline-run-cancelled", tb.PipelineRunNamespace("foo"),
			tb.PipelineRunSpec("test-pipeline",
				tb.PipelineRunCancelled,
			),
			tb.PipelineRunStatus(
				tb.PipelineRunTaskRunsStatus("t1", &v1beta1.PipelineRunTaskRunStatus{
					PipelineTaskName: "task-1",
				})),
		),
		taskRuns: []*v1beta1.TaskRun{tb.TaskRun("t1", tb.TaskRunNamespace("foo"))},
	}, {
		name: "multiple-taskruns",
		pipelineRun: tb.PipelineRun("test-pipeline-run-cancelled", tb.PipelineRunNamespace("foo"),
			tb.PipelineRunSpec("test-pipeline",
				tb.PipelineRunCancelled,
			),
			tb.PipelineRunStatus(
				tb.PipelineRunTaskRunsStatus(
					"t1", &v1beta1.PipelineRunTaskRunStatus{PipelineTaskName: "task-1"}),
				tb.PipelineRunTaskRunsStatus(
					"t2", &v1beta1.PipelineRunTaskRunStatus{PipelineTaskName: "task-2"})),
		),
		taskRuns: []*v1beta1.TaskRun{tb.TaskRun("t1", tb.TaskRunNamespace("foo")), tb.TaskRun("t2", tb.TaskRunNamespace("foo"))},
	}}
	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			d := test.Data{
				PipelineRuns: []*v1beta1.PipelineRun{tc.pipelineRun},
				TaskRuns:     tc.taskRuns,
			}
			ctx, _ := ttesting.SetupFakeContext(t)
			ctx, cancel := context.WithCancel(ctx)
			defer cancel()
			c, _ := test.SeedTestData(t, ctx, d)
			err := cancelPipelineRun(logtesting.TestLogger(t), tc.pipelineRun, c.Pipeline)
			if err != nil {
				t.Fatal(err)
			}
			// This PipelineRun should still be complete and false, and the status should reflect that
			cond := tc.pipelineRun.Status.GetCondition(apis.ConditionSucceeded)
			if cond.IsTrue() {
				t.Errorf("Expected PipelineRun status to be complete and false, but was %v", cond)
			}
			l, err := c.Pipeline.TektonV1beta1().TaskRuns("foo").List(metav1.ListOptions{})
			if err != nil {
				t.Fatal(err)
			}
			for _, tr := range l.Items {
				if tr.Spec.Status != v1beta1.TaskRunSpecStatusCancelled {
					t.Errorf("expected task %q to be marked as cancelled, was %q", tr.Name, tr.Spec.Status)
				}
			}
		})
	}
}
<commit_msg>Remove test builders from pipelinerun cancel_test.go<commit_after>/*
Copyright 2019 The Tekton Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pipelinerun

import (
	"context"
	"testing"

	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
	ttesting "github.com/tektoncd/pipeline/pkg/reconciler/testing"
	"github.com/tektoncd/pipeline/test"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/pkg/apis"
	logtesting "knative.dev/pkg/logging/testing"
)

func TestCancelPipelineRun(t *testing.T) {
	testCases := []struct {
		name        string
		pipelineRun *v1beta1.PipelineRun
		taskRuns    []*v1beta1.TaskRun
	}{{
		name: "no-resolved-taskrun",
		pipelineRun: &v1beta1.PipelineRun{
			ObjectMeta: metav1.ObjectMeta{Name: "test-pipeline-run-cancelled"},
			Spec: v1beta1.PipelineRunSpec{
				Status: v1beta1.PipelineRunSpecStatusCancelled,
			},
		},
	}, {
		name: "one-taskrun",
		pipelineRun: &v1beta1.PipelineRun{
			ObjectMeta: metav1.ObjectMeta{Name: "test-pipeline-run-cancelled"},
			Spec: v1beta1.PipelineRunSpec{
				Status: v1beta1.PipelineRunSpecStatusCancelled,
			},
			Status: v1beta1.PipelineRunStatus{PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{
				TaskRuns: map[string]*v1beta1.PipelineRunTaskRunStatus{
					"t1": {PipelineTaskName: "task-1"},
				},
			}},
		},
		taskRuns: []*v1beta1.TaskRun{
			{ObjectMeta: metav1.ObjectMeta{Name: "t1"}},
		},
	}, {
		name: "multiple-taskruns",
		pipelineRun: &v1beta1.PipelineRun{
			ObjectMeta: metav1.ObjectMeta{Name: "test-pipeline-run-cancelled"},
			Spec: v1beta1.PipelineRunSpec{
				Status: v1beta1.PipelineRunSpecStatusCancelled,
			},
			Status: v1beta1.PipelineRunStatus{PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{
				TaskRuns: map[string]*v1beta1.PipelineRunTaskRunStatus{
					"t1": {PipelineTaskName: "task-1"},
					"t2": {PipelineTaskName: "task-2"},
				},
			}},
		},
		taskRuns: []*v1beta1.TaskRun{
			{ObjectMeta: metav1.ObjectMeta{Name: "t1"}},
			{ObjectMeta: metav1.ObjectMeta{Name: "t2"}},
		},
	}}
	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			d := test.Data{
				PipelineRuns: []*v1beta1.PipelineRun{tc.pipelineRun},
				TaskRuns:     tc.taskRuns,
			}
			ctx, _ := ttesting.SetupFakeContext(t)
			ctx, cancel := context.WithCancel(ctx)
			defer cancel()
			c, _ := test.SeedTestData(t, ctx, d)
			if err := cancelPipelineRun(logtesting.TestLogger(t), tc.pipelineRun, c.Pipeline); err != nil {
				t.Fatal(err)
			}
			// This PipelineRun should still be complete and false, and the status should reflect that
			cond := tc.pipelineRun.Status.GetCondition(apis.ConditionSucceeded)
			if cond.IsTrue() {
				t.Errorf("Expected PipelineRun status to be complete and false, but was %v", cond)
			}
			l, err := c.Pipeline.TektonV1beta1().TaskRuns("").List(metav1.ListOptions{})
			if err != nil {
				t.Fatal(err)
			}
			for _, tr := range l.Items {
				if tr.Spec.Status != v1beta1.TaskRunSpecStatusCancelled {
					t.Errorf("expected task %q to be marked as cancelled, was %q", tr.Name, tr.Spec.Status)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package zone

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/pkg/errors"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/cluster/request"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/network"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
	"github.com/lxc/lxd/shared/validate"
	"github.com/lxc/lxd/shared/version"
)

// zone represents a Network zone.
type zone struct {
	logger      logger.Logger
	state       *state.State
	id          int64
	projectName string
	info        *api.NetworkZone
}

// init initialise internal variables.
func (d *zone) init(state *state.State, id int64, projectName string, info *api.NetworkZone) {
	if info == nil {
		d.info = &api.NetworkZone{}
	} else {
		d.info = info
	}

	d.logger = logging.AddContext(logger.Log, log.Ctx{"project": projectName, "networkzone": d.info.Name})
	d.id = id
	d.projectName = projectName
	d.state = state

	if d.info.Config == nil {
		d.info.Config = make(map[string]string)
	}
}

// ID returns the Network zone ID.
func (d *zone) ID() int64 {
	return d.id
}

// Name returns the project.
func (d *zone) Project() string {
	return d.projectName
}

// Info returns copy of internal info for the Network zone.
func (d *zone) Info() *api.NetworkZone {
	// Copy internal info to prevent modification externally.
	info := api.NetworkZone{}
	info.Name = d.info.Name
	info.Description = d.info.Description
	info.Config = util.CopyConfig(d.info.Config)
	info.UsedBy = nil // To indicate its not populated (use Usedby() function to populate).

	return &info
}

// usedBy returns a list of API endpoints referencing this zone.
// If firstOnly is true then search stops at first result.
func (d *zone) usedBy(firstOnly bool) ([]string, error) {
	usedBy := []string{}

	// Find networks using the zone.
	networkNames, err := d.state.Cluster.GetCreatedNetworks(d.projectName)
	if err != nil && err != db.ErrNoSuchObject {
		return nil, errors.Wrapf(err, "Failed loading networks for project %q", d.projectName)
	}

	for _, networkName := range networkNames {
		_, network, _, err := d.state.Cluster.GetNetworkInAnyState(d.projectName, networkName)
		if err != nil {
			return nil, errors.Wrapf(err, "Failed to get network config for %q", networkName)
		}

		uri := fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName)
		if shared.StringInSlice(uri, usedBy) {
			// Skip if the network is already listed in UsedBy.
			continue
		}

		// Check if the network is using this zone.
		if shared.StringInSlice(d.info.Name, []string{network.Config["dns.zone.forward"], network.Config["dns.zone.reverse.ipv4"], network.Config["dns.zone.reverse.ipv6"]}) {
			usedBy = append(usedBy, fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName))
			if firstOnly {
				return usedBy, nil
			}
		}
	}

	return usedBy, nil
}

// UsedBy returns a list of API endpoints referencing this zone.
func (d *zone) UsedBy() ([]string, error) {
	return d.usedBy(false)
}

// isUsed returns whether or not the zone is in use.
func (d *zone) isUsed() (bool, error) {
	usedBy, err := d.usedBy(true)
	if err != nil {
		return false, err
	}

	return len(usedBy) > 0, nil
}

// Etag returns the values used for etag generation.
func (d *zone) Etag() []interface{} {
	return []interface{}{d.info.Name, d.info.Description, d.info.Config}
}

// validateName checks name is valid.
func (d *zone) validateName(name string) error {
	if name == "" {
		return fmt.Errorf("Name is required")
	}

	return nil
}

// validateConfig checks the config and rules are valid.
func (d *zone) validateConfig(info *api.NetworkZonePut) error {
	rules := map[string]func(value string) error{}

	// Regular config keys.
	rules["dns.nameservers"] = validate.IsListOf(validate.IsAny)
	rules["network.nat"] = validate.Optional(validate.IsBool)

	// Validate peer config.
	for k := range info.Config {
		if !strings.HasPrefix(k, "peers.") {
			continue
		}

		// Validate remote name in key.
		fields := strings.Split(k, ".")
		if len(fields) != 3 {
			return fmt.Errorf("Invalid network zone configuration key %q", k)
		}

		peerKey := fields[2]

		// Add the correct validation rule for the dynamic field based on last part of key.
		switch peerKey {
		case "address":
			rules[k] = validate.Optional(validate.IsNetworkAddress)
		case "key":
			rules[k] = validate.Optional(validate.IsAny)
		}
	}

	err := d.validateConfigMap(info.Config, rules)
	if err != nil {
		return err
	}

	return nil
}

// validateConfigMap checks zone config map against rules.
func (d *zone) validateConfigMap(config map[string]string, rules map[string]func(value string) error) error {
	checkedFields := map[string]struct{}{}

	// Run the validator against each field.
	for k, validator := range rules {
		checkedFields[k] = struct{}{} //Mark field as checked.
		err := validator(config[k])
		if err != nil {
			return errors.Wrapf(err, "Invalid value for config option %q", k)
		}
	}

	// Look for any unchecked fields, as these are unknown fields and validation should fail.
	for k := range config {
		_, checked := checkedFields[k]
		if checked {
			continue
		}

		// User keys are not validated.
		if shared.IsUserConfig(k) {
			continue
		}

		return fmt.Errorf("Invalid config option %q", k)
	}

	return nil
}

// Update applies the supplied config to the zone.
func (d *zone) Update(config *api.NetworkZonePut, clientType request.ClientType) error {
	err := d.validateConfig(config)
	if err != nil {
		return err
	}

	revert := revert.New()
	defer revert.Fail()

	// Update the database and notify the rest of the cluster.
	if clientType == request.ClientTypeNormal {
		oldConfig := d.info.NetworkZonePut

		// Update database.
		err = d.state.Cluster.UpdateNetworkZone(d.id, config)
		if err != nil {
			return err
		}

		// Apply changes internally and reinitialise.
		d.info.NetworkZonePut = *config
		d.init(d.state, d.id, d.projectName, d.info)

		revert.Add(func() {
			d.state.Cluster.UpdateNetworkZone(d.id, &oldConfig)
			d.info.NetworkZonePut = oldConfig
			d.init(d.state, d.id, d.projectName, d.info)
		})

		// Notify all other nodes to update the network zone if no target specified.
		notifier, err := cluster.NewNotifier(d.state, d.state.Endpoints.NetworkCert(), d.state.ServerCert(), cluster.NotifyAll)
		if err != nil {
			return err
		}

		err = notifier(func(client lxd.InstanceServer) error {
			return client.UseProject(d.projectName).UpdateNetworkZone(d.info.Name, d.info.NetworkZonePut, "")
		})
		if err != nil {
			return err
		}
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	revert.Success()
	return nil
}

// Delete deletes the zone.
func (d *zone) Delete() error {
	isUsed, err := d.isUsed()
	if err != nil {
		return err
	}

	if isUsed {
		return fmt.Errorf("Cannot delete a zone that is in use")
	}

	// Delete the database record.
	err = d.state.Cluster.DeleteNetworkZone(d.id)
	if err != nil {
		return err
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	return nil
}

// Content returns the DNS zone content.
func (d *zone) Content() (*strings.Builder, error) {
	records := []map[string]string{}

	// Load all networks for the zone.
	networks, err := d.state.Cluster.GetNetworksForZone(d.projectName, d.info.Name)
	if err != nil {
		return nil, err
	}

	for _, netName := range networks {
		// Load the network.
		n, err := network.LoadByName(d.state, d.projectName, netName)
		if err != nil {
			return nil, err
		}

		// Load the leases.
		leases, err := n.Leases(d.projectName, request.ClientTypeNormal)
		if err != nil {
			return nil, err
		}

		// Check if dealing with a reverse zone.
		isReverse4 := strings.HasSuffix(d.info.Name, ip4Arpa)
		isReverse6 := strings.HasSuffix(d.info.Name, ip6Arpa)
		isReverse := isReverse4 || isReverse6
		forwardZone := n.Config()["dns.zone.forward"]

		genRecord := func(name string, addr string) map[string]string {
			isV4 := net.ParseIP(addr).To4() != nil

			record := map[string]string{}
			if !isReverse {
				if isV4 {
					record["type"] = "A"
				} else {
					record["type"] = "AAAA"
				}

				record["name"] = name
				record["value"] = addr
			} else {
				// Skip PTR records if no forward zone.
				if forwardZone == "" {
					return nil
				}

				// Skip PTR records for wrong family.
				if isV4 && !isReverse4 {
					return nil
				}

				if !isV4 && !isReverse6 {
					return nil
				}

				// Get the ARPA record.
				reverseAddr := reverse(addr)
				if reverseAddr == "" {
					return nil
				}

				record["type"] = "PTR"
				record["name"] = strings.TrimSuffix(reverseAddr, "."+d.info.Name+".")
				record["value"] = name + "." + forwardZone + "."
			}

			return record
		}

		// Convert leases to usable records.
		for _, lease := range leases {
			// Get the record.
			record := genRecord(lease.Hostname, lease.Address)
			if record == nil {
				continue
			}

			records = append(records, record)
		}

		// Add gateways.
		for _, addr := range []string{n.Config()["ipv4.address"], n.Config()["ipv6.address"]} {
			if addr == "" || addr == "none" {
				continue
			}

			// Strip the mask.
			addr = strings.Split(addr, "/")[0]

			// Get the record.
			record := genRecord(n.Name()+".gw", addr)
			if record == nil {
				continue
			}

			records = append(records, record)
		}
	}

	// Get the nameservers.
	nameservers := []string{}
	for _, entry := range strings.Split(d.info.Config["dns.nameservers"], ",") {
		entry = strings.TrimSpace(entry)
		if entry == "" {
			continue
		}

		nameservers = append(nameservers, entry)
	}

	primary := "hostmaster." + d.info.Name
	if len(nameservers) > 0 {
		primary = nameservers[0]
	}

	// Template the zone file.
	sb := &strings.Builder{}
	err = zoneTemplate.Execute(sb, map[string]interface{}{
		"primary":     primary,
		"nameservers": nameservers,
		"zone":        d.info.Name,
		"serial":      time.Now().Unix(),
		"records":     records,
	})
	if err != nil {
		return nil, err
	}

	return sb, nil
}
<commit_msg>lxd/network/zone: Support network.nat<commit_after>package zone

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/pkg/errors"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/cluster/request"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/network"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
	"github.com/lxc/lxd/shared/validate"
	"github.com/lxc/lxd/shared/version"
)

// zone represents a Network zone.
type zone struct {
	logger      logger.Logger
	state       *state.State
	id          int64
	projectName string
	info        *api.NetworkZone
}

// init initialise internal variables.
func (d *zone) init(state *state.State, id int64, projectName string, info *api.NetworkZone) {
	if info == nil {
		d.info = &api.NetworkZone{}
	} else {
		d.info = info
	}

	d.logger = logging.AddContext(logger.Log, log.Ctx{"project": projectName, "networkzone": d.info.Name})
	d.id = id
	d.projectName = projectName
	d.state = state

	if d.info.Config == nil {
		d.info.Config = make(map[string]string)
	}
}

// ID returns the Network zone ID.
func (d *zone) ID() int64 {
	return d.id
}

// Name returns the project.
func (d *zone) Project() string {
	return d.projectName
}

// Info returns copy of internal info for the Network zone.
func (d *zone) Info() *api.NetworkZone {
	// Copy internal info to prevent modification externally.
	info := api.NetworkZone{}
	info.Name = d.info.Name
	info.Description = d.info.Description
	info.Config = util.CopyConfig(d.info.Config)
	info.UsedBy = nil // To indicate its not populated (use Usedby() function to populate).

	return &info
}

// usedBy returns a list of API endpoints referencing this zone.
// If firstOnly is true then search stops at first result.
func (d *zone) usedBy(firstOnly bool) ([]string, error) {
	usedBy := []string{}

	// Find networks using the zone.
	networkNames, err := d.state.Cluster.GetCreatedNetworks(d.projectName)
	if err != nil && err != db.ErrNoSuchObject {
		return nil, errors.Wrapf(err, "Failed loading networks for project %q", d.projectName)
	}

	for _, networkName := range networkNames {
		_, network, _, err := d.state.Cluster.GetNetworkInAnyState(d.projectName, networkName)
		if err != nil {
			return nil, errors.Wrapf(err, "Failed to get network config for %q", networkName)
		}

		uri := fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName)
		if shared.StringInSlice(uri, usedBy) {
			// Skip if the network is already listed in UsedBy.
			continue
		}

		// Check if the network is using this zone.
		if shared.StringInSlice(d.info.Name, []string{network.Config["dns.zone.forward"], network.Config["dns.zone.reverse.ipv4"], network.Config["dns.zone.reverse.ipv6"]}) {
			usedBy = append(usedBy, fmt.Sprintf("/%s/networks/%s", version.APIVersion, networkName))
			if firstOnly {
				return usedBy, nil
			}
		}
	}

	return usedBy, nil
}

// UsedBy returns a list of API endpoints referencing this zone.
func (d *zone) UsedBy() ([]string, error) {
	return d.usedBy(false)
}

// isUsed returns whether or not the zone is in use.
func (d *zone) isUsed() (bool, error) {
	usedBy, err := d.usedBy(true)
	if err != nil {
		return false, err
	}

	return len(usedBy) > 0, nil
}

// Etag returns the values used for etag generation.
func (d *zone) Etag() []interface{} {
	return []interface{}{d.info.Name, d.info.Description, d.info.Config}
}

// validateName checks name is valid.
func (d *zone) validateName(name string) error {
	if name == "" {
		return fmt.Errorf("Name is required")
	}

	return nil
}

// validateConfig checks the config and rules are valid.
func (d *zone) validateConfig(info *api.NetworkZonePut) error {
	rules := map[string]func(value string) error{}

	// Regular config keys.
	rules["dns.nameservers"] = validate.IsListOf(validate.IsAny)
	rules["network.nat"] = validate.Optional(validate.IsBool)

	// Validate peer config.
	for k := range info.Config {
		if !strings.HasPrefix(k, "peers.") {
			continue
		}

		// Validate remote name in key.
		fields := strings.Split(k, ".")
		if len(fields) != 3 {
			return fmt.Errorf("Invalid network zone configuration key %q", k)
		}

		peerKey := fields[2]

		// Add the correct validation rule for the dynamic field based on last part of key.
		switch peerKey {
		case "address":
			rules[k] = validate.Optional(validate.IsNetworkAddress)
		case "key":
			rules[k] = validate.Optional(validate.IsAny)
		}
	}

	err := d.validateConfigMap(info.Config, rules)
	if err != nil {
		return err
	}

	return nil
}

// validateConfigMap checks zone config map against rules.
func (d *zone) validateConfigMap(config map[string]string, rules map[string]func(value string) error) error {
	checkedFields := map[string]struct{}{}

	// Run the validator against each field.
	for k, validator := range rules {
		checkedFields[k] = struct{}{} //Mark field as checked.
		err := validator(config[k])
		if err != nil {
			return errors.Wrapf(err, "Invalid value for config option %q", k)
		}
	}

	// Look for any unchecked fields, as these are unknown fields and validation should fail.
	for k := range config {
		_, checked := checkedFields[k]
		if checked {
			continue
		}

		// User keys are not validated.
		if shared.IsUserConfig(k) {
			continue
		}

		return fmt.Errorf("Invalid config option %q", k)
	}

	return nil
}

// Update applies the supplied config to the zone.
func (d *zone) Update(config *api.NetworkZonePut, clientType request.ClientType) error {
	err := d.validateConfig(config)
	if err != nil {
		return err
	}

	revert := revert.New()
	defer revert.Fail()

	// Update the database and notify the rest of the cluster.
	if clientType == request.ClientTypeNormal {
		oldConfig := d.info.NetworkZonePut

		// Update database.
		err = d.state.Cluster.UpdateNetworkZone(d.id, config)
		if err != nil {
			return err
		}

		// Apply changes internally and reinitialise.
		d.info.NetworkZonePut = *config
		d.init(d.state, d.id, d.projectName, d.info)

		revert.Add(func() {
			d.state.Cluster.UpdateNetworkZone(d.id, &oldConfig)
			d.info.NetworkZonePut = oldConfig
			d.init(d.state, d.id, d.projectName, d.info)
		})

		// Notify all other nodes to update the network zone if no target specified.
		notifier, err := cluster.NewNotifier(d.state, d.state.Endpoints.NetworkCert(), d.state.ServerCert(), cluster.NotifyAll)
		if err != nil {
			return err
		}

		err = notifier(func(client lxd.InstanceServer) error {
			return client.UseProject(d.projectName).UpdateNetworkZone(d.info.Name, d.info.NetworkZonePut, "")
		})
		if err != nil {
			return err
		}
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	revert.Success()
	return nil
}

// Delete deletes the zone.
func (d *zone) Delete() error {
	isUsed, err := d.isUsed()
	if err != nil {
		return err
	}

	if isUsed {
		return fmt.Errorf("Cannot delete a zone that is in use")
	}

	// Delete the database record.
	err = d.state.Cluster.DeleteNetworkZone(d.id)
	if err != nil {
		return err
	}

	// Trigger a refresh of the TSIG entries.
	err = d.state.DNS.UpdateTSIG()
	if err != nil {
		return err
	}

	return nil
}

// Content returns the DNS zone content.
func (d *zone) Content() (*strings.Builder, error) {
	records := []map[string]string{}

	// Check if we should include NAT records.
	val, ok := d.info.Config["network.nat"]
	includeNAT := !ok || shared.IsTrue(val)

	// Load all networks for the zone.
	networks, err := d.state.Cluster.GetNetworksForZone(d.projectName, d.info.Name)
	if err != nil {
		return nil, err
	}

	for _, netName := range networks {
		// Load the network.
		n, err := network.LoadByName(d.state, d.projectName, netName)
		if err != nil {
			return nil, err
		}

		// Load the leases.
		leases, err := n.Leases(d.projectName, request.ClientTypeNormal)
		if err != nil {
			return nil, err
		}

		// Check whether what records to include.
		val, _ = n.Config()["ipv4.nat"]
		includeV4 := includeNAT || !shared.IsTrue(val)

		val, _ = n.Config()["ipv6.nat"]
		includeV6 := includeNAT || !shared.IsTrue(val)

		// Check if dealing with a reverse zone.
		isReverse4 := strings.HasSuffix(d.info.Name, ip4Arpa)
		isReverse6 := strings.HasSuffix(d.info.Name, ip6Arpa)
		isReverse := isReverse4 || isReverse6
		forwardZone := n.Config()["dns.zone.forward"]

		genRecord := func(name string, addr string) map[string]string {
			isV4 := net.ParseIP(addr).To4() != nil

			// Skip disabled families.
			if isV4 && !includeV4 {
				return nil
			}

			if !isV4 && !includeV6 {
				return nil
			}

			record := map[string]string{}
			if !isReverse {
				if isV4 {
					record["type"] = "A"
				} else {
					record["type"] = "AAAA"
				}

				record["name"] = name
				record["value"] = addr
			} else {
				// Skip PTR records if no forward zone.
				if forwardZone == "" {
					return nil
				}

				// Skip PTR records for wrong family.
				if isV4 && !isReverse4 {
					return nil
				}

				if !isV4 && !isReverse6 {
					return nil
				}

				// Get the ARPA record.
				reverseAddr := reverse(addr)
				if reverseAddr == "" {
					return nil
				}

				record["type"] = "PTR"
				record["name"] = strings.TrimSuffix(reverseAddr, "."+d.info.Name+".")
				record["value"] = name + "." + forwardZone + "."
			}

			return record
		}

		// Convert leases to usable records.
		for _, lease := range leases {
			// Get the record.
			record := genRecord(lease.Hostname, lease.Address)
			if record == nil {
				continue
			}

			records = append(records, record)
		}

		// Add gateways.
		for _, addr := range []string{n.Config()["ipv4.address"], n.Config()["ipv6.address"]} {
			if addr == "" || addr == "none" {
				continue
			}

			// Strip the mask.
			addr = strings.Split(addr, "/")[0]

			// Get the record.
			record := genRecord(n.Name()+".gw", addr)
			if record == nil {
				continue
			}

			records = append(records, record)
		}
	}

	// Get the nameservers.
	nameservers := []string{}
	for _, entry := range strings.Split(d.info.Config["dns.nameservers"], ",") {
		entry = strings.TrimSpace(entry)
		if entry == "" {
			continue
		}

		nameservers = append(nameservers, entry)
	}

	primary := "hostmaster." + d.info.Name
	if len(nameservers) > 0 {
		primary = nameservers[0]
	}

	// Template the zone file.
	sb := &strings.Builder{}
	err = zoneTemplate.Execute(sb, map[string]interface{}{
		"primary":     primary,
		"nameservers": nameservers,
		"zone":        d.info.Name,
		"serial":      time.Now().Unix(),
		"records":     records,
	})
	if err != nil {
		return nil, err
	}

	return sb, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package dash

import (
	"bytes"
	"fmt"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/google/syzkaller/dashboard/dashapi"
	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
)

// This file contains web UI http handlers.

func init() {
	http.Handle("/", handlerWrapper(handleMain))
	http.Handle("/bug", handlerWrapper(handleBug))
	http.Handle("/text", handlerWrapper(handleText))
}

type uiMain struct {
	Header    *uiHeader
	Log       []byte
	BugGroups []*uiBugGroup
}

type uiBugPage struct {
	Header  *uiHeader
	Bug     *uiBug
	Crashes []*uiCrash
}

type uiBugGroup struct {
	Namespace string
	Bugs      []*uiBug
}

type uiBug struct {
	Namespace      string
	ID             string
	Title          string
	NumCrashes     int64
	FirstTime      time.Time
	LastTime       time.Time
	ReproLevel     dashapi.ReproLevel
	ReportingIndex int
	Status         string
	Link           string
	Commits        string
}

type uiCrash struct {
	Manager          string
	Time             time.Time
	Maintainers      string
	LogLink          string
	ReportLink       string
	ReproSyzLink     string
	ReproCLink       string
	SyzkallerCommit  string
	KernelRepo       string
	KernelBranch     string
	KernelCommit     string
	KernelConfigLink string
}

// handleMain serves main page.
func handleMain(c context.Context, w http.ResponseWriter, r *http.Request) error {
	h, err := commonHeader(c)
	if err != nil {
		return err
	}
	errorLog, err := fetchErrorLogs(c)
	if err != nil {
		return err
	}
	groups, err := fetchBugs(c)
	if err != nil {
		return err
	}
	data := &uiMain{
		Header:    h,
		Log:       errorLog,
		BugGroups: groups,
	}
	return templates.ExecuteTemplate(w, "main.html", data)
}

// handleBug serves page about a single bug (which is passed in id argument).
func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error {
	bug := new(Bug)
	bugKey := datastore.NewKey(c, "Bug", r.FormValue("id"), 0, nil)
	if err := datastore.Get(c, bugKey, bug); err != nil {
		return err
	}
	h, err := commonHeader(c)
	if err != nil {
		return err
	}
	state, err := loadReportingState(c)
	if err != nil {
		return err
	}
	uiBug := createUIBug(c, bug, state)
	crashes, err := loadCrashesForBug(c, bug)
	if err != nil {
		return err
	}
	data := &uiBugPage{
		Header:  h,
		Bug:     uiBug,
		Crashes: crashes,
	}
	return templates.ExecuteTemplate(w, "bug.html", data)
}

// handleText serves plain text blobs (crash logs, reports, reproducers, etc).
func handleText(c context.Context, w http.ResponseWriter, r *http.Request) error {
	id, err := strconv.ParseInt(r.FormValue("id"), 10, 64)
	if err != nil {
		return fmt.Errorf("failed to parse text id: %v", err)
	}
	data, err := getText(c, r.FormValue("tag"), id)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write(data)
	return nil
}

func fetchBugs(c context.Context) ([]*uiBugGroup, error) {
	var bugs []*Bug
	_, err := datastore.NewQuery("Bug").
		Filter("Status=", BugStatusOpen).
		GetAll(c, &bugs)
	if err != nil {
		return nil, err
	}
	state, err := loadReportingState(c)
	if err != nil {
		return nil, err
	}
	groups := make(map[string][]*uiBug)
	for _, bug := range bugs {
		uiBug := createUIBug(c, bug, state)
		groups[bug.Namespace] = append(groups[bug.Namespace], uiBug)
	}
	var res []*uiBugGroup
	for ns, bugs := range groups {
		sort.Sort(uiBugSorter(bugs))
		res = append(res, &uiBugGroup{
			Namespace: ns,
			Bugs:      bugs,
		})
	}
	sort.Sort(uiBugGroupSorter(res))
	return res, nil
}

func createUIBug(c context.Context, bug *Bug, state *ReportingState) *uiBug {
	_, _, reportingIdx, status, link, err := needReport(c, "", state, bug)
	if err != nil {
		status = err.Error()
	}
	if status == "" {
		status = "???"
	}
	uiBug := &uiBug{
		Namespace:      bug.Namespace,
		ID:             bugKeyHash(bug.Namespace, bug.Title, bug.Seq),
		Title:          bug.displayTitle(),
		NumCrashes:     bug.NumCrashes,
		FirstTime:      bug.FirstTime,
		LastTime:       bug.LastTime,
		ReproLevel:     bug.ReproLevel,
		ReportingIndex: reportingIdx,
		Status:         status,
		Link:           link,
		Commits:        fmt.Sprintf("%q", bug.Commits),
	}
	return uiBug
}

func loadCrashesForBug(c context.Context, bug *Bug) ([]*uiCrash, error) {
	bugHash := bugKeyHash(bug.Namespace, bug.Title, bug.Seq)
	bugKey := datastore.NewKey(c, "Bug", bugHash, 0, nil)
	crashes, err := queryCrashesForBug(c, bugKey, 100)
	if err != nil {
		return nil, err
	}
	builds := make(map[string]*Build)
	var results []*uiCrash
	for _, crash := range crashes {
		build := builds[crash.BuildID]
		if build == nil {
			build, err = loadBuild(c, bug.Namespace, crash.BuildID)
			if err != nil {
				return nil, err
			}
			builds[crash.BuildID] = build
		}
		ui := &uiCrash{
			Manager:          crash.Manager,
			Time:             crash.Time,
			Maintainers:      fmt.Sprintf("%q", crash.Maintainers),
			LogLink:          textLink("CrashLog", crash.Log),
			ReportLink:       textLink("CrashReport", crash.Report),
			ReproSyzLink:     textLink("ReproSyz", crash.ReproSyz),
			ReproCLink:       textLink("ReproC", crash.ReproC),
			SyzkallerCommit:  build.SyzkallerCommit,
			KernelRepo:       build.KernelRepo,
			KernelBranch:     build.KernelBranch,
			KernelCommit:     build.KernelCommit,
			KernelConfigLink: textLink("KernelConfig", build.KernelConfig),
		}
		results = append(results, ui)
	}
	return results, nil
}

func fetchErrorLogs(c context.Context) ([]byte, error) {
	const (
		minLogLevel  = 2
		maxLines     = 100
		reportPeriod = 7 * 24 * time.Hour
	)
	q := &log.Query{
		StartTime:     time.Now().Add(-reportPeriod),
		AppLogs:       true,
		ApplyMinLevel: true,
		MinLevel:      minLogLevel,
	}
	result := q.Run(c)
	var lines []string
	for i := 0; i < maxLines; i++ {
		rec, err := result.Next()
		if rec == nil {
			break
		}
		if err != nil {
			entry := fmt.Sprintf("ERROR FETCHING LOGS: %v\n", err)
			lines = append(lines, entry)
			break
		}
		for _, al := range rec.AppLogs {
			if al.Level < minLogLevel {
				continue
			}
			text := strings.Replace(al.Message, "\n", " ", -1)
			entry := fmt.Sprintf("%v: %v (%v)\n", formatTime(al.Time), text, rec.Resource)
			lines = append(lines, entry)
		}
	}
	buf := new(bytes.Buffer)
	for i := len(lines) - 1; i >= 0; i-- {
		buf.WriteString(lines[i])
	}
	return buf.Bytes(), nil
}

type uiBugSorter []*uiBug

func (a uiBugSorter) Len() int      { return len(a) }
func (a uiBugSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a uiBugSorter) Less(i, j int) bool {
	if a[i].ReportingIndex != a[j].ReportingIndex {
		return a[i].ReportingIndex > a[j].ReportingIndex
	}
	if (a[i].Link != "") != (a[j].Link != "") {
		return a[i].Link != ""
	}
	if a[i].ReproLevel != a[j].ReproLevel {
		return a[i].ReproLevel > a[j].ReproLevel
	}
	return a[i].FirstTime.After(a[j].FirstTime)
}

type uiBugGroupSorter []*uiBugGroup

func (a uiBugGroupSorter) Len() int           { return len(a) }
func (a uiBugGroupSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a uiBugGroupSorter) Less(i, j int) bool { return a[i].Namespace < a[j].Namespace }
<commit_msg>dashboard/app: don't print resource for log records<commit_after>// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package dash

import (
	"bytes"
	"fmt"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/google/syzkaller/dashboard/dashapi"
	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
)

// This file contains web UI http handlers.

func init() {
	http.Handle("/", handlerWrapper(handleMain))
	http.Handle("/bug", handlerWrapper(handleBug))
	http.Handle("/text", handlerWrapper(handleText))
}

type uiMain struct {
	Header    *uiHeader
	Log       []byte
	BugGroups []*uiBugGroup
}

type uiBugPage struct {
	Header  *uiHeader
	Bug     *uiBug
	Crashes []*uiCrash
}

type uiBugGroup struct {
	Namespace string
	Bugs      []*uiBug
}

type uiBug struct {
	Namespace      string
	ID             string
	Title          string
	NumCrashes     int64
	FirstTime      time.Time
	LastTime       time.Time
	ReproLevel     dashapi.ReproLevel
	ReportingIndex int
	Status         string
	Link           string
	Commits        string
}

type uiCrash struct {
	Manager          string
	Time             time.Time
	Maintainers      string
	LogLink          string
	ReportLink       string
	ReproSyzLink     string
	ReproCLink       string
	SyzkallerCommit  string
	KernelRepo       string
	KernelBranch     string
	KernelCommit     string
	KernelConfigLink string
}

// handleMain serves main page.
func handleMain(c context.Context, w http.ResponseWriter, r *http.Request) error {
	h, err := commonHeader(c)
	if err != nil {
		return err
	}
	errorLog, err := fetchErrorLogs(c)
	if err != nil {
		return err
	}
	groups, err := fetchBugs(c)
	if err != nil {
		return err
	}
	data := &uiMain{
		Header:    h,
		Log:       errorLog,
		BugGroups: groups,
	}
	return templates.ExecuteTemplate(w, "main.html", data)
}

// handleBug serves page about a single bug (which is passed in id argument).
func handleBug(c context.Context, w http.ResponseWriter, r *http.Request) error {
	bug := new(Bug)
	bugKey := datastore.NewKey(c, "Bug", r.FormValue("id"), 0, nil)
	if err := datastore.Get(c, bugKey, bug); err != nil {
		return err
	}
	h, err := commonHeader(c)
	if err != nil {
		return err
	}
	state, err := loadReportingState(c)
	if err != nil {
		return err
	}
	uiBug := createUIBug(c, bug, state)
	crashes, err := loadCrashesForBug(c, bug)
	if err != nil {
		return err
	}
	data := &uiBugPage{
		Header:  h,
		Bug:     uiBug,
		Crashes: crashes,
	}
	return templates.ExecuteTemplate(w, "bug.html", data)
}

// handleText serves plain text blobs (crash logs, reports, reproducers, etc).
func handleText(c context.Context, w http.ResponseWriter, r *http.Request) error {
	id, err := strconv.ParseInt(r.FormValue("id"), 10, 64)
	if err != nil {
		return fmt.Errorf("failed to parse text id: %v", err)
	}
	data, err := getText(c, r.FormValue("tag"), id)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Write(data)
	return nil
}

func fetchBugs(c context.Context) ([]*uiBugGroup, error) {
	var bugs []*Bug
	_, err := datastore.NewQuery("Bug").
		Filter("Status=", BugStatusOpen).
		GetAll(c, &bugs)
	if err != nil {
		return nil, err
	}
	state, err := loadReportingState(c)
	if err != nil {
		return nil, err
	}
	groups := make(map[string][]*uiBug)
	for _, bug := range bugs {
		uiBug := createUIBug(c, bug, state)
		groups[bug.Namespace] = append(groups[bug.Namespace], uiBug)
	}
	var res []*uiBugGroup
	for ns, bugs := range groups {
		sort.Sort(uiBugSorter(bugs))
		res = append(res, &uiBugGroup{
			Namespace: ns,
			Bugs:      bugs,
		})
	}
	sort.Sort(uiBugGroupSorter(res))
	return res, nil
}

func createUIBug(c context.Context, bug *Bug, state *ReportingState) *uiBug {
	_, _, reportingIdx, status, link, err := needReport(c, "", state, bug)
	if err != nil {
		status = err.Error()
	}
	if status == "" {
		status = "???"
	}
	uiBug := &uiBug{
		Namespace:      bug.Namespace,
		ID:             bugKeyHash(bug.Namespace, bug.Title, bug.Seq),
		Title:          bug.displayTitle(),
		NumCrashes:     bug.NumCrashes,
		FirstTime:      bug.FirstTime,
		LastTime:       bug.LastTime,
		ReproLevel:     bug.ReproLevel,
		ReportingIndex: reportingIdx,
		Status:         status,
		Link:           link,
		Commits:        fmt.Sprintf("%q", bug.Commits),
	}
	return uiBug
}

func loadCrashesForBug(c context.Context, bug *Bug) ([]*uiCrash, error) {
	bugHash := bugKeyHash(bug.Namespace, bug.Title, bug.Seq)
	bugKey := datastore.NewKey(c, "Bug", bugHash, 0, nil)
	crashes, err := queryCrashesForBug(c, bugKey, 100)
	if err != nil {
		return nil, err
	}
	builds := make(map[string]*Build)
	var results []*uiCrash
	for _, crash := range crashes {
		build := builds[crash.BuildID]
		if build == nil {
			build, err = loadBuild(c, bug.Namespace, crash.BuildID)
			if err != nil {
				return nil, err
			}
			builds[crash.BuildID] = build
		}
		ui := &uiCrash{
			Manager:          crash.Manager,
			Time:             crash.Time,
			Maintainers:      fmt.Sprintf("%q", crash.Maintainers),
			LogLink:          textLink("CrashLog", crash.Log),
			ReportLink:       textLink("CrashReport", crash.Report),
			ReproSyzLink:     textLink("ReproSyz", crash.ReproSyz),
			ReproCLink:       textLink("ReproC", crash.ReproC),
			SyzkallerCommit:  build.SyzkallerCommit,
			KernelRepo:       build.KernelRepo,
			KernelBranch:     build.KernelBranch,
			KernelCommit:     build.KernelCommit,
			KernelConfigLink: textLink("KernelConfig", build.KernelConfig),
		}
		results = append(results, ui)
	}
	return results, nil
}

func fetchErrorLogs(c context.Context) ([]byte, error) {
	const (
		minLogLevel  = 2
		maxLines     = 100
		reportPeriod = 7 * 24 * time.Hour
	)
	q := &log.Query{
		StartTime:     time.Now().Add(-reportPeriod),
		AppLogs:       true,
		ApplyMinLevel: true,
		MinLevel:      minLogLevel,
	}
	result := q.Run(c)
	var lines []string
	for i := 0; i < maxLines; i++ {
		rec, err := result.Next()
		if rec == nil {
			break
		}
		if err != nil {
			entry := fmt.Sprintf("ERROR FETCHING LOGS: %v\n", err)
			lines = append(lines, entry)
			break
		}
		for _, al := range rec.AppLogs {
			if al.Level < minLogLevel {
				continue
			}
			text := strings.Replace(al.Message, "\n", " ", -1)
			res := ""
			if !strings.Contains(rec.Resource, "method=log_error") {
				res = fmt.Sprintf(" (%v)", rec.Resource)
			}
			entry := fmt.Sprintf("%v: %v%v\n", formatTime(al.Time), text, res)
			lines = append(lines, entry)
		}
	}
	buf := new(bytes.Buffer)
	for i := len(lines) - 1; i >= 0; i-- {
		buf.WriteString(lines[i])
	}
	return buf.Bytes(), nil
}

type uiBugSorter []*uiBug

func (a uiBugSorter) Len() int      { return len(a) }
func (a uiBugSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a uiBugSorter) Less(i, j int) bool {
	if a[i].ReportingIndex != a[j].ReportingIndex {
		return a[i].ReportingIndex > a[j].ReportingIndex
	}
	if (a[i].Link != "") != (a[j].Link != "") {
		return a[i].Link != ""
	}
	if a[i].ReproLevel != a[j].ReproLevel {
		return a[i].ReproLevel > a[j].ReproLevel
	}
	return a[i].FirstTime.After(a[j].FirstTime)
}

type uiBugGroupSorter []*uiBugGroup

func (a uiBugGroupSorter) Len() int           { return len(a) }
func (a uiBugGroupSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a uiBugGroupSorter) Less(i, j int) bool { return a[i].Namespace < a[j].Namespace }
<|endoftext|>


<commit_before>package pkix

import (
	"testing"
)

func TestCreateCertificateHost(t *testing.T) {
	crtAuth, err := NewCertificateFromPEM([]byte(certAuthPEM))
	if err != nil {
		t.Fatal("Failed to parse certificate from PEM:", err)
	}

	key, err := NewKeyFromPrivateKeyPEM([]byte(rsaPrivKeyAuthPEM))
	if err != nil {
		t.Fatal("Failed parsing RSA private key:", err)
	}

	csr, err := NewCertificateSigningRequestFromPEM([]byte(csrPEM))
	if err != nil {
		t.Fatal("Failed parsing certificate request from PEM:", err)
	}

	crt, err := CreateCertificateHost(crtAuth, NewCertificateAuthorityInfo(authStartSerialNumber), key, csr, 1)
	if err != nil {
		t.Fatal("Failed creating certificate for host:", err)
	}

	rawCrt, err := crt.GetRawCertificate()
	if err != nil {
		t.Fatal("Failed to get x509.Certificate:", err)
	}

	rawCrtAuth, err := crtAuth.GetRawCertificate()
	if err != nil {
		t.Fatal("Failed to get x509.Certificate:", err)
	}
	if err = rawCrt.CheckSignatureFrom(rawCrtAuth); err != nil {
		t.Fatal("Failed to check signature:", err)
	}

	if err = rawCrt.VerifyHostname(csrIP); err != nil {
		t.Fatal("Failed to verify CommonName:", err)
	}

	if rawCrt.SerialNumber.Uint64() != authStartSerialNumber {
		t.Fatal("Expect serial number %v instead of %v", authStartSerialNumber, rawCrt.SerialNumber)
	}
}
<commit_msg>pkix: fix tests<commit_after>package pkix

import (
	"testing"
)

// TODO: we move to standard crypto/x509 now, so the cert file is changed.
// upgrade needed.
func TestCreateCertificateHost(t *testing.T) {
	crtAuth, err := NewCertificateFromPEM([]byte(certAuthPEM))
	if err != nil {
		t.Fatal("Failed to parse certificate from PEM:", err)
	}

	key, err := NewKeyFromPrivateKeyPEM([]byte(rsaPrivKeyAuthPEM))
	if err != nil {
		t.Fatal("Failed parsing RSA private key:", err)
	}

	csr, err := NewCertificateSigningRequestFromPEM([]byte(csrPEM))
	if err != nil {
		t.Fatal("Failed parsing certificate request from PEM:", err)
	}

	crt, err := CreateCertificateHost(crtAuth, NewCertificateAuthorityInfo(authStartSerialNumber), key, csr, 1)
	if err != nil {
		t.Fatal("Failed creating certificate for host:", err)
	}

	rawCrt, err := crt.GetRawCertificate()
	if err != nil {
		t.Fatal("Failed to get x509.Certificate:", err)
	}

	rawCrtAuth, err := crtAuth.GetRawCertificate()
	if err != nil {
		t.Fatal("Failed to get x509.Certificate:", err)
	}
	if err = rawCrt.CheckSignatureFrom(rawCrtAuth); err != nil {
		t.Fatal("Failed to check signature:", err)
	}

	if rawCrt.SerialNumber.Uint64() != authStartSerialNumber {
		t.Fatal("Expect serial number %v instead of %v", authStartSerialNumber, rawCrt.SerialNumber)
	}
}
<|endoftext|>


<commit_before>package py

/*
#include "Python.h"
*/
import "C"
import (
	"errors"
	"fmt"
	"pfi/sensorbee/sensorbee/data"
	"runtime"
	"unsafe"
)

// ObjectFunc is a bind of `PyObject` used as `PyFunc`
type ObjectFunc struct {
	Object
}

// invokeDirect calls name's function. User needs to call DecRef.
// This Returns a Object even if result values are more thane one.
// For example, use to get the object of the class instance that method returned.
func invokeDirect(pyObj *C.PyObject, name string, args []data.Value) (Object, error) {
	type Result struct {
		val Object
		err error
	}
	ch := make(chan *Result, 1)
	go func() {
		runtime.LockOSThread()
		state := GILState_Ensure()
		defer GILState_Release(state)

		var res Object
		pyFunc, err := getPyFunc(pyObj, name)
		if err != nil {
			ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
			return
		}
		defer pyFunc.decRef()

		pyArg := C.PyTuple_New(C.Py_ssize_t(len(args)))
		defer C.Py_DecRef(pyArg)

		for i, v := range args {
			o, err := newPyObj(v)
			if err != nil {
				ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
				return
			}
			// PyTuple object takes over the value's reference, and not need to
			// decrease reference counter.
			C.PyTuple_SetItem(pyArg, C.Py_ssize_t(i), o.p)
		}

		ret, err := pyFunc.callObject(Object{p: pyArg})
		if ret.p == nil && err != nil {
			ch <- &Result{res, fmt.Errorf("%v in '%v'", err.Error(), name)}
			return
		}

		ch <- &Result{ret, err}
	}()
	res := <-ch

	return res.val, res.err
}

// invoke name's function. TODO should be placed at internal package.
func invoke(pyObj *C.PyObject, name string, args []data.Value) (data.Value, error) {
	type Result struct {
		val data.Value
		err error
	}
	ch := make(chan *Result, 1)
	go func() {
		runtime.LockOSThread()
		state := GILState_Ensure()
		defer GILState_Release(state)

		var res data.Value
		pyFunc, err := getPyFunc(pyObj, name)
		if err != nil {
			ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
			return
		}
		defer pyFunc.decRef()

		pyArg := C.PyTuple_New(C.Py_ssize_t(len(args)))
		defer C.Py_DecRef(pyArg)

		for i, v := range args {
			o, err := newPyObj(v)
			if err != nil {
				ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
				return
			}
			// PyTuple object takes over the value's reference, and not need to
			// decrease reference counter.
			C.PyTuple_SetItem(pyArg, C.Py_ssize_t(i), o.p)
		}

		ret, err := pyFunc.callObject(Object{p: pyArg})
		if ret.p == nil && err != nil {
			ch <- &Result{res, fmt.Errorf("%v in '%v'", err.Error(), name)}
			return
		}
		defer ret.decRef()

		po, err := fromPyTypeObject(ret.p)
		ch <- &Result{po, err}
	}()
	res := <-ch

	return res.val, res.err
}

// TODO should be placed at internal package
func getPyFunc(pyObj *C.PyObject, name string) (ObjectFunc, error) {
	cFunc := C.CString(name)
	defer C.free(unsafe.Pointer(cFunc))

	pyFunc := C.PyObject_GetAttrString(pyObj, cFunc)
	if pyFunc == nil {
		return ObjectFunc{}, errors.New("cannot load function")
	}

	if ok := C.PyCallable_Check(pyFunc); ok == 0 {
		return ObjectFunc{}, errors.New("cannot call function")
	}

	return ObjectFunc{Object{p: pyFunc}}, nil
}

// callObject executes python function, using `PyObject_CallObject`. Returns a
// `PyObject` even if result values are more thane one. When a value will be set
// directory, and values will be set as a `PyTuple` object.
func (f *ObjectFunc) callObject(arg Object) (po Object, err error) {
	po = Object{}
	pyValue, err := C.PyObject_CallObject(f.p, arg.p)
	if pyValue == nil && err != nil {
		err = fmt.Errorf("call function error: %v", err)
	} else {
		po.p = pyValue
	}
	return po, err
}
<commit_msg>Fix typo in godoc of pystate/py<commit_after>package py

/*
#include "Python.h"
*/
import "C"
import (
	"errors"
	"fmt"
	"pfi/sensorbee/sensorbee/data"
	"runtime"
	"unsafe"
)

// ObjectFunc is a bind of `PyObject` used as `PyFunc`
type ObjectFunc struct {
	Object
}

// invokeDirect calls name's function. User needs to call DecRef.
// This returns an Object even if result values are more than one.
// For example, use to get the object of the class instance that method returned.
func invokeDirect(pyObj *C.PyObject, name string, args []data.Value) (Object, error) {
	type Result struct {
		val Object
		err error
	}
	ch := make(chan *Result, 1)
	go func() {
		runtime.LockOSThread()
		state := GILState_Ensure()
		defer GILState_Release(state)

		var res Object
		pyFunc, err := getPyFunc(pyObj, name)
		if err != nil {
			ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
			return
		}
		defer pyFunc.decRef()

		pyArg := C.PyTuple_New(C.Py_ssize_t(len(args)))
		defer C.Py_DecRef(pyArg)

		for i, v := range args {
			o, err := newPyObj(v)
			if err != nil {
				ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
				return
			}
			// PyTuple object takes over the value's reference, and not need to
			// decrease reference counter.
			C.PyTuple_SetItem(pyArg, C.Py_ssize_t(i), o.p)
		}

		ret, err := pyFunc.callObject(Object{p: pyArg})
		if ret.p == nil && err != nil {
			ch <- &Result{res, fmt.Errorf("%v in '%v'", err.Error(), name)}
			return
		}

		ch <- &Result{ret, err}
	}()
	res := <-ch

	return res.val, res.err
}

// invoke name's function. TODO should be placed at internal package.
func invoke(pyObj *C.PyObject, name string, args []data.Value) (data.Value, error) {
	type Result struct {
		val data.Value
		err error
	}
	ch := make(chan *Result, 1)
	go func() {
		runtime.LockOSThread()
		state := GILState_Ensure()
		defer GILState_Release(state)

		var res data.Value
		pyFunc, err := getPyFunc(pyObj, name)
		if err != nil {
			ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
			return
		}
		defer pyFunc.decRef()

		pyArg := C.PyTuple_New(C.Py_ssize_t(len(args)))
		defer C.Py_DecRef(pyArg)

		for i, v := range args {
			o, err := newPyObj(v)
			if err != nil {
				ch <- &Result{res, fmt.Errorf("%v at '%v'", err.Error(), name)}
				return
			}
			// PyTuple object takes over the value's reference, and not need to
			// decrease reference counter.
			C.PyTuple_SetItem(pyArg, C.Py_ssize_t(i), o.p)
		}

		ret, err := pyFunc.callObject(Object{p: pyArg})
		if ret.p == nil && err != nil {
			ch <- &Result{res, fmt.Errorf("%v in '%v'", err.Error(), name)}
			return
		}
		defer ret.decRef()

		po, err := fromPyTypeObject(ret.p)
		ch <- &Result{po, err}
	}()
	res := <-ch

	return res.val, res.err
}

// TODO should be placed at internal package
func getPyFunc(pyObj *C.PyObject, name string) (ObjectFunc, error) {
	cFunc := C.CString(name)
	defer C.free(unsafe.Pointer(cFunc))

	pyFunc := C.PyObject_GetAttrString(pyObj, cFunc)
	if pyFunc == nil {
		return ObjectFunc{}, errors.New("cannot load function")
	}

	if ok := C.PyCallable_Check(pyFunc); ok == 0 {
		return ObjectFunc{}, errors.New("cannot call function")
	}

	return ObjectFunc{Object{p: pyFunc}}, nil
}

// callObject executes python function, using `PyObject_CallObject`. Returns a
// `PyObject` even if result values are more than one. When a value will be set
// directory, and values will be set as a `PyTuple` object.
func (f *ObjectFunc) callObject(arg Object) (po Object, err error) {
	po = Object{}
	pyValue, err := C.PyObject_CallObject(f.p, arg.p)
	if pyValue == nil && err != nil {
		err = fmt.Errorf("call function error: %v", err)
	} else {
		po.p = pyValue
	}
	return po, err
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"

	"github.com/ninjasphere/go-openzwave"
	"github.com/ninjasphere/go-openzwave/NT"
)

const (
	driverName = "com.ninjablocks.zwave"
)

var (
	log  = logger.GetLogger(driverName)
	info = ninja.LoadModuleInfo("./package.json")
)

/*model.Module{
	ID:          "com.ninjablocks.zwave",
	Name:        "ZWave Driver",
	Version:     "0.2.0",
	Description: "Ninja Blocks ZWave driver",
	Author:      "Jon Seymour <jon@ninjablocks.com>",
	License:     "MIT",
}*/

type driver struct {
	config    *ZWaveDriverConfig
	conn      *ninja.Connection
	debug     bool
	zwaveAPI  openzwave.API
	exit      chan int
	sendEvent func(event string, payload interface{}) error
}

type ZWaveDriverConfig struct {
}

func defaultConfig() *ZWaveDriverConfig {
	return &ZWaveDriverConfig{}
}

func (driver *driver) GetOpenZWaveAPI() openzwave.API {
	return driver.zwaveAPI
}

func (driver *driver) GetNinjaDriver() ninja.Driver {
	return driver
}

func (driver *driver) GetNinjaConnection() *ninja.Connection {
	return driver.conn
}

func newZWaveDriver(debug bool) (*driver, error) {

	conn, err := ninja.Connect(driverName)

	if err != nil {
		log.Fatalf("Failed to create %s driver: %s", driverName, err)
	}

	driver := &driver{
		config:    defaultConfig(),
		conn:      conn,
		sendEvent: nil,
		debug:     debug,
		zwaveAPI:  nil,
		exit:      make(chan int, 0),
	}

	err = conn.ExportDriver(driver)

	if err != nil {
		log.Fatalf("Failed to export %s driver: %s", driverName, err)
	}

	return driver, nil
}

func (d *driver) Start(config *ZWaveDriverConfig) error {
	log.Infof("Driver %s starting with config %v", driverName, config)

	d.config = config

	zwaveDeviceFactory := func(api openzwave.API, node openzwave.Node) openzwave.Device {
		d.zwaveAPI = api
		return GetLibrary().GetDeviceFactory(*node.GetProductId())(d, node)
	}

	shuttingDown := false

	notificationCallback := func(api openzwave.API, nt openzwave.Notification) {
		switch nt.GetNotificationType().Code {
		case NT.NODE_REMOVED:
			//
			// Currently the RPC layer prevents us releasing the resources associated
			// with removed nodes. If the nodes come back (when, say, the zwave controller
			// is re-inserted), we can't build new device  wrappers for them because the
			// devices are already registered with the RPC layer.
			//
			// We could fix the RPC layer or we could attempt to work around the
			// problems with the RPC layer by using "patch" proxies for each ninja device
			// that allows us to change the actual zwave device.
			//
			// For now, it is simpler if we simply restart the driver process in the event of node
			// removal. This also avoids potential race conditions between
			// event dispatch and freeing of the resources associated with the
			// removed node.
			//
			if !shuttingDown {
				shuttingDown = true
				api.Logger().Infof("ZWave driver shutdown in response to node removed event.")
				api.Shutdown(openzwave.EXIT_NODE_REMOVED)
			}
		default:

		}
	}

	configurator := openzwave.
		BuildAPI("/usr/local/etc/openzwave", ".", "").
		SetLogger(log).
		SetNotificationCallback(notificationCallback).
		SetDeviceFactory(zwaveDeviceFactory)

	if d.debug {
		callback := func(api openzwave.API, notification openzwave.Notification) {
			api.Logger().Infof("%v\n", notification)
			notificationCallback(api, notification)
		}

		configurator.SetNotificationCallback(callback)
	}

	go func() {
		// slightly racy - we would like a guarantee we have replied to Start
		// before we start generating advice about new nodes.
		d.exit <- configurator.Run()
	}()

	d.sendEvent("config", config)

	return nil
}

func (d *driver) Stop() error {
	// TODO: propagate shutdown request to ZWave driver and let it take it down
	log.Infof("Stop received - shutting down")
	d.exit <- 0
	return nil
}

// wait until the drivers are ready for us to shutdown.
func (d *driver) Wait() int {
	return <-d.exit
}

func (d *driver) GetModuleInfo() *model.Module {
	return info
}

func (d *driver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<commit_msg>rename ZWaveDriverConfig -> config.<commit_after>package main

import (
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"

	"github.com/ninjasphere/go-openzwave"
	"github.com/ninjasphere/go-openzwave/NT"
)

const (
	driverName = "com.ninjablocks.zwave"
)

var (
	log  = logger.GetLogger(driverName)
	info = ninja.LoadModuleInfo("./package.json")
)

/*model.Module{
	ID:          "com.ninjablocks.zwave",
	Name:        "ZWave Driver",
	Version:     "0.2.0",
	Description: "Ninja Blocks ZWave driver",
	Author:      "Jon Seymour <jon@ninjablocks.com>",
	License:     "MIT",
}*/

type driver struct {
	config    *config
	conn      *ninja.Connection
	debug     bool
	zwaveAPI  openzwave.API
	exit      chan int
	sendEvent func(event string, payload interface{}) error
}

type config struct {
}

func defaultConfig() *config {
	return &config{}
}

func (driver *driver) GetOpenZWaveAPI() openzwave.API {
	return driver.zwaveAPI
}

func (driver *driver) GetNinjaDriver() ninja.Driver {
	return driver
}

func (driver *driver) GetNinjaConnection() *ninja.Connection {
	return driver.conn
}

func newZWaveDriver(debug bool) (*driver, error) {

	conn, err := ninja.Connect(driverName)

	if err != nil {
		log.Fatalf("Failed to create %s driver: %s", driverName, err)
	}

	driver := &driver{
		config:    defaultConfig(),
		conn:      conn,
		sendEvent: nil,
		debug:     debug,
		zwaveAPI:  nil,
		exit:      make(chan int, 0),
	}

	err = conn.ExportDriver(driver)

	if err != nil {
		log.Fatalf("Failed to export %s driver: %s", driverName, err)
	}

	return driver, nil
}

func (d *driver) Start(config *config) error {
	log.Infof("Driver %s starting with config %v", driverName, config)

	d.config = config

	zwaveDeviceFactory := func(api openzwave.API, node openzwave.Node) openzwave.Device {
		d.zwaveAPI = api
		return GetLibrary().GetDeviceFactory(*node.GetProductId())(d, node)
	}

	shuttingDown := false

	notificationCallback := func(api openzwave.API, nt openzwave.Notification) {
		switch nt.GetNotificationType().Code {
		case NT.NODE_REMOVED:
			//
			// Currently the RPC layer prevents us releasing the resources associated
			// with removed nodes. If the nodes come back (when, say, the zwave controller
			// is re-inserted), we can't build new device  wrappers for them because the
			// devices are already registered with the RPC layer.
			//
			// We could fix the RPC layer or we could attempt to work around the
			// problems with the RPC layer by using "patch" proxies for each ninja device
			// that allows us to change the actual zwave device.
			//
			// For now, it is simpler if we simply restart the driver process in the event of node
			// removal. This also avoids potential race conditions between
			// event dispatch and freeing of the resources associated with the
			// removed node.
			//
			if !shuttingDown {
				shuttingDown = true
				api.Logger().Infof("ZWave driver shutdown in response to node removed event.")
				api.Shutdown(openzwave.EXIT_NODE_REMOVED)
			}
		default:

		}
	}

	configurator := openzwave.
		BuildAPI("/usr/local/etc/openzwave", ".", "").
		SetLogger(log).
		SetNotificationCallback(notificationCallback).
		SetDeviceFactory(zwaveDeviceFactory)

	if d.debug {
		callback := func(api openzwave.API, notification openzwave.Notification) {
			api.Logger().Infof("%v\n", notification)
			notificationCallback(api, notification)
		}

		configurator.SetNotificationCallback(callback)
	}

	go func() {
		// slightly racy - we would like a guarantee we have replied to Start
		// before we start generating advice about new nodes.
		d.exit <- configurator.Run()
	}()

	d.sendEvent("config", config)

	return nil
}

func (d *driver) Stop() error {
	// TODO: propagate shutdown request to ZWave driver and let it take it down
	log.Infof("Stop received - shutting down")
	d.exit <- 0
	return nil
}

// wait until the drivers are ready for us to shutdown.
func (d *driver) Wait() int {
	return <-d.exit
}

func (d *driver) GetModuleInfo() *model.Module {
	return info
}

func (d *driver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<|endoftext|>