<commit_before>/*
Copyright 2016 The Fission 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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"text/tabwriter"

	"github.com/urfave/cli"

	"github.com/platform9/fission"
)

func fnCreate(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	envName := c.String("env")

	fileName := c.String("code")
	code, err := ioutil.ReadFile(fileName)
	checkErr(err, fmt.Sprintf("read %v", fileName))

	function := &fission.Function{
		Metadata:    fission.Metadata{Name: fnName},
		Environment: fission.Metadata{Name: envName},
		Code:        string(code),
	}

	_, err = client.FunctionCreate(function)
	checkErr(err, "create function")

	fmt.Printf("function '%v' created\n", fnName)
	return err
}

func fnGet(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	fnUid := c.String("uid")
	m := &fission.Metadata{Name: fnName, Uid: fnUid}

	code, err := client.FunctionGetRaw(m)
	checkErr(err, "get function")

	fmt.Println(string(code))
	return err
}

func fnGetMeta(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	fnUid := c.String("uid")
	m := &fission.Metadata{Name: fnName, Uid: fnUid}

	f, err := client.FunctionGet(m)
	checkErr(err, "get function")

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	fmt.Fprintf(w, "%v\t%v\t%v\n", "NAME", "UID", "ENV")
	fmt.Fprintf(w, "%v\t%v\t%v\n",
		f.Metadata.Name, f.Metadata.Uid, f.Environment.Name)
	w.Flush()
	return err
}

func fnUpdate(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")

	function, err := client.FunctionGet(&fission.Metadata{Name: fnName})
	checkErr(err, fmt.Sprintf("read function '%v'", fnName))

	envName := c.String("env")
	if len(envName) > 0 {
		function.Environment.Name = envName
	}

	fileName := c.String("code")
	if len(fileName) > 0 {
		code, err := ioutil.ReadFile(fileName)
		checkErr(err, fmt.Sprintf("read %v", fileName))

		function.Code = string(code)
	}

	_, err = client.FunctionCreate(function)
	checkErr(err, "update function")

	fmt.Printf("function '%v' created\n", fnName)
	return err
}

func fnDelete(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	fnUid := c.String("uid")
	m := &fission.Metadata{Name: fnName, Uid: fnUid}

	err := client.FunctionDelete(m)
	checkErr(err, fmt.Sprintf("delete function '%v'", fnName))

	fmt.Printf("function '%v' deleted\n", fnName)
	return err
}

func fnList(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fns, err := client.FunctionList()
	checkErr(err, "list functions")

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)

	fmt.Fprintf(w, "%v\t%v\t%v\n", "NAME", "UID", "ENV")
	for _, f := range fns {
		fmt.Fprintf(w, "%v\t%v\t%v\n",
			f.Metadata.Name, f.Metadata.Uid, f.Environment.Name)
	}
	w.Flush()

	return err
}
<commit_msg>Minor cli option validation bug<commit_after>/*
Copyright 2016 The Fission 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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"text/tabwriter"

	"github.com/urfave/cli"

	"github.com/platform9/fission"
)

func fnCreate(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	envName := c.String("env")

	fileName := c.String("code")
	code, err := ioutil.ReadFile(fileName)
	checkErr(err, fmt.Sprintf("read %v", fileName))

	function := &fission.Function{
		Metadata:    fission.Metadata{Name: fnName},
		Environment: fission.Metadata{Name: envName},
		Code:        string(code),
	}

	_, err = client.FunctionCreate(function)
	checkErr(err, "create function")

	fmt.Printf("function '%v' created\n", fnName)
	return err
}

func fnGet(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	if len(fnName) == 0 {
		fatal("Need name of function, use --name")
	}
	fnUid := c.String("uid")
	m := &fission.Metadata{Name: fnName, Uid: fnUid}

	code, err := client.FunctionGetRaw(m)
	checkErr(err, "get function")

	fmt.Println(string(code))
	return err
}

func fnGetMeta(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	fnUid := c.String("uid")
	m := &fission.Metadata{Name: fnName, Uid: fnUid}

	f, err := client.FunctionGet(m)
	checkErr(err, "get function")

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	fmt.Fprintf(w, "%v\t%v\t%v\n", "NAME", "UID", "ENV")
	fmt.Fprintf(w, "%v\t%v\t%v\n",
		f.Metadata.Name, f.Metadata.Uid, f.Environment.Name)
	w.Flush()
	return err
}

func fnUpdate(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")

	function, err := client.FunctionGet(&fission.Metadata{Name: fnName})
	checkErr(err, fmt.Sprintf("read function '%v'", fnName))

	envName := c.String("env")
	if len(envName) > 0 {
		function.Environment.Name = envName
	}

	fileName := c.String("code")
	if len(fileName) > 0 {
		code, err := ioutil.ReadFile(fileName)
		checkErr(err, fmt.Sprintf("read %v", fileName))

		function.Code = string(code)
	}

	_, err = client.FunctionCreate(function)
	checkErr(err, "update function")

	fmt.Printf("function '%v' created\n", fnName)
	return err
}

func fnDelete(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fnName := c.String("name")
	fnUid := c.String("uid")
	m := &fission.Metadata{Name: fnName, Uid: fnUid}

	err := client.FunctionDelete(m)
	checkErr(err, fmt.Sprintf("delete function '%v'", fnName))

	fmt.Printf("function '%v' deleted\n", fnName)
	return err
}

func fnList(c *cli.Context) error {
	client := getClient(c.GlobalString("server"))

	fns, err := client.FunctionList()
	checkErr(err, "list functions")

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)

	fmt.Fprintf(w, "%v\t%v\t%v\n", "NAME", "UID", "ENV")
	for _, f := range fns {
		fmt.Fprintf(w, "%v\t%v\t%v\n",
			f.Metadata.Name, f.Metadata.Uid, f.Environment.Name)
	}
	w.Flush()

	return err
}
<|endoftext|>


<commit_before>// Package layer is package for managing read-only
// and read-write mounts on the union file system
// driver. Read-only mounts are referenced using a
// content hash and are protected from mutation in
// the exposed interface. The tar format is used
// to create read-only layers and export both
// read-only and writable layers. The exported
// tar data for a read-only layer should match
// the tar used to create the layer.
package layer // import "github.com/docker/docker/layer"

import (
	"errors"
	"io"

	"github.com/docker/distribution"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/containerfs"
	digest "github.com/opencontainers/go-digest"
	"github.com/sirupsen/logrus"
)

var (
	// ErrLayerDoesNotExist is used when an operation is
	// attempted on a layer which does not exist.
	ErrLayerDoesNotExist = errors.New("layer does not exist")

	// ErrLayerNotRetained is used when a release is
	// attempted on a layer which is not retained.
	ErrLayerNotRetained = errors.New("layer not retained")

	// ErrMountDoesNotExist is used when an operation is
	// attempted on a mount layer which does not exist.
	ErrMountDoesNotExist = errors.New("mount does not exist")

	// ErrMountNameConflict is used when a mount is attempted
	// to be created but there is already a mount with the name
	// used for creation.
	ErrMountNameConflict = errors.New("mount already exists with name")

	// ErrActiveMount is used when an operation on a
	// mount is attempted but the layer is still
	// mounted and the operation cannot be performed.
	ErrActiveMount = errors.New("mount still active")

	// ErrNotMounted is used when requesting an active
	// mount but the layer is not mounted.
	ErrNotMounted = errors.New("not mounted")

	// ErrMaxDepthExceeded is used when a layer is attempted
	// to be created which would result in a layer depth
	// greater than the 125 max.
	ErrMaxDepthExceeded = errors.New("max depth exceeded")

	// ErrNotSupported is used when the action is not supported
	// on the current host operating system.
	ErrNotSupported = errors.New("not support on this host operating system")
)

// ChainID is the content-addressable ID of a layer.
type ChainID digest.Digest

// String returns a string rendition of a layer ID
func (id ChainID) String() string {
	return string(id)
}

// DiffID is the hash of an individual layer tar.
type DiffID digest.Digest

// String returns a string rendition of a layer DiffID
func (diffID DiffID) String() string {
	return string(diffID)
}

// TarStreamer represents an object which may
// have its contents exported as a tar stream.
type TarStreamer interface {
	// TarStream returns a tar archive stream
	// for the contents of a layer.
	TarStream() (io.ReadCloser, error)
}

// Layer represents a read-only layer
type Layer interface {
	TarStreamer

	// TarStreamFrom returns a tar archive stream for all the layer chain with
	// arbitrary depth.
	TarStreamFrom(ChainID) (io.ReadCloser, error)

	// ChainID returns the content hash of the entire layer chain. The hash
	// chain is made up of DiffID of top layer and all of its parents.
	ChainID() ChainID

	// DiffID returns the content hash of the layer
	// tar stream used to create this layer.
	DiffID() DiffID

	// Parent returns the next layer in the layer chain.
	Parent() Layer

	// Size returns the size of the entire layer chain. The size
	// is calculated from the total size of all files in the layers.
	Size() int64

	// DiffSize returns the size difference of the top layer
	// from parent layer.
	DiffSize() int64

	// Metadata returns the low level storage metadata associated
	// with layer.
	Metadata() (map[string]string, error)
}

// RWLayer represents a layer which is
// read and writable
type RWLayer interface {
	TarStreamer

	// Name of mounted layer
	Name() string

	// Parent returns the layer which the writable
	// layer was created from.
	Parent() Layer

	// Mount mounts the RWLayer and returns the filesystem path
	// to the writable layer.
	Mount(mountLabel string) (containerfs.ContainerFS, error)

	// Unmount unmounts the RWLayer. This should be called
	// for every mount. If there are multiple mount calls
	// this operation will only decrement the internal mount counter.
	Unmount() error

	// Size represents the size of the writable layer
	// as calculated by the total size of the files
	// changed in the mutable layer.
	Size() (int64, error)

	// Changes returns the set of changes for the mutable layer
	// from the base layer.
	Changes() ([]archive.Change, error)

	// Metadata returns the low level metadata for the mutable layer
	Metadata() (map[string]string, error)

	// ApplyDiff applies the diff to the RW layer
	ApplyDiff(diff io.Reader) (int64, error)
}

// Metadata holds information about a
// read-only layer
type Metadata struct {
	// ChainID is the content hash of the layer
	ChainID ChainID

	// DiffID is the hash of the tar data used to
	// create the layer
	DiffID DiffID

	// Size is the size of the layer and all parents
	Size int64

	// DiffSize is the size of the top layer
	DiffSize int64
}

// MountInit is a function to initialize a
// writable mount. Changes made here will
// not be included in the Tar stream of the
// RWLayer.
type MountInit func(root containerfs.ContainerFS) error

// CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer
type CreateRWLayerOpts struct {
	MountLabel string
	InitFunc   MountInit
	StorageOpt map[string]string
}

// Store represents a backend for managing both
// read-only and read-write layers.
type Store interface {
	Register(io.Reader, ChainID) (Layer, error)
	Get(ChainID) (Layer, error)
	Map() map[ChainID]Layer
	Release(Layer) ([]Metadata, error)

	CreateRWLayer(id string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error)
	GetRWLayer(id string) (RWLayer, error)
	GetMountID(id string) (string, error)
	ReleaseRWLayer(RWLayer) ([]Metadata, error)

	Cleanup() error
	DriverStatus() [][2]string
	DriverName() string
}

// DescribableStore represents a layer store capable of storing
// descriptors for layers.
type DescribableStore interface {
	RegisterWithDescriptor(io.Reader, ChainID, distribution.Descriptor) (Layer, error)
}

// CreateChainID returns ID for a layerDigest slice
func CreateChainID(dgsts []DiffID) ChainID {
	return createChainIDFromParent("", dgsts...)
}

func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
	if len(dgsts) == 0 {
		return parent
	}
	if parent == "" {
		return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
	}
	// H = "H(n-1) SHA256(n)"
	dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
	return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
}

// ReleaseAndLog releases the provided layer from the given layer
// store, logging any error and release metadata
func ReleaseAndLog(ls Store, l Layer) {
	metadata, err := ls.Release(l)
	if err != nil {
		logrus.Errorf("Error releasing layer %s: %v", l.ChainID(), err)
	}
	LogReleaseMetadata(metadata)
}

// LogReleaseMetadata logs a metadata array, uses this to
// ensure consistent logging for release metadata
func LogReleaseMetadata(metadatas []Metadata) {
	for _, metadata := range metadatas {
		logrus.Infof("Layer %s cleaned up", metadata.ChainID)
	}
}
<commit_msg>layer: remove unused ErrActiveMount, ErrNotMounted, ErrNotSupported<commit_after>// Package layer is package for managing read-only
// and read-write mounts on the union file system
// driver. Read-only mounts are referenced using a
// content hash and are protected from mutation in
// the exposed interface. The tar format is used
// to create read-only layers and export both
// read-only and writable layers. The exported
// tar data for a read-only layer should match
// the tar used to create the layer.
package layer // import "github.com/docker/docker/layer"

import (
	"errors"
	"io"

	"github.com/docker/distribution"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/containerfs"
	digest "github.com/opencontainers/go-digest"
	"github.com/sirupsen/logrus"
)

var (
	// ErrLayerDoesNotExist is used when an operation is
	// attempted on a layer which does not exist.
	ErrLayerDoesNotExist = errors.New("layer does not exist")

	// ErrLayerNotRetained is used when a release is
	// attempted on a layer which is not retained.
	ErrLayerNotRetained = errors.New("layer not retained")

	// ErrMountDoesNotExist is used when an operation is
	// attempted on a mount layer which does not exist.
	ErrMountDoesNotExist = errors.New("mount does not exist")

	// ErrMountNameConflict is used when a mount is attempted
	// to be created but there is already a mount with the name
	// used for creation.
	ErrMountNameConflict = errors.New("mount already exists with name")

	// ErrMaxDepthExceeded is used when a layer is attempted
	// to be created which would result in a layer depth
	// greater than the 125 max.
	ErrMaxDepthExceeded = errors.New("max depth exceeded")
)

// ChainID is the content-addressable ID of a layer.
type ChainID digest.Digest

// String returns a string rendition of a layer ID
func (id ChainID) String() string {
	return string(id)
}

// DiffID is the hash of an individual layer tar.
type DiffID digest.Digest

// String returns a string rendition of a layer DiffID
func (diffID DiffID) String() string {
	return string(diffID)
}

// TarStreamer represents an object which may
// have its contents exported as a tar stream.
type TarStreamer interface {
	// TarStream returns a tar archive stream
	// for the contents of a layer.
	TarStream() (io.ReadCloser, error)
}

// Layer represents a read-only layer
type Layer interface {
	TarStreamer

	// TarStreamFrom returns a tar archive stream for all the layer chain with
	// arbitrary depth.
	TarStreamFrom(ChainID) (io.ReadCloser, error)

	// ChainID returns the content hash of the entire layer chain. The hash
	// chain is made up of DiffID of top layer and all of its parents.
	ChainID() ChainID

	// DiffID returns the content hash of the layer
	// tar stream used to create this layer.
	DiffID() DiffID

	// Parent returns the next layer in the layer chain.
	Parent() Layer

	// Size returns the size of the entire layer chain. The size
	// is calculated from the total size of all files in the layers.
	Size() int64

	// DiffSize returns the size difference of the top layer
	// from parent layer.
	DiffSize() int64

	// Metadata returns the low level storage metadata associated
	// with layer.
	Metadata() (map[string]string, error)
}

// RWLayer represents a layer which is
// read and writable
type RWLayer interface {
	TarStreamer

	// Name of mounted layer
	Name() string

	// Parent returns the layer which the writable
	// layer was created from.
	Parent() Layer

	// Mount mounts the RWLayer and returns the filesystem path
	// to the writable layer.
	Mount(mountLabel string) (containerfs.ContainerFS, error)

	// Unmount unmounts the RWLayer. This should be called
	// for every mount. If there are multiple mount calls
	// this operation will only decrement the internal mount counter.
	Unmount() error

	// Size represents the size of the writable layer
	// as calculated by the total size of the files
	// changed in the mutable layer.
	Size() (int64, error)

	// Changes returns the set of changes for the mutable layer
	// from the base layer.
	Changes() ([]archive.Change, error)

	// Metadata returns the low level metadata for the mutable layer
	Metadata() (map[string]string, error)

	// ApplyDiff applies the diff to the RW layer
	ApplyDiff(diff io.Reader) (int64, error)
}

// Metadata holds information about a
// read-only layer
type Metadata struct {
	// ChainID is the content hash of the layer
	ChainID ChainID

	// DiffID is the hash of the tar data used to
	// create the layer
	DiffID DiffID

	// Size is the size of the layer and all parents
	Size int64

	// DiffSize is the size of the top layer
	DiffSize int64
}

// MountInit is a function to initialize a
// writable mount. Changes made here will
// not be included in the Tar stream of the
// RWLayer.
type MountInit func(root containerfs.ContainerFS) error

// CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer
type CreateRWLayerOpts struct {
	MountLabel string
	InitFunc   MountInit
	StorageOpt map[string]string
}

// Store represents a backend for managing both
// read-only and read-write layers.
type Store interface {
	Register(io.Reader, ChainID) (Layer, error)
	Get(ChainID) (Layer, error)
	Map() map[ChainID]Layer
	Release(Layer) ([]Metadata, error)

	CreateRWLayer(id string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error)
	GetRWLayer(id string) (RWLayer, error)
	GetMountID(id string) (string, error)
	ReleaseRWLayer(RWLayer) ([]Metadata, error)

	Cleanup() error
	DriverStatus() [][2]string
	DriverName() string
}

// DescribableStore represents a layer store capable of storing
// descriptors for layers.
type DescribableStore interface {
	RegisterWithDescriptor(io.Reader, ChainID, distribution.Descriptor) (Layer, error)
}

// CreateChainID returns ID for a layerDigest slice
func CreateChainID(dgsts []DiffID) ChainID {
	return createChainIDFromParent("", dgsts...)
}

func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
	if len(dgsts) == 0 {
		return parent
	}
	if parent == "" {
		return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
	}
	// H = "H(n-1) SHA256(n)"
	dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
	return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
}

// ReleaseAndLog releases the provided layer from the given layer
// store, logging any error and release metadata
func ReleaseAndLog(ls Store, l Layer) {
	metadata, err := ls.Release(l)
	if err != nil {
		logrus.Errorf("Error releasing layer %s: %v", l.ChainID(), err)
	}
	LogReleaseMetadata(metadata)
}

// LogReleaseMetadata logs a metadata array, uses this to
// ensure consistent logging for release metadata
func LogReleaseMetadata(metadatas []Metadata) {
	for _, metadata := range metadatas {
		logrus.Infof("Layer %s cleaned up", metadata.ChainID)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os/exec"
	"time"
)

// TODO allow to specify boot sequence

var (
	doQuiet  = flag.Bool("q", false, "Disable verbose output")
	interval = flag.Int("I", 1, "Interval in seconds before looping to the next boot command")
)

var bootsequence = [][]string{
	[]string{"netboot", "-userclass", "linuxboot"},
	[]string{"localboot"},
}

func main() {
	flag.Parse()

	log.Print("Starting boot sequence, press CTRL-C within 5 seconds to drop into a shell")
	time.Sleep(5 * time.Second)

	sleepInterval := time.Duration(*interval) * time.Second
	for {
		for _, bootcmd := range bootsequence {
			if !*doQuiet {
				bootcmd = append(bootcmd, "-d")
			}
			log.Printf("Running boot command: %v", bootcmd)
			cmd := exec.Command(bootcmd[0], bootcmd[1:]...)
			if err := cmd.Run(); err != nil {
				log.Printf("Error executing %s: %v", cmd, err)
			}
		}
		if !*doQuiet {
			log.Printf("Sleeping %v before attempting next boot command", sleepInterval)
		}
		time.Sleep(sleepInterval)
	}

}
<commit_msg>Fix tests on go1.10 (#10)<commit_after>package main

import (
	"flag"
	"log"
	"os/exec"
	"time"
)

// TODO allow to specify boot sequence

var (
	doQuiet  = flag.Bool("q", false, "Disable verbose output")
	interval = flag.Int("I", 1, "Interval in seconds before looping to the next boot command")
)

var bootsequence = [][]string{
	[]string{"netboot", "-userclass", "linuxboot"},
	[]string{"localboot"},
}

func main() {
	flag.Parse()

	log.Print("Starting boot sequence, press CTRL-C within 5 seconds to drop into a shell")
	time.Sleep(5 * time.Second)

	sleepInterval := time.Duration(*interval) * time.Second
	for {
		for _, bootcmd := range bootsequence {
			if !*doQuiet {
				bootcmd = append(bootcmd, "-d")
			}
			log.Printf("Running boot command: %v", bootcmd)
			cmd := exec.Command(bootcmd[0], bootcmd[1:]...)
			if err := cmd.Run(); err != nil {
				log.Printf("Error executing %v: %v", cmd, err)
			}
		}
		if !*doQuiet {
			log.Printf("Sleeping %v before attempting next boot command", sleepInterval)
		}
		time.Sleep(sleepInterval)
	}

}
<|endoftext|>


<commit_before>package vmware

import (
	"bytes"
	"fmt"
	"github.com/mitchellh/go-vnc"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"log"
	"net"
	"strings"
	"text/template"
	"time"
	"unicode"
	"unicode/utf8"
)

const KeyLeftShift uint32 = 0xFFE1

type bootCommandTemplateData struct {
	HTTPIP   string
	HTTPPort uint
	Name     string
}

// This step "types" the boot command into the VM over VNC.
//
// Uses:
//   config *config
//   http_port int
//   ui     packer.Ui
//   vnc_port uint
//
// Produces:
//   <nothing>
type stepTypeBootCommand struct{}

func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
	config := state["config"].(*config)
	httpPort := state["http_port"].(uint)
	ui := state["ui"].(packer.Ui)
	vncPort := state["vnc_port"].(uint)

	// Connect to VNC
	ui.Say("Connecting to VM via VNC")
	nc, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", vncPort))
	if err != nil {
		err := fmt.Errorf("Error connecting to VNC: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer nc.Close()

	c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: true})
	if err != nil {
		err := fmt.Errorf("Error handshaking with VNC: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer c.Close()

	log.Printf("Connected to VNC desktop: %s", c.DesktopName)

	// Determine the host IP
	ipFinder := &IfconfigIPFinder{"vmnet8"}
	hostIp, err := ipFinder.HostIP()
	if err != nil {
		err := fmt.Errorf("Error detecting host IP: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	tplData := &bootCommandTemplateData{
		hostIp,
		httpPort,
		config.VMName,
	}

	ui.Say("Typing the boot command over VNC...")
	for _, command := range config.BootCommand {
		var buf bytes.Buffer
		t := template.Must(template.New("boot").Parse(command))
		t.Execute(&buf, tplData)

		vncSendString(c, buf.String())
	}

	return multistep.ActionContinue
}

func (*stepTypeBootCommand) Cleanup(map[string]interface{}) {}

func vncSendString(c *vnc.ClientConn, original string) {
	special := make(map[string]uint32)
	special["<bs>"] = 0xFF08
	special["<del>"] = 0xFFFF
	special["<enter>"] = 0xFF0D
	special["<esc>"] = 0xFF1B
	special["<f1>"] = 0xFFBE
	special["<f2>"] = 0xFFBF
	special["<f3>"] = 0xFFC0
	special["<f4>"] = 0xFFC1
	special["<f5>"] = 0xFFC2
	special["<f6>"] = 0xFFC3
	special["<f7>"] = 0xFFC4
	special["<f8>"] = 0xFFC5
	special["<f9>"] = 0xFFC6
	special["<f10>"] = 0xFFC7
	special["<f11>"] = 0xFFC8
	special["<f12>"] = 0xFFC9
	special["<return>"] = 0xFF0D
	special["<tab>"] = 0xFF09

	shiftedChars := "~!@#$%^&*()_+{}|:\"<>?"

	// TODO(mitchellh): Ripe for optimizations of some point, perhaps.
	for len(original) > 0 {
		var keyCode uint32
		keyShift := false

		if strings.HasPrefix(original, "<wait>") {
			log.Printf("Special code '<wait>' found, sleeping one second")
			time.Sleep(1 * time.Second)
			original = original[len("<wait>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait5>") {
			log.Printf("Special code '<wait5>' found, sleeping 5 seconds")
			time.Sleep(5 * time.Second)
			original = original[len("<wait5>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait10>") {
			log.Printf("Special code '<wait10>' found, sleeping 10 seconds")
			time.Sleep(10 * time.Second)
			original = original[len("<wait10>"):]
			continue
		}

		for specialCode, specialValue := range special {
			if strings.HasPrefix(original, specialCode) {
				log.Printf("Special code '%s' found, replacing with: %d", specialCode, specialValue)
				keyCode = specialValue
				original = original[len(specialCode):]
				break
			}
		}

		if keyCode == 0 {
			r, size := utf8.DecodeRuneInString(original)
			original = original[size:]
			keyCode = uint32(r)
			keyShift = unicode.IsUpper(r) || strings.ContainsRune(shiftedChars, r)

			log.Printf("Sending char '%c', code %d, shift %v", r, keyCode, keyShift)
		}

		if keyShift {
			c.KeyEvent(KeyLeftShift, true)
		}

		c.KeyEvent(keyCode, true)
		c.KeyEvent(keyCode, false)

		if keyShift {
			c.KeyEvent(KeyLeftShift, false)
		}
	}
}
<commit_msg>builder/vmware: more logs for Workstation<commit_after>package vmware

import (
	"bytes"
	"fmt"
	"github.com/mitchellh/go-vnc"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"log"
	"net"
	"strings"
	"text/template"
	"time"
	"unicode"
	"unicode/utf8"
)

const KeyLeftShift uint32 = 0xFFE1

type bootCommandTemplateData struct {
	HTTPIP   string
	HTTPPort uint
	Name     string
}

// This step "types" the boot command into the VM over VNC.
//
// Uses:
//   config *config
//   http_port int
//   ui     packer.Ui
//   vnc_port uint
//
// Produces:
//   <nothing>
type stepTypeBootCommand struct{}

func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
	config := state["config"].(*config)
	httpPort := state["http_port"].(uint)
	ui := state["ui"].(packer.Ui)
	vncPort := state["vnc_port"].(uint)

	// Connect to VNC
	ui.Say("Connecting to VM via VNC")
	nc, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", vncPort))
	if err != nil {
		err := fmt.Errorf("Error connecting to VNC: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer nc.Close()

	c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: true})
	if err != nil {
		err := fmt.Errorf("Error handshaking with VNC: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}
	defer c.Close()

	log.Printf("Connected to VNC desktop: %s", c.DesktopName)

	// Determine the host IP
	ipFinder := &IfconfigIPFinder{"vmnet8"}
	hostIp, err := ipFinder.HostIP()
	if err != nil {
		err := fmt.Errorf("Error detecting host IP: %s", err)
		state["error"] = err
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	log.Printf("Host IP for the VMware machine: %s", hostIp)

	tplData := &bootCommandTemplateData{
		hostIp,
		httpPort,
		config.VMName,
	}

	ui.Say("Typing the boot command over VNC...")
	for _, command := range config.BootCommand {
		var buf bytes.Buffer
		t := template.Must(template.New("boot").Parse(command))
		t.Execute(&buf, tplData)

		vncSendString(c, buf.String())
	}

	return multistep.ActionContinue
}

func (*stepTypeBootCommand) Cleanup(map[string]interface{}) {}

func vncSendString(c *vnc.ClientConn, original string) {
	special := make(map[string]uint32)
	special["<bs>"] = 0xFF08
	special["<del>"] = 0xFFFF
	special["<enter>"] = 0xFF0D
	special["<esc>"] = 0xFF1B
	special["<f1>"] = 0xFFBE
	special["<f2>"] = 0xFFBF
	special["<f3>"] = 0xFFC0
	special["<f4>"] = 0xFFC1
	special["<f5>"] = 0xFFC2
	special["<f6>"] = 0xFFC3
	special["<f7>"] = 0xFFC4
	special["<f8>"] = 0xFFC5
	special["<f9>"] = 0xFFC6
	special["<f10>"] = 0xFFC7
	special["<f11>"] = 0xFFC8
	special["<f12>"] = 0xFFC9
	special["<return>"] = 0xFF0D
	special["<tab>"] = 0xFF09

	shiftedChars := "~!@#$%^&*()_+{}|:\"<>?"

	// TODO(mitchellh): Ripe for optimizations of some point, perhaps.
	for len(original) > 0 {
		var keyCode uint32
		keyShift := false

		if strings.HasPrefix(original, "<wait>") {
			log.Printf("Special code '<wait>' found, sleeping one second")
			time.Sleep(1 * time.Second)
			original = original[len("<wait>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait5>") {
			log.Printf("Special code '<wait5>' found, sleeping 5 seconds")
			time.Sleep(5 * time.Second)
			original = original[len("<wait5>"):]
			continue
		}

		if strings.HasPrefix(original, "<wait10>") {
			log.Printf("Special code '<wait10>' found, sleeping 10 seconds")
			time.Sleep(10 * time.Second)
			original = original[len("<wait10>"):]
			continue
		}

		for specialCode, specialValue := range special {
			if strings.HasPrefix(original, specialCode) {
				log.Printf("Special code '%s' found, replacing with: %d", specialCode, specialValue)
				keyCode = specialValue
				original = original[len(specialCode):]
				break
			}
		}

		if keyCode == 0 {
			r, size := utf8.DecodeRuneInString(original)
			original = original[size:]
			keyCode = uint32(r)
			keyShift = unicode.IsUpper(r) || strings.ContainsRune(shiftedChars, r)

			log.Printf("Sending char '%c', code %d, shift %v", r, keyCode, keyShift)
		}

		if keyShift {
			c.KeyEvent(KeyLeftShift, true)
		}

		c.KeyEvent(keyCode, true)
		c.KeyEvent(keyCode, false)

		if keyShift {
			c.KeyEvent(KeyLeftShift, false)
		}
	}
}
<|endoftext|>


<commit_before>package pki

import (
	"context"
	"encoding/base64"
	"fmt"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/vault/sdk/framework"
	"github.com/hashicorp/vault/sdk/helper/certutil"
	"github.com/hashicorp/vault/sdk/helper/errutil"
	"github.com/hashicorp/vault/sdk/logical"
)

func pathGenerateIntermediate(b *backend) *framework.Path {
	ret := &framework.Path{
		Pattern: "intermediate/generate/" + framework.GenericNameRegex("exported"),

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathGenerateIntermediate,
		},

		HelpSynopsis:    pathGenerateIntermediateHelpSyn,
		HelpDescription: pathGenerateIntermediateHelpDesc,
	}

	ret.Fields = addCACommonFields(map[string]*framework.FieldSchema{})
	ret.Fields = addCAKeyGenerationFields(ret.Fields)
	ret.Fields["add_basic_constraints"] = &framework.FieldSchema{
		Type: framework.TypeBool,
		Description: `Whether to add a Basic Constraints
extension with CA: true. Only needed as a
workaround in some compatibility scenarios
with Active Directory Certificate Services.`,
	}

	return ret
}

func pathSetSignedIntermediate(b *backend) *framework.Path {
	ret := &framework.Path{
		Pattern: "intermediate/set-signed",

		Fields: map[string]*framework.FieldSchema{
			"certificate": &framework.FieldSchema{
				Type: framework.TypeString,
				Description: `PEM-format certificate. This must be a CA
certificate with a public key matching the
previously-generated key from the generation
endpoint.`,
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathSetSignedIntermediate,
		},

		HelpSynopsis:    pathSetSignedIntermediateHelpSyn,
		HelpDescription: pathSetSignedIntermediateHelpDesc,
	}

	return ret
}

func (b *backend) pathGenerateIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	var err error

	exported, format, role, errorResp := b.getGenerationParams(data)
	if errorResp != nil {
		return errorResp, nil
	}

	var resp *logical.Response
	input := &inputBundle{
		role:    role,
		req:     req,
		apiData: data,
	}
	parsedBundle, err := generateIntermediateCSR(b, input)
	if err != nil {
		switch err.(type) {
		case errutil.UserError:
			return logical.ErrorResponse(err.Error()), nil
		case errutil.InternalError:
			return nil, err
		}
	}

	csrb, err := parsedBundle.ToCSRBundle()
	if err != nil {
		return nil, errwrap.Wrapf("error converting raw CSR bundle to CSR bundle: {{err}}", err)
	}

	resp = &logical.Response{
		Data: map[string]interface{}{},
	}

	switch format {
	case "pem":
		resp.Data["csr"] = csrb.CSR
		if exported {
			resp.Data["private_key"] = csrb.PrivateKey
			resp.Data["private_key_type"] = csrb.PrivateKeyType
		}

	case "pem_bundle":
		resp.Data["csr"] = csrb.CSR
		if exported {
			resp.Data["csr"] = fmt.Sprintf("%s\n%s", csrb.PrivateKey, csrb.CSR)
			resp.Data["private_key"] = csrb.PrivateKey
			resp.Data["private_key_type"] = csrb.PrivateKeyType
		}

	case "der":
		resp.Data["csr"] = base64.StdEncoding.EncodeToString(parsedBundle.CSRBytes)
		if exported {
			resp.Data["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes)
			resp.Data["private_key_type"] = csrb.PrivateKeyType
		}
	}

	if data.Get("private_key_format").(string) == "pkcs8" {
		err = convertRespToPKCS8(resp)
		if err != nil {
			return nil, err
		}
	}

	cb := &certutil.CertBundle{}
	cb.PrivateKey = csrb.PrivateKey
	cb.PrivateKeyType = csrb.PrivateKeyType

	entry, err := logical.StorageEntryJSON("config/ca_bundle", cb)
	if err != nil {
		return nil, err
	}
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

func (b *backend) pathSetSignedIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	cert := data.Get("certificate").(string)

	if cert == "" {
		return logical.ErrorResponse("no certificate provided in the \"certificate\" parameter"), nil
	}

	inputBundle, err := certutil.ParsePEMBundle(cert)
	if err != nil {
		switch err.(type) {
		case errutil.InternalError:
			return nil, err
		default:
			return logical.ErrorResponse(err.Error()), nil
		}
	}

	if inputBundle.Certificate == nil {
		return logical.ErrorResponse("supplied certificate could not be successfully parsed"), nil
	}

	cb := &certutil.CertBundle{}
	entry, err := req.Storage.Get(ctx, "config/ca_bundle")
	if err != nil {
		return nil, err
	}
	if entry == nil {
		return logical.ErrorResponse("could not find any existing entry with a private key"), nil
	}

	err = entry.DecodeJSON(cb)
	if err != nil {
		return nil, err
	}

	if len(cb.PrivateKey) == 0 || cb.PrivateKeyType == "" {
		return logical.ErrorResponse("could not find an existing private key"), nil
	}

	parsedCB, err := cb.ToParsedCertBundle()
	if err != nil {
		return nil, err
	}
	if parsedCB.PrivateKey == nil {
		return nil, fmt.Errorf("saved key could not be parsed successfully")
	}

	inputBundle.PrivateKey = parsedCB.PrivateKey
	inputBundle.PrivateKeyType = parsedCB.PrivateKeyType
	inputBundle.PrivateKeyBytes = parsedCB.PrivateKeyBytes

	if !inputBundle.Certificate.IsCA {
		return logical.ErrorResponse("the given certificate is not marked for CA use and cannot be used with this backend"), nil
	}

	if err := inputBundle.Verify(); err != nil {
		return nil, errwrap.Wrapf("verification of parsed bundle failed: {{err}}", err)
	}

	cb, err = inputBundle.ToCertBundle()
	if err != nil {
		return nil, errwrap.Wrapf("error converting raw values into cert bundle: {{err}}", err)
	}

	entry, err = logical.StorageEntryJSON("config/ca_bundle", cb)
	if err != nil {
		return nil, err
	}
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	entry.Key = "certs/" + normalizeSerial(cb.SerialNumber)
	entry.Value = inputBundle.CertificateBytes
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	// For ease of later use, also store just the certificate at a known
	// location
	entry.Key = "ca"
	entry.Value = inputBundle.CertificateBytes
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	// Build a fresh CRL
	err = buildCRL(ctx, b, req, true)

	return nil, err
}

const pathGenerateIntermediateHelpSyn = `
Generate a new CSR and private key used for signing.
`

const pathGenerateIntermediateHelpDesc = `
See the API documentation for more information.
`

const pathSetSignedIntermediateHelpSyn = `
Provide the signed intermediate CA cert.
`

const pathSetSignedIntermediateHelpDesc = `
See the API documentation for more information.
`
<commit_msg>fix minor potential nil-pointer panic on line 89 (#8488)<commit_after>package pki

import (
	"context"
	"encoding/base64"
	"fmt"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/vault/sdk/framework"
	"github.com/hashicorp/vault/sdk/helper/certutil"
	"github.com/hashicorp/vault/sdk/helper/errutil"
	"github.com/hashicorp/vault/sdk/logical"
)

func pathGenerateIntermediate(b *backend) *framework.Path {
	ret := &framework.Path{
		Pattern: "intermediate/generate/" + framework.GenericNameRegex("exported"),

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathGenerateIntermediate,
		},

		HelpSynopsis:    pathGenerateIntermediateHelpSyn,
		HelpDescription: pathGenerateIntermediateHelpDesc,
	}

	ret.Fields = addCACommonFields(map[string]*framework.FieldSchema{})
	ret.Fields = addCAKeyGenerationFields(ret.Fields)
	ret.Fields["add_basic_constraints"] = &framework.FieldSchema{
		Type: framework.TypeBool,
		Description: `Whether to add a Basic Constraints
extension with CA: true. Only needed as a
workaround in some compatibility scenarios
with Active Directory Certificate Services.`,
	}

	return ret
}

func pathSetSignedIntermediate(b *backend) *framework.Path {
	ret := &framework.Path{
		Pattern: "intermediate/set-signed",

		Fields: map[string]*framework.FieldSchema{
			"certificate": &framework.FieldSchema{
				Type: framework.TypeString,
				Description: `PEM-format certificate. This must be a CA
certificate with a public key matching the
previously-generated key from the generation
endpoint.`,
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathSetSignedIntermediate,
		},

		HelpSynopsis:    pathSetSignedIntermediateHelpSyn,
		HelpDescription: pathSetSignedIntermediateHelpDesc,
	}

	return ret
}

func (b *backend) pathGenerateIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	var err error

	exported, format, role, errorResp := b.getGenerationParams(data)
	if errorResp != nil {
		return errorResp, nil
	}

	var resp *logical.Response
	input := &inputBundle{
		role:    role,
		req:     req,
		apiData: data,
	}
	parsedBundle, err := generateIntermediateCSR(b, input)
	if err != nil {
		switch err.(type) {
		case errutil.UserError:
			return logical.ErrorResponse(err.Error()), nil
		default:
			return nil, err
		}
	}

	csrb, err := parsedBundle.ToCSRBundle()
	if err != nil {
		return nil, errwrap.Wrapf("error converting raw CSR bundle to CSR bundle: {{err}}", err)
	}

	resp = &logical.Response{
		Data: map[string]interface{}{},
	}

	switch format {
	case "pem":
		resp.Data["csr"] = csrb.CSR
		if exported {
			resp.Data["private_key"] = csrb.PrivateKey
			resp.Data["private_key_type"] = csrb.PrivateKeyType
		}

	case "pem_bundle":
		resp.Data["csr"] = csrb.CSR
		if exported {
			resp.Data["csr"] = fmt.Sprintf("%s\n%s", csrb.PrivateKey, csrb.CSR)
			resp.Data["private_key"] = csrb.PrivateKey
			resp.Data["private_key_type"] = csrb.PrivateKeyType
		}

	case "der":
		resp.Data["csr"] = base64.StdEncoding.EncodeToString(parsedBundle.CSRBytes)
		if exported {
			resp.Data["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes)
			resp.Data["private_key_type"] = csrb.PrivateKeyType
		}
	}

	if data.Get("private_key_format").(string) == "pkcs8" {
		err = convertRespToPKCS8(resp)
		if err != nil {
			return nil, err
		}
	}

	cb := &certutil.CertBundle{}
	cb.PrivateKey = csrb.PrivateKey
	cb.PrivateKeyType = csrb.PrivateKeyType

	entry, err := logical.StorageEntryJSON("config/ca_bundle", cb)
	if err != nil {
		return nil, err
	}
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

func (b *backend) pathSetSignedIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	cert := data.Get("certificate").(string)

	if cert == "" {
		return logical.ErrorResponse("no certificate provided in the \"certificate\" parameter"), nil
	}

	inputBundle, err := certutil.ParsePEMBundle(cert)
	if err != nil {
		switch err.(type) {
		case errutil.InternalError:
			return nil, err
		default:
			return logical.ErrorResponse(err.Error()), nil
		}
	}

	if inputBundle.Certificate == nil {
		return logical.ErrorResponse("supplied certificate could not be successfully parsed"), nil
	}

	cb := &certutil.CertBundle{}
	entry, err := req.Storage.Get(ctx, "config/ca_bundle")
	if err != nil {
		return nil, err
	}
	if entry == nil {
		return logical.ErrorResponse("could not find any existing entry with a private key"), nil
	}

	err = entry.DecodeJSON(cb)
	if err != nil {
		return nil, err
	}

	if len(cb.PrivateKey) == 0 || cb.PrivateKeyType == "" {
		return logical.ErrorResponse("could not find an existing private key"), nil
	}

	parsedCB, err := cb.ToParsedCertBundle()
	if err != nil {
		return nil, err
	}
	if parsedCB.PrivateKey == nil {
		return nil, fmt.Errorf("saved key could not be parsed successfully")
	}

	inputBundle.PrivateKey = parsedCB.PrivateKey
	inputBundle.PrivateKeyType = parsedCB.PrivateKeyType
	inputBundle.PrivateKeyBytes = parsedCB.PrivateKeyBytes

	if !inputBundle.Certificate.IsCA {
		return logical.ErrorResponse("the given certificate is not marked for CA use and cannot be used with this backend"), nil
	}

	if err := inputBundle.Verify(); err != nil {
		return nil, errwrap.Wrapf("verification of parsed bundle failed: {{err}}", err)
	}

	cb, err = inputBundle.ToCertBundle()
	if err != nil {
		return nil, errwrap.Wrapf("error converting raw values into cert bundle: {{err}}", err)
	}

	entry, err = logical.StorageEntryJSON("config/ca_bundle", cb)
	if err != nil {
		return nil, err
	}
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	entry.Key = "certs/" + normalizeSerial(cb.SerialNumber)
	entry.Value = inputBundle.CertificateBytes
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	// For ease of later use, also store just the certificate at a known
	// location
	entry.Key = "ca"
	entry.Value = inputBundle.CertificateBytes
	err = req.Storage.Put(ctx, entry)
	if err != nil {
		return nil, err
	}

	// Build a fresh CRL
	err = buildCRL(ctx, b, req, true)

	return nil, err
}

const pathGenerateIntermediateHelpSyn = `
Generate a new CSR and private key used for signing.
`

const pathGenerateIntermediateHelpDesc = `
See the API documentation for more information.
`

const pathSetSignedIntermediateHelpSyn = `
Provide the signed intermediate CA cert.
`

const pathSetSignedIntermediateHelpDesc = `
See the API documentation for more information.
`
<|endoftext|>


<commit_before>package prometheus_client

import (
	"testing"

	"github.com/influxdb/influxdb/client/v2"
	"github.com/influxdb/telegraf/plugins/prometheus"
	"github.com/influxdb/telegraf/testutil"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var pTesting *PrometheusClient

func TestPrometheusWritePointEmptyTag(t *testing.T) {

	p := &prometheus.Prometheus{
		Urls: []string{"http://localhost:9126/metrics"},
	}
	tags := make(map[string]string)
	pt1, _ := client.NewPoint(
		"test_point_1",
		tags,
		map[string]interface{}{"value": 0.0})
	pt2, _ := client.NewPoint(
		"test_point_2",
		tags,
		map[string]interface{}{"value": 1.0})
	var points = []*client.Point{
		pt1,
		pt2,
	}
	require.NoError(t, pTesting.Write(points))

	expected := []struct {
		name  string
		value float64
		tags  map[string]string
	}{
		{"test_point_1", 0.0, tags},
		{"test_point_2", 1.0, tags},
	}

	var acc testutil.Accumulator

	require.NoError(t, p.Gather(&acc))
	for _, e := range expected {
		assert.NoError(t, acc.ValidateValue(e.name, e.value))
	}
}

func TestPrometheusWritePointTag(t *testing.T) {

	p := &prometheus.Prometheus{
		Urls: []string{"http://localhost:9126/metrics"},
	}
	tags := make(map[string]string)
	tags["testtag"] = "testvalue"
	pt1, _ := client.NewPoint(
		"test_point_3",
		tags,
		map[string]interface{}{"value": 0.0})
	pt2, _ := client.NewPoint(
		"test_point_4",
		tags,
		map[string]interface{}{"value": 1.0})
	var points = []*client.Point{
		pt1,
		pt2,
	}
	require.NoError(t, pTesting.Write(points))

	expected := []struct {
		name  string
		value float64
	}{
		{"test_point_3", 0.0},
		{"test_point_4", 1.0},
	}

	var acc testutil.Accumulator

	require.NoError(t, p.Gather(&acc))
	for _, e := range expected {
		assert.True(t, acc.CheckTaggedValue(e.name, e.value, tags))
	}
}

func init() {
	pTesting = &PrometheusClient{Listen: "localhost:9126"}
	pTesting.Start()
}
<commit_msg>Make Prometheus output tests skipped in short mode.<commit_after>package prometheus_client

import (
	"testing"

	"github.com/influxdb/influxdb/client/v2"
	"github.com/influxdb/telegraf/plugins/prometheus"
	"github.com/influxdb/telegraf/testutil"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var pTesting *PrometheusClient

func TestPrometheusWritePointEmptyTag(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test in short mode")
	}

	p := &prometheus.Prometheus{
		Urls: []string{"http://localhost:9126/metrics"},
	}
	tags := make(map[string]string)
	pt1, _ := client.NewPoint(
		"test_point_1",
		tags,
		map[string]interface{}{"value": 0.0})
	pt2, _ := client.NewPoint(
		"test_point_2",
		tags,
		map[string]interface{}{"value": 1.0})
	var points = []*client.Point{
		pt1,
		pt2,
	}
	require.NoError(t, pTesting.Write(points))

	expected := []struct {
		name  string
		value float64
		tags  map[string]string
	}{
		{"test_point_1", 0.0, tags},
		{"test_point_2", 1.0, tags},
	}

	var acc testutil.Accumulator

	require.NoError(t, p.Gather(&acc))
	for _, e := range expected {
		assert.NoError(t, acc.ValidateValue(e.name, e.value))
	}
}

func TestPrometheusWritePointTag(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test in short mode")
	}

	p := &prometheus.Prometheus{
		Urls: []string{"http://localhost:9126/metrics"},
	}
	tags := make(map[string]string)
	tags["testtag"] = "testvalue"
	pt1, _ := client.NewPoint(
		"test_point_3",
		tags,
		map[string]interface{}{"value": 0.0})
	pt2, _ := client.NewPoint(
		"test_point_4",
		tags,
		map[string]interface{}{"value": 1.0})
	var points = []*client.Point{
		pt1,
		pt2,
	}
	require.NoError(t, pTesting.Write(points))

	expected := []struct {
		name  string
		value float64
	}{
		{"test_point_3", 0.0},
		{"test_point_4", 1.0},
	}

	var acc testutil.Accumulator

	require.NoError(t, p.Gather(&acc))
	for _, e := range expected {
		assert.True(t, acc.CheckTaggedValue(e.name, e.value, tags))
	}
}

func init() {
	pTesting = &PrometheusClient{Listen: "localhost:9126"}
	pTesting.Start()
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative 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 activator

import (
	"fmt"
	"net/http"
	"time"

	"github.com/knative/pkg/logging/logkey"
	"github.com/knative/serving/pkg/apis/serving"
	"github.com/knative/serving/pkg/apis/serving/v1alpha1"
	clientset "github.com/knative/serving/pkg/client/clientset/versioned"
	revisionresources "github.com/knative/serving/pkg/reconciler/v1alpha1/revision/resources"
	revisionresourcenames "github.com/knative/serving/pkg/reconciler/v1alpha1/revision/resources/names"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

var _ Activator = (*revisionActivator)(nil)

type revisionActivator struct {
	readyTimout time.Duration // for testing
	kubeClient  kubernetes.Interface
	knaClient   clientset.Interface
	logger      *zap.SugaredLogger
	reporter    StatsReporter
}

// NewRevisionActivator creates an Activator that changes revision
// serving status to active if necessary, then returns the endpoint
// once the revision is ready to serve traffic.
func NewRevisionActivator(kubeClient kubernetes.Interface, servingClient clientset.Interface, logger *zap.SugaredLogger, reporter StatsReporter) Activator {
	return &revisionActivator{
		readyTimout: 60 * time.Second,
		kubeClient:  kubeClient,
		knaClient:   servingClient,
		logger:      logger,
		reporter:    reporter,
	}
}

func (r *revisionActivator) Shutdown() {
	// nothing to do
}

func (r *revisionActivator) activateRevision(namespace, name string) (*v1alpha1.Revision, error) {
	key := fmt.Sprintf("%s/%s", namespace, name)
	logger := r.logger.With(zap.String(logkey.Key, key))
	rev := revisionID{
		namespace: namespace,
		name:      name,
	}

	// Get the current revision serving state
	revisionClient := r.knaClient.ServingV1alpha1().Revisions(rev.namespace)
	revision, err := revisionClient.Get(rev.name, metav1.GetOptions{})
	if err != nil {
		return nil, errors.Wrap(err, "Unable to get revision")
	}

	serviceName, configurationName := getServiceAndConfigurationLabels(revision)
	r.reporter.ReportRequest(namespace, serviceName, configurationName, name, string(revision.Spec.ServingState), 1.0)

	// Wait for the revision to be ready
	if !revision.Status.IsReady() {
		wi, err := r.knaClient.ServingV1alpha1().Revisions(rev.namespace).Watch(metav1.ListOptions{
			FieldSelector: fmt.Sprintf("metadata.name=%s", rev.name),
		})
		if err != nil {
			return nil, fmt.Errorf("Failed to watch the revision")
		}
		defer wi.Stop()
		ch := wi.ResultChan()
	RevisionReady:
		for {
			select {
			case <-time.After(r.readyTimout):
				return nil, errors.New("Timeout waiting for revision to become ready")
			case event := <-ch:
				if revision, ok := event.Object.(*v1alpha1.Revision); ok {
					if !revision.Status.IsReady() {
						logger.Info("Revision is not yet ready")
						continue
					} else {
						logger.Info("Revision is ready")
					}
					break RevisionReady
				} else {
					return nil, fmt.Errorf("Unexpected result type for revision: %v", event)
				}
			}
		}
	}
	return revision, nil
}

func (r *revisionActivator) getRevisionEndpoint(revision *v1alpha1.Revision) (end Endpoint, err error) {
	// Get the revision endpoint
	services := r.kubeClient.CoreV1().Services(revision.GetNamespace())
	serviceName := revisionresourcenames.K8sService(revision)
	svc, err := services.Get(serviceName, metav1.GetOptions{})
	if err != nil {
		return end, errors.Wrapf(err, "Unable to get service %s for revision", serviceName)
	}

	fqdn := fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, revision.Namespace)

	// Search for the correct port in all the service ports.
	port := int32(-1)
	for _, p := range svc.Spec.Ports {
		if p.Name == revisionresources.ServicePortName {
			port = p.Port
			break
		}
	}
	if port == -1 {
		return end, fmt.Errorf("Revision needs external. Found %v", len(svc.Spec.Ports))
	}

	return Endpoint{
		FQDN: fqdn,
		Port: port,
	}, nil
}

func (r *revisionActivator) ActiveEndpoint(namespace, name string) ActivationResult {
	key := fmt.Sprintf("%s/%s", namespace, name)
	logger := r.logger.With(zap.String(logkey.Key, key))
	revision, err := r.activateRevision(namespace, name)
	if err != nil {
		logger.Error("Failed to activate the revision.", zap.Error(err))
		return ActivationResult{
			Status: http.StatusInternalServerError,
			Error:  err,
		}
	}

	serviceName, configurationName := getServiceAndConfigurationLabels(revision)
	endpoint, err := r.getRevisionEndpoint(revision)
	if err != nil {
		logger.Error("Failed to get revision endpoint.", zap.Error(err))
		return ActivationResult{
			Status:            http.StatusInternalServerError,
			ServiceName:       serviceName,
			ConfigurationName: configurationName,
			Error:             err,
		}
	}

	return ActivationResult{
		Status:            http.StatusOK,
		Endpoint:          endpoint,
		ServiceName:       serviceName,
		ConfigurationName: configurationName,
		Error:             nil,
	}
}

func getServiceAndConfigurationLabels(rev *v1alpha1.Revision) (string, string) {
	if rev.Labels == nil {
		return "", ""
	}
	return rev.Labels[serving.ServiceLabelKey], rev.Labels[serving.ConfigurationLabelKey]
}
<commit_msg>add last check (#2256)<commit_after>/*
Copyright 2018 The Knative 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 activator

import (
	"fmt"
	"net/http"
	"time"

	"github.com/knative/pkg/logging/logkey"
	"github.com/knative/serving/pkg/apis/serving"
	"github.com/knative/serving/pkg/apis/serving/v1alpha1"
	clientset "github.com/knative/serving/pkg/client/clientset/versioned"
	revisionresources "github.com/knative/serving/pkg/reconciler/v1alpha1/revision/resources"
	revisionresourcenames "github.com/knative/serving/pkg/reconciler/v1alpha1/revision/resources/names"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

var _ Activator = (*revisionActivator)(nil)

type revisionActivator struct {
	readyTimout time.Duration // for testing
	kubeClient  kubernetes.Interface
	knaClient   clientset.Interface
	logger      *zap.SugaredLogger
	reporter    StatsReporter
}

// NewRevisionActivator creates an Activator that changes revision
// serving status to active if necessary, then returns the endpoint
// once the revision is ready to serve traffic.
func NewRevisionActivator(kubeClient kubernetes.Interface, servingClient clientset.Interface, logger *zap.SugaredLogger, reporter StatsReporter) Activator {
	return &revisionActivator{
		readyTimout: 60 * time.Second,
		kubeClient:  kubeClient,
		knaClient:   servingClient,
		logger:      logger,
		reporter:    reporter,
	}
}

func (r *revisionActivator) Shutdown() {
	// nothing to do
}

func (r *revisionActivator) activateRevision(namespace, name string) (*v1alpha1.Revision, error) {
	key := fmt.Sprintf("%s/%s", namespace, name)
	logger := r.logger.With(zap.String(logkey.Key, key))
	rev := revisionID{
		namespace: namespace,
		name:      name,
	}

	// Get the current revision serving state
	revisionClient := r.knaClient.ServingV1alpha1().Revisions(rev.namespace)
	revision, err := revisionClient.Get(rev.name, metav1.GetOptions{})
	if err != nil {
		return nil, errors.Wrap(err, "Unable to get revision")
	}

	serviceName, configurationName := getServiceAndConfigurationLabels(revision)
	r.reporter.ReportRequest(namespace, serviceName, configurationName, name, string(revision.Spec.ServingState), 1.0)

	// Wait for the revision to be ready
	if !revision.Status.IsReady() {
		wi, err := r.knaClient.ServingV1alpha1().Revisions(rev.namespace).Watch(metav1.ListOptions{
			FieldSelector: fmt.Sprintf("metadata.name=%s", rev.name),
		})
		if err != nil {
			return nil, fmt.Errorf("Failed to watch the revision")
		}
		defer wi.Stop()
		ch := wi.ResultChan()
	RevisionReady:
		for {
			select {
			case <-time.After(r.readyTimout):
				// last chance to check
				if revision.Status.IsReady() {
					break RevisionReady
				}
				return nil, errors.New("Timeout waiting for revision to become ready")
			case event := <-ch:
				if revision, ok := event.Object.(*v1alpha1.Revision); ok {
					if !revision.Status.IsReady() {
						logger.Info("Revision is not yet ready")
						continue
					} else {
						logger.Info("Revision is ready")
					}
					break RevisionReady
				} else {
					return nil, fmt.Errorf("Unexpected result type for revision: %v", event)
				}
			}
		}
	}
	return revision, nil
}

func (r *revisionActivator) getRevisionEndpoint(revision *v1alpha1.Revision) (end Endpoint, err error) {
	// Get the revision endpoint
	services := r.kubeClient.CoreV1().Services(revision.GetNamespace())
	serviceName := revisionresourcenames.K8sService(revision)
	svc, err := services.Get(serviceName, metav1.GetOptions{})
	if err != nil {
		return end, errors.Wrapf(err, "Unable to get service %s for revision", serviceName)
	}

	fqdn := fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, revision.Namespace)

	// Search for the correct port in all the service ports.
	port := int32(-1)
	for _, p := range svc.Spec.Ports {
		if p.Name == revisionresources.ServicePortName {
			port = p.Port
			break
		}
	}
	if port == -1 {
		return end, fmt.Errorf("Revision needs external. Found %v", len(svc.Spec.Ports))
	}

	return Endpoint{
		FQDN: fqdn,
		Port: port,
	}, nil
}

func (r *revisionActivator) ActiveEndpoint(namespace, name string) ActivationResult {
	key := fmt.Sprintf("%s/%s", namespace, name)
	logger := r.logger.With(zap.String(logkey.Key, key))
	revision, err := r.activateRevision(namespace, name)
	if err != nil {
		logger.Error("Failed to activate the revision.", zap.Error(err))
		return ActivationResult{
			Status: http.StatusInternalServerError,
			Error:  err,
		}
	}

	serviceName, configurationName := getServiceAndConfigurationLabels(revision)
	endpoint, err := r.getRevisionEndpoint(revision)
	if err != nil {
		logger.Error("Failed to get revision endpoint.", zap.Error(err))
		return ActivationResult{
			Status:            http.StatusInternalServerError,
			ServiceName:       serviceName,
			ConfigurationName: configurationName,
			Error:             err,
		}
	}

	return ActivationResult{
		Status:            http.StatusOK,
		Endpoint:          endpoint,
		ServiceName:       serviceName,
		ConfigurationName: configurationName,
		Error:             nil,
	}
}

func getServiceAndConfigurationLabels(rev *v1alpha1.Revision) (string, string) {
	if rev.Labels == nil {
		return "", ""
	}
	return rev.Labels[serving.ServiceLabelKey], rev.Labels[serving.ConfigurationLabelKey]
}
<|endoftext|>


<commit_before>package automation

import (
	"google.golang.org/api/recommender/v1"
)

type gcloudClaimedRequest = recommender.GoogleCloudRecommenderV1MarkRecommendationClaimedRequest
type gcloudFailedRequest = recommender.GoogleCloudRecommenderV1MarkRecommendationFailedRequest
type gcloudSucceededRequest = recommender.GoogleCloudRecommenderV1MarkRecommendationSucceededRequest

func (s *googleService) MarkRecommendationClaimed(name, etag string) error {
	r := recommender.NewProjectsLocationsRecommendersRecommendationsService(s.recommenderService)
	request := gcloudClaimedRequest{
		Etag: etag,
	}

	markClaimedCall := r.MarkClaimed(name, &request)
	_, err := markClaimedCall.Do()

	return err
}

func (s *googleService) MarkRecommendationFailed(name, etag string) error {
	r := recommender.NewProjectsLocationsRecommendersRecommendationsService(s.recommenderService)
	request := gcloudFailedRequest{
		Etag: etag,
	}

	markFailedCall := r.MarkFailed(name, &request)
	_, err := markFailedCall.Do()

	return err
}

func (s *googleService) MarkRecommendationSucceded(name, etag string) error {
	r := recommender.NewProjectsLocationsRecommendersRecommendationsService(s.recommenderService)
	request := gcloudSucceededRequest{
		Etag: etag,
	}

	markSucceededCall := r.MarkSucceeded(name, &request)
	_, err := markSucceededCall.Do()

	return err
}
<commit_msg>Added comments<commit_after>package automation

import (
	"google.golang.org/api/recommender/v1"
)

type gcloudClaimedRequest = recommender.GoogleCloudRecommenderV1MarkRecommendationClaimedRequest
type gcloudFailedRequest = recommender.GoogleCloudRecommenderV1MarkRecommendationFailedRequest
type gcloudSucceededRequest = recommender.GoogleCloudRecommenderV1MarkRecommendationSucceededRequest

// Marks the recommendation defined by the given name and etag as claimed
func (s *googleService) MarkRecommendationClaimed(name, etag string) error {
	r := recommender.NewProjectsLocationsRecommendersRecommendationsService(s.recommenderService)
	request := gcloudClaimedRequest{
		Etag: etag,
	}

	markClaimedCall := r.MarkClaimed(name, &request)
	_, err := markClaimedCall.Do()

	return err
}

// Marks the recommendation defined by the given name and etag as failed
func (s *googleService) MarkRecommendationFailed(name, etag string) error {
	r := recommender.NewProjectsLocationsRecommendersRecommendationsService(s.recommenderService)
	request := gcloudFailedRequest{
		Etag: etag,
	}

	markFailedCall := r.MarkFailed(name, &request)
	_, err := markFailedCall.Do()

	return err
}

// Marks the recommendation defined by the given name and etag as succeded
func (s *googleService) MarkRecommendationSucceded(name, etag string) error {
	r := recommender.NewProjectsLocationsRecommendersRecommendationsService(s.recommenderService)
	request := gcloudSucceededRequest{
		Etag: etag,
	}

	markSucceededCall := r.MarkSucceeded(name, &request)
	_, err := markSucceededCall.Do()

	return err
}
<|endoftext|>


<commit_before>package config

import (
	"testing"

	"github.com/oif/apex/pkg/types"
	"github.com/stretchr/testify/assert"
)

func TestLoadConfig(t *testing.T) {
	config := NewConfig()
	assert.NotPanics(t, func() {
		config.Load("test.toml").Check()
	}, "This test case should not panic")
	assert.Equal(t, DefaultListenAddress, config.ListenAddress, "Set default listen address where ListenAddress is empty in config")
	assert.Equal(t, DefaultListenProtocol, config.ListenProtocol, "Set default listen protocol where ListenProtocol is empty in config")

	config = NewConfig()
	assert.Panics(t, func() {
		config.Load("no_exists.toml")
	}, "Should panic due to file not exists")

	config = NewConfig()
	assert.Panics(t, func() {
		config.Load("test_bad.toml")
	}, "Should panic due to invalid toml format file given")
}

func TestUpstreamCheck(t *testing.T) {
	ups := &Upstream{}
	assert.Panics(t, func() {
		ups.Check()
	}, "Should panic due to primary DNS and alternative DNS are both empty")

	ups.PrimaryDNS = append(ups.PrimaryDNS, &types.Upstream{})
	assert.Panics(t, func() {
		ups.Check()
	}, "Should panic due to primary DNS check fail")

	ups.PrimaryDNS = make([]*types.Upstream, 0)

	ups.AlternativeDNS = append(ups.AlternativeDNS, &types.Upstream{})
	ups.AlternativeDNS = append(ups.PrimaryDNS, &types.Upstream{})
	assert.Panics(t, func() {
		ups.Check()
	}, "Should panic due to alternative DNS check fail")

	ups.AlternativeDNS[0] = &types.Upstream{
		Name:     "Google DNS",
		Address:  "8.8.8.8:53",
		Protocol: "udp",
	}
	assert.NotPanics(t, func() {
		ups.Check()
	}, "No panic here")
}

func TestProxyCheck(t *testing.T) {
	p := &Proxy{
		Policy: "",
	}

	assert.Panics(t, func() {
		p.Check()
	}, "Should Panic due to invalid policy")

	p.Policy = types.ProxyActivePolicy
	assert.Panics(t, func() {
		p.Check()
	}, "Should panic due to did not set proxy")

	p.Proxy = &types.Proxy{
		Protocol: "http",
	}
	assert.Panics(t, func() {
		p.Check()
	}, "Should panic due to invalid proxy")

	p.Proxy = &types.Proxy{
		Protocol: "http",
		Address:  "127.0.0.1:1080",
	}
	assert.NotPanics(t, func() {
		p.Check()
	}, "No panic here")
}

func TestCacheCheck(t *testing.T) {
	c := &Cache{
		Enable: true,
		Size:   -1,
	}

	assert.Panics(t, func() {
		c.Check()
	}, "Should panic due to invalid size")

	c.Size = 2
	assert.NotPanics(t, func() {
		c.Check()
	}, "No panic here")
}

func TestHostsCheck(t *testing.T) {
	h := &Hosts{
		Enable: true,
	}

	assert.Panics(t, func() {
		h.Check()
	}, "Should panic due to empty address")

	h.Address = "https://line.cat/hosts"
	assert.Panics(t, func() {
		h.Check()
	}, "Should panic due to update interval < 0")

	h.UpdateInterval = 3600
	assert.NotPanics(t, func() {
		h.Check()
	}, "No panic here")
}
<commit_msg>MOD: enhance config test case<commit_after>package config

import (
	"testing"

	"github.com/oif/apex/pkg/types"
	"github.com/stretchr/testify/assert"
)

func TestLoadConfig(t *testing.T) {
	config := NewConfig()
	assert.NotPanics(t, func() {
		config.Load("test.toml").Check()
	}, "This test case should not panic")
	assert.Equal(t, DefaultListenAddress, config.ListenAddress, "Set default listen address where ListenAddress is empty in config")
	assert.Equal(t, DefaultListenProtocol, config.ListenProtocol, "Set default listen protocol where ListenProtocol is empty in config")

	config = NewConfig()
	config.ListenProtocol = "http"
	assert.Panics(t, func() { config.Check() }, "Panic due to invalid listen protocol")

	config = NewConfig()
	assert.Panics(t, func() {
		config.Load("no_exists.toml")
	}, "Should panic due to file not exists")

	config = NewConfig()
	assert.Panics(t, func() {
		config.Load("test_bad.toml")
	}, "Should panic due to invalid toml format file given")
}

func TestUpstreamCheck(t *testing.T) {
	ups := &Upstream{}
	assert.Panics(t, func() {
		ups.Check()
	}, "Should panic due to primary DNS and alternative DNS are both empty")

	ups.PrimaryDNS = append(ups.PrimaryDNS, &types.Upstream{})
	assert.Panics(t, func() {
		ups.Check()
	}, "Should panic due to primary DNS check fail")

	ups.PrimaryDNS = make([]*types.Upstream, 0)

	ups.AlternativeDNS = append(ups.AlternativeDNS, &types.Upstream{})
	ups.AlternativeDNS = append(ups.PrimaryDNS, &types.Upstream{})
	assert.Panics(t, func() {
		ups.Check()
	}, "Should panic due to alternative DNS check fail")

	ups.AlternativeDNS[0] = &types.Upstream{
		Name:     "Google DNS",
		Address:  "8.8.8.8:53",
		Protocol: "udp",
	}
	assert.NotPanics(t, func() {
		ups.Check()
	}, "No panic here")
}

func TestProxyCheck(t *testing.T) {
	p := &Proxy{
		Policy: "",
	}

	assert.Panics(t, func() {
		p.Check()
	}, "Should Panic due to invalid policy")

	p.Policy = types.ProxyActivePolicy
	assert.Panics(t, func() {
		p.Check()
	}, "Should panic due to did not set proxy")

	p.Proxy = &types.Proxy{
		Protocol: "http",
	}
	assert.Panics(t, func() {
		p.Check()
	}, "Should panic due to invalid proxy")

	p.Proxy = &types.Proxy{
		Protocol: "http",
		Address:  "127.0.0.1:1080",
	}
	assert.NotPanics(t, func() {
		p.Check()
	}, "No panic here")
}

func TestCacheCheck(t *testing.T) {
	c := &Cache{
		Enable: true,
		Size:   -1,
	}

	assert.Panics(t, func() {
		c.Check()
	}, "Should panic due to invalid size")

	c.Size = 2
	assert.NotPanics(t, func() {
		c.Check()
	}, "No panic here")
}

func TestHostsCheck(t *testing.T) {
	h := &Hosts{
		Enable: true,
	}

	assert.Panics(t, func() {
		h.Check()
	}, "Should panic due to empty address")

	h.Address = "https://line.cat/hosts"
	assert.Panics(t, func() {
		h.Check()
	}, "Should panic due to update interval < 0")

	h.UpdateInterval = 3600
	assert.NotPanics(t, func() {
		h.Check()
	}, "No panic here")
}
<|endoftext|>


<commit_before>package controller

import (
	"bytes"
	"fmt"
	"time"

	"github.com/golang/glog"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"

	platform "kolihub.io/koli/pkg/apis/v1alpha1"
	"kolihub.io/koli/pkg/apis/v1alpha1/draft"
	"kolihub.io/koli/pkg/util"
)

// SecretController generates dynamic secrets through namespaces. It manages secrets
// which have specific expiration time, usually used for machine-to-machine communication
// with limited access throughout the platform
type SecretController struct {
	kclient kubernetes.Interface

	nsInf cache.SharedIndexInformer
	skInf cache.SharedIndexInformer

	queue    *TaskQueue
	recorder record.EventRecorder

	jwtSecret string
}

// NewSecretController creates a new SecretController
func NewSecretController(nsInf, skInf cache.SharedIndexInformer, client kubernetes.Interface, jwtSecret string) *SecretController {
	c := &SecretController{
		kclient:   client,
		nsInf:     nsInf,
		skInf:     skInf,
		recorder:  newRecorder(client, "secret-controller"),
		jwtSecret: jwtSecret,
	}
	c.queue = NewTaskQueue(c.syncHandler)
	c.nsInf.AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc:    c.addNamespace,
		UpdateFunc: c.updateNamespace,
	})
	return c
}

func (c *SecretController) addNamespace(n interface{}) {
	new := n.(*v1.Namespace)
	glog.V(2).Infof("%s(%s) - add-namespace", new.Name, new.ResourceVersion)
	c.queue.Add(new)
}

func (c *SecretController) updateNamespace(o, n interface{}) {
	new := n.(*v1.Namespace)
	glog.V(2).Infof("%s(%s) - update-namespace", new.Name, new.ResourceVersion)
	c.queue.Add(new)
}

// Run the controller.
func (c *SecretController) Run(workers int, stopc <-chan struct{}) {
	// don't let panics crash the process
	defer utilruntime.HandleCrash()
	// make sure the work queue is shutdown which will trigger workers to end
	defer c.queue.shutdown()

	glog.Info("Starting Secret controller...")

	if !cache.WaitForCacheSync(stopc, c.nsInf.HasSynced) {
		return
	}

	for i := 0; i < workers; i++ {
		// runWorker will loop until "something bad" happens.
		// The .Until will then rekick the worker after one second
		go c.queue.run(time.Second, stopc)
	}

	// wait until we're told to stop
	<-stopc
	glog.Info("Shutting down Secret controller")
}

func (c *SecretController) syncHandler(key string) error {
	obj, exists, err := c.nsInf.GetStore().GetByKey(key)
	if err != nil {
		glog.Warningf("%s - failed retrieving object from store [%s]", key, err)
		return err
	}
	if !exists {
		glog.V(3).Infof("%s - the namespace doesn't exists", key)
		return nil
	}
	ns := obj.(*v1.Namespace)
	if ns.DeletionTimestamp != nil {
		glog.V(3).Infof("%s - object marked for deletion, skip ...", key)
		return nil
	}

	nsMeta := draft.NewNamespaceMetadata(ns.Name)
	if !nsMeta.IsValid() {
		glog.V(3).Infof("%s - it's not a valid namespace, skip ...", key)
		return nil
	}

	// Verify the last time an object was synced, using a shared informer doesn't permit having a
	// custom resync time, thus veryfing if an object can perform a sync operation is important.
	// This validation prevents starving resources from the api server
	if obj, exists, _ = c.skInf.GetStore().GetByKey(fmt.Sprintf("%s/%s", key, platform.SystemSecretName)); exists {
		s := obj.(*v1.Secret)
		if s.Annotations != nil {
			lastUpdated, err := time.Parse(time.RFC3339, s.Annotations[platform.AnnotationSecretLastUpdated])
			if err == nil && lastUpdated.Add(time.Minute*20).After(time.Now().UTC()) {
				glog.V(3).Infof(`%s/%s - to soon for updating secret "%s"`, key, platform.SystemSecretName, lastUpdated.Format(time.RFC3339))
				return nil
			}
			if err != nil {
				glog.Warningf("%s - got error converting time [%v]", key, err)
			}
		}
	}
	// Generate a system token based on the customer and organization of the namespace.
	// The access token has limited access to the resources of the platform
	tokenString, err := util.GenerateNewJwtToken(
		c.jwtSecret,
		nsMeta.Customer(),
		nsMeta.Organization(),
		platform.SystemTokenType,
		time.Now().UTC().Add(time.Hour*1), // hard-coded exp time
	)
	if err != nil {
		glog.Warningf("%s - failed generating system token [%v]", key, err)
		return nil
	}

	// Patching an object primarily is less expensive because the most part of
	// secret resources will be synced in each resync
	s, err := c.kclient.Core().Secrets(ns.Name).Patch(
		platform.SystemSecretName,
		types.StrategicMergePatchType,
		genSystemTokenPatchData(tokenString),
	)
	if err != nil && !apierrors.IsNotFound(err) {
		return fmt.Errorf("failed updating secret [%v]", err)
	}
	if s != nil {
		glog.V(3).Infof(`%s/%s secret updated with success, `, key, s.Name)
		return nil
	}

	_, err = c.kclient.Core().Secrets(ns.Name).Create(&v1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: ns.Name,
			Name:      platform.SystemSecretName,
			Labels:    map[string]string{platform.LabelSecretController: "true"},
			Annotations: map[string]string{
				platform.AnnotationSecretLastUpdated: time.Now().UTC().Format(time.RFC3339),
			},
		},
		Data: map[string][]byte{
			"token.jwt": bytes.NewBufferString(tokenString).Bytes(),
		},
		Type: v1.SecretTypeOpaque,
	})
	if err != nil {
		return fmt.Errorf("failed creating secret [%v]", err)
	}
	glog.V(3).Infof("%s/%s secret created with success", key, platform.SystemSecretName)
	return nil
}

func genSystemTokenPatchData(token string) []byte {
	return []byte(
		fmt.Sprintf(
			`{"metadata": {"labels": {"%s": "true"}, "annotations": {"%s": "%s"}}, "data": {"token.jwt": "%s"}, "type": "Opaque"}`,
			platform.LabelSecretController,
			platform.AnnotationSecretLastUpdated,
			time.Now().UTC().Format(time.RFC3339),
			token,
		),
	)
}
<commit_msg>Correcting wrong logic when patching the resource<commit_after>package controller

import (
	"bytes"
	"fmt"
	"time"

	"github.com/golang/glog"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"

	platform "kolihub.io/koli/pkg/apis/v1alpha1"
	"kolihub.io/koli/pkg/apis/v1alpha1/draft"
	"kolihub.io/koli/pkg/util"
)

// SecretController generates dynamic secrets through namespaces. It manages secrets
// which have specific expiration time, usually used for machine-to-machine communication
// with limited access throughout the platform
type SecretController struct {
	kclient kubernetes.Interface

	nsInf cache.SharedIndexInformer
	skInf cache.SharedIndexInformer

	queue    *TaskQueue
	recorder record.EventRecorder

	jwtSecret string
}

// NewSecretController creates a new SecretController
func NewSecretController(nsInf, skInf cache.SharedIndexInformer, client kubernetes.Interface, jwtSecret string) *SecretController {
	c := &SecretController{
		kclient:   client,
		nsInf:     nsInf,
		skInf:     skInf,
		recorder:  newRecorder(client, "secret-controller"),
		jwtSecret: jwtSecret,
	}
	c.queue = NewTaskQueue(c.syncHandler)
	c.nsInf.AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc:    c.addNamespace,
		UpdateFunc: c.updateNamespace,
	})
	return c
}

func (c *SecretController) addNamespace(n interface{}) {
	new := n.(*v1.Namespace)
	glog.V(2).Infof("%s(%s) - add-namespace", new.Name, new.ResourceVersion)
	c.queue.Add(new)
}

func (c *SecretController) updateNamespace(o, n interface{}) {
	new := n.(*v1.Namespace)
	glog.V(2).Infof("%s(%s) - update-namespace", new.Name, new.ResourceVersion)
	c.queue.Add(new)
}

// Run the controller.
func (c *SecretController) Run(workers int, stopc <-chan struct{}) {
	// don't let panics crash the process
	defer utilruntime.HandleCrash()
	// make sure the work queue is shutdown which will trigger workers to end
	defer c.queue.shutdown()

	glog.Info("Starting Secret controller...")

	if !cache.WaitForCacheSync(stopc, c.nsInf.HasSynced) {
		return
	}

	for i := 0; i < workers; i++ {
		// runWorker will loop until "something bad" happens.
		// The .Until will then rekick the worker after one second
		go c.queue.run(time.Second, stopc)
	}

	// wait until we're told to stop
	<-stopc
	glog.Info("Shutting down Secret controller")
}

func (c *SecretController) syncHandler(key string) error {
	obj, exists, err := c.nsInf.GetStore().GetByKey(key)
	if err != nil {
		glog.Warningf("%s - failed retrieving object from store [%s]", key, err)
		return err
	}
	if !exists {
		glog.V(3).Infof("%s - the namespace doesn't exists", key)
		return nil
	}
	ns := obj.(*v1.Namespace)
	if ns.DeletionTimestamp != nil {
		glog.V(3).Infof("%s - object marked for deletion, skip ...", key)
		return nil
	}

	nsMeta := draft.NewNamespaceMetadata(ns.Name)
	if !nsMeta.IsValid() {
		glog.V(3).Infof("%s - it's not a valid namespace, skip ...", key)
		return nil
	}

	// Verify the last time an object was synced, using a shared informer doesn't permit having a
	// custom resync time, thus veryfing if an object can perform a sync operation is important.
	// This validation prevents starving resources from the api server
	if obj, exists, _ = c.skInf.GetStore().GetByKey(fmt.Sprintf("%s/%s", key, platform.SystemSecretName)); exists {
		s := obj.(*v1.Secret)
		if s.Annotations != nil {
			lastUpdated, err := time.Parse(time.RFC3339, s.Annotations[platform.AnnotationSecretLastUpdated])
			if err == nil && lastUpdated.Add(time.Minute*20).After(time.Now().UTC()) {
				glog.V(3).Infof(`%s/%s - to soon for updating secret "%s"`, key, platform.SystemSecretName, lastUpdated.Format(time.RFC3339))
				return nil
			}
			if err != nil {
				glog.Warningf("%s - got error converting time [%v]", key, err)
			}
		}
	}
	// Generate a system token based on the customer and organization of the namespace.
	// The access token has limited access to the resources of the platform
	tokenString, err := util.GenerateNewJwtToken(
		c.jwtSecret,
		nsMeta.Customer(),
		nsMeta.Organization(),
		platform.SystemTokenType,
		time.Now().UTC().Add(time.Hour*1), // hard-coded exp time
	)
	if err != nil {
		glog.Warningf("%s - failed generating system token [%v]", key, err)
		return nil
	}

	// Patching an object primarily is less expensive because the most part of
	// secret resources will be synced in each resync
	_, err = c.kclient.Core().Secrets(ns.Name).Patch(
		platform.SystemSecretName,
		types.StrategicMergePatchType,
		genSystemTokenPatchData(tokenString),
	)
	if err != nil && !apierrors.IsNotFound(err) {
		return fmt.Errorf("failed updating secret [%v]", err)
	}
	if err == nil {
		glog.V(3).Infof(`%s/%s secret updated with success`, key, platform.SystemSecretName)
		return nil
	}

	_, err = c.kclient.Core().Secrets(ns.Name).Create(&v1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: ns.Name,
			Name:      platform.SystemSecretName,
			Labels:    map[string]string{platform.LabelSecretController: "true"},
			Annotations: map[string]string{
				platform.AnnotationSecretLastUpdated: time.Now().UTC().Format(time.RFC3339),
			},
		},
		Data: map[string][]byte{
			"token.jwt": bytes.NewBufferString(tokenString).Bytes(),
		},
		Type: v1.SecretTypeOpaque,
	})
	if err != nil {
		return fmt.Errorf("failed creating secret [%v]", err)
	}
	glog.V(3).Infof("%s/%s secret created with success", key, platform.SystemSecretName)
	return nil
}

func genSystemTokenPatchData(token string) []byte {
	return []byte(
		fmt.Sprintf(
			`{"metadata": {"labels": {"%s": "true"}, "annotations": {"%s": "%s"}}, "data": {"token.jwt": "%s"}, "type": "Opaque"}`,
			platform.LabelSecretController,
			platform.AnnotationSecretLastUpdated,
			time.Now().UTC().Format(time.RFC3339),
			token,
		),
	)
}
<|endoftext|>


<commit_before>/*
 * Minio Cloud Storage, (C) 2019 Minio, Inc.
 *
 * 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 cpu

import (
	"errors"
)

func newCounter() (counter, error) {
	return counter{}, errors.New("cpu metrics not implemented for darwin platform")
}

func (c counter) now() time.Time {
	return time.Time{}
}
<commit_msg>Add missing time import to counter_darwin.go (#7081)<commit_after>/*
 * Minio Cloud Storage, (C) 2019 Minio, Inc.
 *
 * 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 cpu

import (
	"errors"
	"time"
)

func newCounter() (counter, error) {
	return counter{}, errors.New("cpu metrics not implemented for darwin platform")
}

func (c counter) now() time.Time {
	return time.Time{}
}
<|endoftext|>


<commit_before>package net

import (
	"context"
	"crypto/tls"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"time"

	igd "github.com/emersion/go-upnp-igd"
	"golang.org/x/net/http2"

	"nimona.io/internal/log"
	"nimona.io/pkg/crypto"
)

type httpTransport struct {
	local   *LocalInfo
	address string
}

func NewHTTPTransport(
	local *LocalInfo,
	address string,
) Transport {
	return &httpTransport{
		local:   local,
		address: address,
	}
}

func (tt *httpTransport) Dial(
	ctx context.Context,
	address string,
) (
	*Connection,
	error,
) {
	address = strings.Replace(address, "https:", "https://", 1)
	address = strings.Replace(address, ":443", "", 1)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true, // nolint: gosec
		},
	}
	if err := http2.ConfigureTransport(tr); err != nil {
		return nil, err
	}

	client := &http.Client{
		Transport: tr,
	}
	pr, pw := io.Pipe()
	req, _ := http.NewRequest("GET", address, ioutil.NopCloser(pr))
	req.ContentLength = -1
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	rw := &connWrapper{
		w: flushWriter{pw},
		r: res.Body,
		c: res.Body,
	}

	conn := &Connection{
		Conn:          rw,
		RemotePeerKey: nil, // we don't really know who the other side is
	}

	return conn, nil
}

func (tt *httpTransport) Listen(
	ctx context.Context,
) (
	chan *Connection,
	error,
) {

	logger := log.FromContext(ctx).Named("transport/https")

	cert, err := crypto.GenerateCertificate(tt.local.GetPeerKey())
	if err != nil {
		return nil, err
	}

	config := &tls.Config{
		NextProtos:   []string{"h2"},
		Certificates: []tls.Certificate{*cert},
	}

	cconn := make(chan *Connection, 10)

	handler := func(w http.ResponseWriter, r *http.Request) {
		wf, ok := w.(http.Flusher)
		if !ok {
			http.Error(w, "only h2 is supported", 400)
			return
		}

		wf.Flush()

		rw := &connWrapper{
			w: flushWriter{w},
			r: r.Body,
			c: r.Body,
		}

		conn := &Connection{
			Conn:          rw,
			RemotePeerKey: nil,
			IsIncoming:    true,
		}

		cconn <- conn

		<-r.Cancel // TODO is this the right way to wait here?
	}

	srv := &http.Server{
		Addr:    tt.address,
		Handler: http.HandlerFunc(handler),
	}

	netListener, err := net.Listen("tcp", tt.address)
	if err != nil {
		return nil, err
	}

	tlsListener := tls.NewListener(
		tcpKeepAliveListener{
			netListener.(*net.TCPListener),
		},
		config,
	)

	go func() {
		err := srv.Serve(tlsListener)
		if err != nil {
			logger.Error("http transport stopped", log.Error(err))
		}
	}()

	port := netListener.Addr().(*net.TCPAddr).Port
	logger.Info("HTTP tranport listening", log.Int("port", port))
	devices := make(chan igd.Device, 10)

	useIPs := true

	addresses := []string{}

	if tt.local.GetHostname() != "" {
		useIPs = false
		addresses = append(addresses, fmtAddress("https", tt.local.GetHostname(), port))
	}

	if useIPs {
		addresses = append(addresses, GetAddresses("https", netListener)...)

	}

	if UseUPNP {
		logger.Info("Trying to find external IP and open port")
		go func() {
			if err := igd.Discover(devices, 2*time.Second); err != nil {
				logger.Error("could not discover devices", log.Error(err))
			}
		}()
		for device := range devices {
			externalAddress, err := device.GetExternalIPAddress()
			if err != nil {
				logger.Error("could not get external ip", log.Error(err))
				continue
			}
			desc := "nimona-http"
			ttl := time.Hour * 24 * 365
			if _, err := device.AddPortMapping(igd.TCP, port, port, desc, ttl); err != nil {
				logger.Error("could not add port mapping", log.Error(err))
			} else if useIPs {
				addresses = append(addresses, fmtAddress("https", externalAddress.String(), port))
			}
		}
	}

	tt.local.AddAddress(addresses...)

	logger.Info(
		"Started listening",
		log.Strings("addresses", addresses),
		log.Int("port", port),
	)

	return cconn, nil
}

type flushWriter struct {
	w io.Writer
}

func (fw flushWriter) Write(p []byte) (n int, err error) {
	n, err = fw.w.Write(p)
	if f, ok := fw.w.(http.Flusher); ok {
		f.Flush()
	}
	return
}

func (fw flushWriter) Flush() {
	if f, ok := fw.w.(http.Flusher); ok {
		f.Flush()
	}
}

type connWrapper struct {
	r io.Reader
	w io.Writer
	c io.Closer
}

func (fw connWrapper) Write(p []byte) (int, error) {
	n, err := fw.w.Write(p)
	if f, ok := fw.w.(http.Flusher); ok {
		f.Flush()
	}
	return n, err
}

func (fw connWrapper) Read(b []byte) (int, error) {
	return fw.r.Read(b)
}

func (fw connWrapper) Close() error {
	return fw.c.Close()
}

// From https://golang.org/src/net/http/server.go
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	if err := tc.SetKeepAlive(true); err != nil {
		return nil, err
	}
	if err := tc.SetKeepAlivePeriod(time.Minute); err != nil {
		return nil, err
	}
	return tc, nil
}
<commit_msg>fix(net/http): temporarily lock conn<commit_after>package net

import (
	"context"
	"crypto/tls"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	igd "github.com/emersion/go-upnp-igd"
	"golang.org/x/net/http2"

	"nimona.io/internal/log"
	"nimona.io/pkg/crypto"
)

type httpTransport struct {
	local   *LocalInfo
	address string
}

func NewHTTPTransport(
	local *LocalInfo,
	address string,
) Transport {
	return &httpTransport{
		local:   local,
		address: address,
	}
}

func (tt *httpTransport) Dial(
	ctx context.Context,
	address string,
) (
	*Connection,
	error,
) {
	address = strings.Replace(address, "https:", "https://", 1)
	address = strings.Replace(address, ":443", "", 1)

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true, // nolint: gosec
		},
	}
	if err := http2.ConfigureTransport(tr); err != nil {
		return nil, err
	}

	client := &http.Client{
		Transport: tr,
	}
	pr, pw := io.Pipe()
	req, _ := http.NewRequest("GET", address, ioutil.NopCloser(pr))
	req.ContentLength = -1
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	rw := &connWrapper{
		w: pw,
		r: res.Body,
		c: res.Body,
	}

	conn := &Connection{
		Conn:          rw,
		RemotePeerKey: nil, // we don't really know who the other side is
	}

	return conn, nil
}

func (tt *httpTransport) Listen(
	ctx context.Context,
) (
	chan *Connection,
	error,
) {

	logger := log.FromContext(ctx).Named("transport/https")

	cert, err := crypto.GenerateCertificate(tt.local.GetPeerKey())
	if err != nil {
		return nil, err
	}

	config := &tls.Config{
		NextProtos:   []string{"h2"},
		Certificates: []tls.Certificate{*cert},
	}

	cconn := make(chan *Connection, 10)

	handler := func(w http.ResponseWriter, r *http.Request) {
		wf, ok := w.(http.Flusher)
		if !ok {
			http.Error(w, "only h2 is supported", 400)
			return
		}

		wf.Flush()

		rw := &connWrapper{
			w: w,
			r: r.Body,
			c: r.Body,
		}

		conn := &Connection{
			Conn:          rw,
			RemotePeerKey: nil,
			IsIncoming:    true,
		}

		cconn <- conn

		<-r.Cancel // TODO is this the right way to wait here?
	}

	srv := &http.Server{
		Addr:    tt.address,
		Handler: http.HandlerFunc(handler),
	}

	netListener, err := net.Listen("tcp", tt.address)
	if err != nil {
		return nil, err
	}

	tlsListener := tls.NewListener(
		tcpKeepAliveListener{
			netListener.(*net.TCPListener),
		},
		config,
	)

	go func() {
		err := srv.Serve(tlsListener)
		if err != nil {
			logger.Error("http transport stopped", log.Error(err))
		}
	}()

	port := netListener.Addr().(*net.TCPAddr).Port
	logger.Info("HTTP tranport listening", log.Int("port", port))
	devices := make(chan igd.Device, 10)

	useIPs := true

	addresses := []string{}

	if tt.local.GetHostname() != "" {
		useIPs = false
		addresses = append(addresses, fmtAddress("https", tt.local.GetHostname(), port))
	}

	if useIPs {
		addresses = append(addresses, GetAddresses("https", netListener)...)

	}

	if UseUPNP {
		logger.Info("Trying to find external IP and open port")
		go func() {
			if err := igd.Discover(devices, 2*time.Second); err != nil {
				logger.Error("could not discover devices", log.Error(err))
			}
		}()
		for device := range devices {
			externalAddress, err := device.GetExternalIPAddress()
			if err != nil {
				logger.Error("could not get external ip", log.Error(err))
				continue
			}
			desc := "nimona-http"
			ttl := time.Hour * 24 * 365
			if _, err := device.AddPortMapping(igd.TCP, port, port, desc, ttl); err != nil {
				logger.Error("could not add port mapping", log.Error(err))
			} else if useIPs {
				addresses = append(addresses, fmtAddress("https", externalAddress.String(), port))
			}
		}
	}

	tt.local.AddAddress(addresses...)

	logger.Info(
		"Started listening",
		log.Strings("addresses", addresses),
		log.Int("port", port),
	)

	return cconn, nil
}

type connWrapper struct {
	r io.Reader
	w io.Writer
	c io.Closer
	l sync.Mutex
}

func (fw connWrapper) Write(p []byte) (int, error) {
	fw.l.Lock()
	defer fw.l.Unlock()

	n, err := fw.w.Write(p)
	if f, ok := fw.w.(http.Flusher); ok {
		f.Flush()
	}
	return n, err
}

func (fw connWrapper) Read(b []byte) (int, error) {
	return fw.r.Read(b)
}

func (fw connWrapper) Close() error {
	return fw.c.Close()
}

// From https://golang.org/src/net/http/server.go
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	if err := tc.SetKeepAlive(true); err != nil {
		return nil, err
	}
	if err := tc.SetKeepAlivePeriod(time.Minute); err != nil {
		return nil, err
	}
	return tc, nil
}
<|endoftext|>