<commit_before>package webp

/*
#include <stdlib.h>
#include <webp/decode.h>

static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer);

*/
import "C"

import (
	"errors"
	"fmt"
	"image"
	"unsafe"
)

// DecoderOptions specifies decoding options of WebP.
type DecoderOptions struct {
	BypassFiltering        bool            // If true, bypass filtering process
	NoFancyUpsampling      bool            // If true, do not fancy upsampling
	Crop                   image.Rectangle // Do cropping if image.Rectangle is not empty.
	Scale                  image.Rectangle // Do scaling if image.Rectangle is not empty.
	UseThreads             bool            // If true, use multi threads
	DitheringStrength      int             // Specify dithering strength [0=Off .. 100=full]
	Flip                   bool            // If true, flip output vertically
	AlphaDitheringStrength int             // Specify alpha dithering strength in [0..100]
}

// BitstreamFeatures represents the image properties which are retrived from
// data stream.
type BitstreamFeatures struct {
	Width        int  // Image width in pixels
	Height       int  // Image height in pixles
	HasAlpha     bool // True if data stream contains a alpha channel.
	HasAnimation bool // True if data stream is an animation
	Format       int  // Image compression format
}

// GetDecoderVersion returns decoder's version number, packed in hexadecimal.
// e.g; v0.4.2 is 0x000402
func GetDecoderVersion() (v int) {
	return int(C.WebPGetDecoderVersion())
}

// GetInfo retrives width/height from data bytes.
func GetInfo(data []byte) (width, height int) {
	var w, h C.int
	C.WebPGetInfo((*C.uint8_t)(&data[0]), (C.size_t)(len(data)), &w, &h)
	return int(w), int(h)
}

// GetFeatures returns features as BitstreamFeatures retrived from data stream.
func GetFeatures(data []byte) (f *BitstreamFeatures, err error) {
	var cf C.WebPBitstreamFeatures
	status := C.WebPGetFeatures((*C.uint8_t)(&data[0]), (C.size_t)(len(data)), &cf)

	if status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("WebPGetFeatures returns unexpected status: %s", statusString(status))
	}

	f = &BitstreamFeatures{
		Width:        int(cf.width), // TODO: use Rectangle instaed?
		Height:       int(cf.height),
		HasAlpha:     cf.has_alpha > 0,
		HasAnimation: cf.has_animation > 0,
		Format:       int(cf.format),
	}
	return
}

// DecodeYUVA decodes WebP image into YUV image with alpha channel, and returns
// it as *YUVAImage.
func DecodeYUVA(data []byte, options *DecoderOptions) (img *YUVAImage, err error) {
	config, err := initDecoderConfig(options)
	if err != nil {
		return nil, err
	}

	cDataPtr := (*C.uint8_t)(&data[0])
	cDataSize := (C.size_t)(len(data))

	// Retrive WebP features from data stream
	if status := C.WebPGetFeatures(cDataPtr, cDataSize, &config.input); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not get features from the data stream, return %s", statusString(status))
	}

	outWidth, outHeight := calcOutputSize(config)
	buf := (*C.WebPYUVABuffer)(unsafe.Pointer(&config.output.u[0]))

	// Set up output configurations
	colorSpace := YUV420
	config.output.colorspace = C.MODE_YUV
	if config.input.has_alpha > 0 {
		colorSpace = YUV420A
		config.output.colorspace = C.MODE_YUVA
	}
	config.output.is_external_memory = 1

	// Allocate image and fill into buffer
	img = NewYUVAImage(image.Rect(0, 0, outWidth, outHeight), colorSpace)
	buf.y = (*C.uint8_t)(&img.Y[0])
	buf.u = (*C.uint8_t)(&img.Cb[0])
	buf.v = (*C.uint8_t)(&img.Cr[0])
	buf.a = nil
	buf.y_stride = C.int(img.YStride)
	buf.u_stride = C.int(img.CStride)
	buf.v_stride = C.int(img.CStride)
	buf.a_stride = 0
	buf.y_size = C.size_t(len(img.Y))
	buf.u_size = C.size_t(len(img.Cb))
	buf.v_size = C.size_t(len(img.Cr))
	buf.a_size = 0

	if config.input.has_alpha > 0 {
		buf.a = (*C.uint8_t)(&img.A[0])
		buf.a_stride = C.int(img.AStride)
		buf.a_size = C.size_t(len(img.A))
	}

	if status := C.WebPDecode(cDataPtr, cDataSize, config); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not decode data stream, return %s", statusString(status))
	}

	return
}

// DecodeRGBA decodes WebP image into RGBA image and returns it as an *image.RGBA.
func DecodeRGBA(data []byte, options *DecoderOptions) (img *image.RGBA, err error) {
	config, err := initDecoderConfig(options)
	if err != nil {
		return nil, err
	}

	cDataPtr := (*C.uint8_t)(&data[0])
	cDataSize := (C.size_t)(len(data))

	// Retrive WebP features
	if status := C.WebPGetFeatures(cDataPtr, cDataSize, &config.input); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not get features from the data stream, return %s", statusString(status))
	}

	// Allocate output image
	outWidth, outHeight := calcOutputSize(config)
	img = image.NewRGBA(image.Rect(0, 0, outWidth, outHeight))

	// Set up output configurations
	config.output.colorspace = C.MODE_RGBA
	config.output.is_external_memory = 1

	// Allocate WebPRGBABuffer and fill in the pointers to output image
	buf := (*C.WebPRGBABuffer)(unsafe.Pointer(&config.output.u[0]))
	buf.rgba = (*C.uint8_t)(&img.Pix[0])
	buf.stride = C.int(img.Stride)
	buf.size = (C.size_t)(len(img.Pix))

	// Decode
	if status := C.WebPDecode(cDataPtr, cDataSize, config); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not decode data stream, return %s", statusString(status))
	}

	return
}

// sattusString convert the VP8StatsCode to string.
func statusString(status C.VP8StatusCode) string {
	switch status {
	case C.VP8_STATUS_OK:
		return "VP8_STATUS_OK"
	case C.VP8_STATUS_OUT_OF_MEMORY:
		return "VP8_STATUS_OUT_OF_MEMORY"
	case C.VP8_STATUS_INVALID_PARAM:
		return "VP8_STATUS_INVALID_PARAM"
	case C.VP8_STATUS_BITSTREAM_ERROR:
		return "VP8_STATUS_BITSTREAM_ERROR"
	case C.VP8_STATUS_UNSUPPORTED_FEATURE:
		return "VP8_STATUS_UNSUPPORTED_FEATURE"
	case C.VP8_STATUS_SUSPENDED:
		return "VP8_STATUS_SUSPENDED"
	case C.VP8_STATUS_USER_ABORT:
		return "VP8_STATUS_USER_ABORT"
	case C.VP8_STATUS_NOT_ENOUGH_DATA:
		return "VP8_STATUS_NOT_ENOUGH_DATA"
	}
	return "Unexpected Status Code"
}

// initDecoderConfing initializes a decoder configration and sets up the options.
func initDecoderConfig(options *DecoderOptions) (config *C.WebPDecoderConfig, err error) {
	// Initialize decoder config
	config = &C.WebPDecoderConfig{}
	if C.WebPInitDecoderConfig(config) == 0 {
		return nil, errors.New("Could not initialize decoder config")
	}

	// Set up decoder options
	if options.BypassFiltering {
		config.options.bypass_filtering = 1
	}
	if options.NoFancyUpsampling {
		config.options.no_fancy_upsampling = 1
	}
	if options.Crop.Max.X > 0 && options.Crop.Max.Y > 0 {
		config.options.use_cropping = 1
		config.options.crop_left = C.int(options.Crop.Min.X)
		config.options.crop_top = C.int(options.Crop.Min.Y)
		config.options.crop_width = C.int(options.Crop.Dx())
		config.options.crop_height = C.int(options.Crop.Dy())
	}
	if options.Scale.Max.X > 0 && options.Scale.Max.Y > 0 {
		config.options.use_scaling = 1
		config.options.scaled_width = C.int(options.Scale.Max.X)
		config.options.scaled_height = C.int(options.Scale.Max.Y)
	}
	if options.UseThreads {
		config.options.use_threads = 1
	}
	config.options.dithering_strength = C.int(options.DitheringStrength)

	return
}

// calcOutputSize retrives width and height of output image from the decoder configuration.
func calcOutputSize(config *C.WebPDecoderConfig) (width, height int) {
	options := config.options
	if options.use_scaling > 0 {
		width = int(config.options.scaled_width)
		height = int(config.options.scaled_height)
		return
	}
	if config.options.use_cropping > 0 {
		width = int(config.options.crop_width)
		height = int(config.options.crop_height)
		return
	}

	width = int(config.input.width)
	height = int(config.input.height)
	return
}
<commit_msg>Add DecodeNRGBA() to fix alpha pre-multiplication confusion<commit_after>package webp

/*
#include <stdlib.h>
#include <webp/decode.h>

static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer);

*/
import "C"

import (
	"errors"
	"fmt"
	"image"
	"unsafe"
)

// DecoderOptions specifies decoding options of WebP.
type DecoderOptions struct {
	BypassFiltering        bool            // If true, bypass filtering process
	NoFancyUpsampling      bool            // If true, do not fancy upsampling
	Crop                   image.Rectangle // Do cropping if image.Rectangle is not empty.
	Scale                  image.Rectangle // Do scaling if image.Rectangle is not empty.
	UseThreads             bool            // If true, use multi threads
	DitheringStrength      int             // Specify dithering strength [0=Off .. 100=full]
	Flip                   bool            // If true, flip output vertically
	AlphaDitheringStrength int             // Specify alpha dithering strength in [0..100]
}

// BitstreamFeatures represents the image properties which are retrived from
// data stream.
type BitstreamFeatures struct {
	Width        int  // Image width in pixels
	Height       int  // Image height in pixles
	HasAlpha     bool // True if data stream contains a alpha channel.
	HasAnimation bool // True if data stream is an animation
	Format       int  // Image compression format
}

// GetDecoderVersion returns decoder's version number, packed in hexadecimal.
// e.g; v0.4.2 is 0x000402
func GetDecoderVersion() (v int) {
	return int(C.WebPGetDecoderVersion())
}

// GetInfo retrives width/height from data bytes.
func GetInfo(data []byte) (width, height int) {
	var w, h C.int
	C.WebPGetInfo((*C.uint8_t)(&data[0]), (C.size_t)(len(data)), &w, &h)
	return int(w), int(h)
}

// GetFeatures returns features as BitstreamFeatures retrived from data stream.
func GetFeatures(data []byte) (f *BitstreamFeatures, err error) {
	var cf C.WebPBitstreamFeatures
	status := C.WebPGetFeatures((*C.uint8_t)(&data[0]), (C.size_t)(len(data)), &cf)

	if status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("WebPGetFeatures returns unexpected status: %s", statusString(status))
	}

	f = &BitstreamFeatures{
		Width:        int(cf.width), // TODO: use Rectangle instaed?
		Height:       int(cf.height),
		HasAlpha:     cf.has_alpha > 0,
		HasAnimation: cf.has_animation > 0,
		Format:       int(cf.format),
	}
	return
}

// DecodeYUVA decodes WebP image into YUV image with alpha channel, and returns
// it as *YUVAImage.
func DecodeYUVA(data []byte, options *DecoderOptions) (img *YUVAImage, err error) {
	config, err := initDecoderConfig(options)
	if err != nil {
		return nil, err
	}

	cDataPtr := (*C.uint8_t)(&data[0])
	cDataSize := (C.size_t)(len(data))

	// Retrive WebP features from data stream
	if status := C.WebPGetFeatures(cDataPtr, cDataSize, &config.input); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not get features from the data stream, return %s", statusString(status))
	}

	outWidth, outHeight := calcOutputSize(config)
	buf := (*C.WebPYUVABuffer)(unsafe.Pointer(&config.output.u[0]))

	// Set up output configurations
	colorSpace := YUV420
	config.output.colorspace = C.MODE_YUV
	if config.input.has_alpha > 0 {
		colorSpace = YUV420A
		config.output.colorspace = C.MODE_YUVA
	}
	config.output.is_external_memory = 1

	// Allocate image and fill into buffer
	img = NewYUVAImage(image.Rect(0, 0, outWidth, outHeight), colorSpace)
	buf.y = (*C.uint8_t)(&img.Y[0])
	buf.u = (*C.uint8_t)(&img.Cb[0])
	buf.v = (*C.uint8_t)(&img.Cr[0])
	buf.a = nil
	buf.y_stride = C.int(img.YStride)
	buf.u_stride = C.int(img.CStride)
	buf.v_stride = C.int(img.CStride)
	buf.a_stride = 0
	buf.y_size = C.size_t(len(img.Y))
	buf.u_size = C.size_t(len(img.Cb))
	buf.v_size = C.size_t(len(img.Cr))
	buf.a_size = 0

	if config.input.has_alpha > 0 {
		buf.a = (*C.uint8_t)(&img.A[0])
		buf.a_stride = C.int(img.AStride)
		buf.a_size = C.size_t(len(img.A))
	}

	if status := C.WebPDecode(cDataPtr, cDataSize, config); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not decode data stream, return %s", statusString(status))
	}

	return
}

// DecodeRGBA decodes WebP image into rgbA image and returns it as an *image.RGBA.
func DecodeRGBA(data []byte, options *DecoderOptions) (img *image.RGBA, err error) {
	config, err := initDecoderConfig(options)
	if err != nil {
		return nil, err
	}

	cDataPtr := (*C.uint8_t)(&data[0])
	cDataSize := (C.size_t)(len(data))

	// Retrive WebP features
	if status := C.WebPGetFeatures(cDataPtr, cDataSize, &config.input); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not get features from the data stream, return %s", statusString(status))
	}

	// Allocate output image
	outWidth, outHeight := calcOutputSize(config)
	img = image.NewRGBA(image.Rect(0, 0, outWidth, outHeight))

	// Set up output configurations
	config.output.colorspace = C.MODE_rgbA
	config.output.is_external_memory = 1

	// Allocate WebPRGBABuffer and fill in the pointers to output image
	buf := (*C.WebPRGBABuffer)(unsafe.Pointer(&config.output.u[0]))
	buf.rgba = (*C.uint8_t)(&img.Pix[0])
	buf.stride = C.int(img.Stride)
	buf.size = (C.size_t)(len(img.Pix))

	// Decode
	if status := C.WebPDecode(cDataPtr, cDataSize, config); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not decode data stream, return %s", statusString(status))
	}

	return
}

// DecodeNRGBA decodes WebP image into RGBA image and returns it as an *image.NRGBA.
func DecodeNRGBA(data []byte, options *DecoderOptions) (img *image.NRGBA, err error) {
	config, err := initDecoderConfig(options)
	if err != nil {
		return nil, err
	}

	cDataPtr := (*C.uint8_t)(&data[0])
	cDataSize := (C.size_t)(len(data))

	// Retrive WebP features
	if status := C.WebPGetFeatures(cDataPtr, cDataSize, &config.input); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not get features from the data stream, return %s", statusString(status))
	}

	// Allocate output image
	outWidth, outHeight := calcOutputSize(config)
	img = image.NewNRGBA(image.Rect(0, 0, outWidth, outHeight))

	// Set up output configurations
	config.output.colorspace = C.MODE_RGBA
	config.output.is_external_memory = 1

	// Allocate WebPRGBABuffer and fill in the pointers to output image
	buf := (*C.WebPRGBABuffer)(unsafe.Pointer(&config.output.u[0]))
	buf.rgba = (*C.uint8_t)(&img.Pix[0])
	buf.stride = C.int(img.Stride)
	buf.size = (C.size_t)(len(img.Pix))

	// Decode
	if status := C.WebPDecode(cDataPtr, cDataSize, config); status != C.VP8_STATUS_OK {
		return nil, fmt.Errorf("Could not decode data stream, return %s", statusString(status))
	}

	return
}

// sattusString convert the VP8StatsCode to string.
func statusString(status C.VP8StatusCode) string {
	switch status {
	case C.VP8_STATUS_OK:
		return "VP8_STATUS_OK"
	case C.VP8_STATUS_OUT_OF_MEMORY:
		return "VP8_STATUS_OUT_OF_MEMORY"
	case C.VP8_STATUS_INVALID_PARAM:
		return "VP8_STATUS_INVALID_PARAM"
	case C.VP8_STATUS_BITSTREAM_ERROR:
		return "VP8_STATUS_BITSTREAM_ERROR"
	case C.VP8_STATUS_UNSUPPORTED_FEATURE:
		return "VP8_STATUS_UNSUPPORTED_FEATURE"
	case C.VP8_STATUS_SUSPENDED:
		return "VP8_STATUS_SUSPENDED"
	case C.VP8_STATUS_USER_ABORT:
		return "VP8_STATUS_USER_ABORT"
	case C.VP8_STATUS_NOT_ENOUGH_DATA:
		return "VP8_STATUS_NOT_ENOUGH_DATA"
	}
	return "Unexpected Status Code"
}

// initDecoderConfing initializes a decoder configration and sets up the options.
func initDecoderConfig(options *DecoderOptions) (config *C.WebPDecoderConfig, err error) {
	// Initialize decoder config
	config = &C.WebPDecoderConfig{}
	if C.WebPInitDecoderConfig(config) == 0 {
		return nil, errors.New("Could not initialize decoder config")
	}

	// Set up decoder options
	if options.BypassFiltering {
		config.options.bypass_filtering = 1
	}
	if options.NoFancyUpsampling {
		config.options.no_fancy_upsampling = 1
	}
	if options.Crop.Max.X > 0 && options.Crop.Max.Y > 0 {
		config.options.use_cropping = 1
		config.options.crop_left = C.int(options.Crop.Min.X)
		config.options.crop_top = C.int(options.Crop.Min.Y)
		config.options.crop_width = C.int(options.Crop.Dx())
		config.options.crop_height = C.int(options.Crop.Dy())
	}
	if options.Scale.Max.X > 0 && options.Scale.Max.Y > 0 {
		config.options.use_scaling = 1
		config.options.scaled_width = C.int(options.Scale.Max.X)
		config.options.scaled_height = C.int(options.Scale.Max.Y)
	}
	if options.UseThreads {
		config.options.use_threads = 1
	}
	config.options.dithering_strength = C.int(options.DitheringStrength)

	return
}

// calcOutputSize retrives width and height of output image from the decoder configuration.
func calcOutputSize(config *C.WebPDecoderConfig) (width, height int) {
	options := config.options
	if options.use_scaling > 0 {
		width = int(config.options.scaled_width)
		height = int(config.options.scaled_height)
		return
	}
	if config.options.use_cropping > 0 {
		width = int(config.options.crop_width)
		height = int(config.options.crop_height)
		return
	}

	width = int(config.input.width)
	height = int(config.input.height)
	return
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, 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 bootkube

import (
	"github.com/coreos/pkg/capnslog"

	"github.com/coreos/mantle/kola/register"
)

var plog = capnslog.NewPackageLogger("github.com/coreos-inc/pluton", "tests/bootkube")

func init() {
	register.Register(&register.Test{
		Name:      "bootkube.smoke",
		Run:       bootkubeSmoke,
		Platforms: []string{"gce"},
	})

	register.Register(&register.Test{
		Name:      "bootkube.experimentaletcd.smoke",
		Run:       bootkubeSmokeEtcd,
		Platforms: []string{"gce"},
	})

	/* Temporarily Disabled: Must vet this again when 1.5.3 is out
	register.Register(&register.Test{
		Name:      "bootkube.etcd.scale",
		Run:       etcdScale,
		Platforms: []string{"gce"},
	})
	*/

	register.Register(&register.Test{
		Name:      "bootkube.destruct.reboot",
		Run:       rebootMaster,
		Platforms: []string{"gce"},
	})

	register.Register(&register.Test{
		Name:      "bootkube.destruct.delete",
		Run:       deleteAPIServer,
		Platforms: []string{"gce"},
	})

	register.Register(&register.Test{
		Name:      "conformance.bootkube",
		Run:       conformanceBootkube,
		Platforms: []string{"gce"},
	})
}
<commit_msg>tests/bootkube: self-hosted etcd gets its own prefix until stable again<commit_after>// Copyright 2017 CoreOS, 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 bootkube

import (
	"github.com/coreos/pkg/capnslog"

	"github.com/coreos/mantle/kola/register"
)

var plog = capnslog.NewPackageLogger("github.com/coreos-inc/pluton", "tests/bootkube")

func init() {
	register.Register(&register.Test{
		Name:      "bootkube.smoke",
		Run:       bootkubeSmoke,
		Platforms: []string{"gce"},
	})

	register.Register(&register.Test{
		Name:      "experimentaletcd.smoke",
		Run:       bootkubeSmokeEtcd,
		Platforms: []string{"gce"},
	})

	/* Temporarily Disabled: Must vet this again when 1.5.3 is out
	register.Register(&register.Test{
		Name:      "bootkube.etcd.scale",
		Run:       etcdScale,
		Platforms: []string{"gce"},
	})
	*/

	register.Register(&register.Test{
		Name:      "bootkube.destruct.reboot",
		Run:       rebootMaster,
		Platforms: []string{"gce"},
	})

	register.Register(&register.Test{
		Name:      "bootkube.destruct.delete",
		Run:       deleteAPIServer,
		Platforms: []string{"gce"},
	})

	register.Register(&register.Test{
		Name:      "conformance.bootkube",
		Run:       conformanceBootkube,
		Platforms: []string{"gce"},
	})
}
<|endoftext|>


<commit_before>package namespaces

import (
	"errors"
	"fmt"
	tw "github.com/olekukonko/tablewriter"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
)

type NSTYPE string

type Namespace struct {
	Type NSTYPE
	Id   string
}

type Process struct {
	Pid     string
	PPid    string
	Name    string
	State   string
	Threads string
	Cgroups string
	Uids    string
	Command string
}

// The supported namespaces
const (
	NS_MOUNT  NSTYPE = "mnt"    // CLONE_NEWNS, filesystem mount points
	NS_UTS    NSTYPE = "uts"    // CLONE_NEWUTS, nodename and NIS domain name
	NS_IPC    NSTYPE = "ipc"    // CLONE_NEWIPC, interprocess communication
	NS_PID    NSTYPE = "pid"    // CLONE_NEWPID, process ID number space isolation
	NS_NET    NSTYPE = "net"    // CLONE_NEWNET, network system resources
	NS_USER   NSTYPE = "user"   // CLONE_NEWUSER, user and group ID number space isolation
	NS_CGROUP NSTYPE = "cgroup" // CLONE_NEWCGROUP, cgroup root directory
)

var (
	DEBUG           bool
	NS              []NSTYPE
	namespaces      map[Namespace][]Process
	processes       map[string][]Namespace
	MAX_COMMAND_LEN int
)

func debug(m string) {
	if DEBUG {
		fmt.Printf("DEBUG: %s\n", m)
	}
}

func init() {
	// note: cgroups are not included in the following:
	NS = []NSTYPE{NS_MOUNT, NS_UTS, NS_IPC, NS_PID, NS_NET, NS_USER}
	// for all default operations and lookups:
	namespaces = make(map[Namespace][]Process)
	// for lookups only (PID -> namespaces):
	processes = make(map[string][]Namespace)
	MAX_COMMAND_LEN = 20
}

func contains(s int, slist []int) bool {
	for _, b := range slist {
		if b == s {
			return true
		}
	}
	return false
}

// resolve populates the specified namespace of a process.
// For example:
//  namespaces.resolve(NS_USER, "1234")
func resolve(nstype NSTYPE, pid string) (*Namespace, error) {
	debug("namespace type: " + string(nstype))
	nsfile := filepath.Join("/proc", pid, "ns", string(nstype))
	debug(nsfile)
	if content, err := os.Readlink(nsfile); err == nil {
		debug(content)
		// turn something like user:[4026531837] into 4026531837
		nsnum := strings.Split(content, ":")[1]
		nsnum = nsnum[1 : len(nsnum)-1]
		ns := Namespace{}
		ns.Type = nstype
		ns.Id = string(nsnum)
		return &ns, nil
	} else {
		return nil, err
	}
}

// status reads out process information from /proc/$PID/status.
// For example:
//  namespaces.status("1234")
func status(pid string) (*Process, error) {
	sfile := filepath.Join("/proc", pid, "status")
	debug("reading " + sfile)
	// try to read out data about process status:
	if s, err := ioutil.ReadFile(sfile); err == nil {
		p := Process{}
		lines := strings.Split(string(s), "\n")
		for _, l := range lines {
			debug("status field " + l)
			if l != "" {
				k := strings.Split(l, ":")[0]
				v := strings.TrimSpace(strings.Split(l, ":")[1])
				switch k {
				case "Pid":
					p.Pid = v
				case "PPid":
					p.PPid = v
				case "Name":
					p.Name = v
				case "State":
					p.State = v
				case "Threads":
					p.Threads = v
				case "Uid":
					// Uid:	1000	1000	1000	1000
					p.Uids = v
				}
			}
		}
		// now try to read out data about cgroups:
		cfile := filepath.Join("/proc", pid, "cgroup")
		if cg, cerr := ioutil.ReadFile(cfile); cerr == nil {
			p.Cgroups = string(cg)
		}
		// try to read out process' command:
		cmdfile := filepath.Join("/proc", pid, "cmdline")
		if cmd, cerr := ioutil.ReadFile(cmdfile); cerr == nil {
			p.Command = strings.TrimSpace(string(cmd))
		}
		return &p, nil
	} else {
		return nil, err
	}
}

func usage(cg string, pid string) (map[string]string, error) {
	base := "/sys/fs/cgroup/"
	for _, ns := range processes[pid] { // looking up namespaces of process
		debug("checking namespace " + ns.Id)
		for _, p := range namespaces[ns] { // checking to find process details
			debug("checking process " + p.Pid)
			if pid == p.Pid {
				cgroups := p.Cgroups
				lines := strings.Split(cgroups, "\n")
				for _, l := range lines {
					debug("line " + l)
					if l != "" {
						chierarchy := strings.Split(l, ":")[0]
						cname := strings.Split(l, ":")[1]
						cpath := strings.Split(l, ":")[2]
						if cg == chierarchy { // matches targeted cgroup
							cdir := filepath.Join(base, cname, cpath)
							cfiles, _ := ioutil.ReadDir(cdir)
							cmap := make(map[string]string)
							for _, f := range cfiles { // read out values per control file
								cfname := filepath.Join(cdir, f.Name())
								// note that in the following we're ignoring write-only files:
								if cvalue, err := ioutil.ReadFile(cfname); err == nil {
									cmap[f.Name()] = string(cvalue)
								}
							}
							return cmap, nil
						}
					}
				}
			}
		}
	}
	return nil, errors.New(fmt.Sprintf("No control files found for cgroup %s of process %s", cg, pid))
}

///////////////////////////////////////////////////////////////////////////////
// PUBLIC API
//

// Gather reads out process-related info from /proc and fills the global
// namespaces map with it. Note that only filenames that match the [0-9]* pattern
// are considered here since those are the ones representing processes, with
// the filename being the PID.
// For example:
//  namespaces.Gather()
func Gather() {
	if runtime.GOOS != "linux" {
		fmt.Println("Sorry, this is a Linux-specific tool.")
		os.Exit(1)
	}
	fn, _ := filepath.Glob("/proc/[0-9]*")
	for _, f := range fn { // each file representing a process
		_, pid := filepath.Split(f)
		debug("looking at process: " + pid)
		// establishing mappings:
		for _, tns := range NS {
			debug("for namespace: " + string(tns))
			if ns, e := resolve(tns, pid); e == nil {
				p, _ := status(pid)
				// (namespace -> list of processes) mapping:
				namespaces[*ns] = append(namespaces[*ns], *p)
				// (process -> list of namespaces) mapping:
				processes[pid] = append(processes[pid], *ns)
			} else {
				debug(fmt.Sprintf("%s of process %s", e, pid))
			}
		}
	}
}

// LookupCG displays details about a cgroup a process belongs to.
// Note that cgofp is expected to be in the format CGROUP_HIERARCHY:PID
// with allowed values for CGROUP_HIERARCHY being the cgroups v1 hierarchy
// values as found in /proc/groups - for more infos see also
// http://man7.org/linux/man-pages/man7/cgroups.7.html
// For example:
//  namespaces.LookupCG("2:1000")
func LookupCG(cgofp string) {
	rp := regexp.MustCompile("([0-9])+:([0-9])+")
	if rp.MatchString(cgofp) { // the provided argument matches the expected format
		cg := strings.Split(cgofp, ":")[0]
		pid := strings.Split(cgofp, ":")[1]
		debug(fmt.Sprintf("Looking up cgroup %s of process %s", cg, pid))
		if cm, err := usage(cg, pid); err == nil {
			ptable := tw.NewWriter(os.Stdout)
			ptable.SetHeader([]string{"CONTROLFILE", "VALUE"})
			ptable.SetCenterSeparator("")
			ptable.SetColumnSeparator("")
			ptable.SetRowSeparator("")
			ptable.SetAlignment(tw.ALIGN_LEFT)
			ptable.SetHeaderAlignment(tw.ALIGN_LEFT)
			debug("\n\n=== SUMMARY")
			debug(fmt.Sprintf("control files: %v", cm))
			for cf, v := range cm {
				row := []string{cf, v}
				ptable.Append(row)
			}
			ptable.Render()
		} else {
			fmt.Println(err)
		}
	} else {
		fmt.Println("Provided argument is not in expected format. It should be CGROUP_HIERARCHY:PID.")
		fmt.Println("For example: 2:1000 to list details of cgroup with hierarchy ID 2 the process with PID 1000 belongs to.")
	}
}

// LookupPID displays the namespaces a process is in.
// For example:
//  namespaces.LookupPID("1000")
func LookupPID(pid string) {
	ptable := tw.NewWriter(os.Stdout)
	ptable.SetHeader([]string{"NAMESPACE", "TYPE"})
	ptable.SetCenterSeparator("")
	ptable.SetColumnSeparator("")
	ptable.SetRowSeparator("")
	ptable.SetAlignment(tw.ALIGN_LEFT)
	ptable.SetHeaderAlignment(tw.ALIGN_LEFT)
	debug("\n\n=== SUMMARY")

	for _, ns := range processes[pid] {
		debug("for namespace " + ns.Id)
		row := []string{ns.Id, string(ns.Type)}
		ptable.Append(row)
	}
	ptable.Render()

}

// LookupNS displays details about a specific namespace.
// For example:
//  namespaces.LookupNS("4026532198")
func LookupNS(targetns string) {
	ptable := tw.NewWriter(os.Stdout)
	ptable.SetHeader([]string{"PID", "PPID", "NAME", "CMD", "NTHREADS", "CGROUPS", "STATE"})
	ptable.SetCenterSeparator("")
	ptable.SetColumnSeparator("")
	ptable.SetRowSeparator("")
	ptable.SetAlignment(tw.ALIGN_LEFT)
	ptable.SetHeaderAlignment(tw.ALIGN_LEFT)
	debug("\n\n=== SUMMARY")

	for _, tns := range NS {
		debug("for namespace " + string(tns))
		ns := Namespace{}
		ns.Type = tns
		ns.Id = targetns
		pl := namespaces[ns]
		for _, p := range pl {
			debug(fmt.Sprintf("looking in namespace %s at process %d\n", tns, p.Pid))
			// rendering process command line:
			cmd := p.Command
			if len(cmd) > MAX_COMMAND_LEN {
				cmd = cmd[:MAX_COMMAND_LEN]
			}
			row := []string{string(p.Pid), string(p.PPid), p.Name, cmd, string(p.Threads), p.Cgroups, p.State}
			ptable.Append(row)
		}
	}
	ptable.Render()
}

// Showall displays details about all active namespaces.
// For example:
//  namespaces.Showall()
func Showall() {
	ntable := tw.NewWriter(os.Stdout)
	ntable.SetHeader([]string{"NAMESPACE", "TYPE", "NPROCS", "USER", "CMD"})
	ntable.SetCenterSeparator("")
	ntable.SetColumnSeparator("")
	ntable.SetRowSeparator("")
	ntable.SetAlignment(tw.ALIGN_LEFT)
	ntable.SetHeaderAlignment(tw.ALIGN_LEFT)
	debug("\n\n=== SUMMARY")
	for n, pl := range namespaces {
		debug(fmt.Sprintf("namespace %s: %v\n", n.Id, pl))
		u := ""
		suids := make([]int, 0)
		for _, p := range pl {
			// using the effective UID here (which is the 2nd in the list):
			uid, _ := strconv.Atoi(strings.Fields(p.Uids)[1])
			if !contains(uid, suids) {
				suids = append(suids, int(uid))
			}
		}
		sort.Ints(suids)
		for _, uid := range suids {
			u += fmt.Sprintf("%d,", uid)
		}
		if strings.HasSuffix(u, ",") {
			u = u[0 : len(u)-1]
		}
		// rendering process command line:
		cmd := pl[0].Command
		if len(cmd) > MAX_COMMAND_LEN {
			cmd = cmd[:MAX_COMMAND_LEN]
		}
		// assembling one row (one namespace rendering)
		row := []string{string(n.Id), string(n.Type), strconv.Itoa(len(pl)), u, cmd}
		ntable.Append(row)
	}
	ntable.Render()
}
<commit_msg>updates inline docs<commit_after>package namespaces

import (
	"errors"
	"fmt"
	tw "github.com/olekukonko/tablewriter"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
)

type NSTYPE string

type Namespace struct {
	Type NSTYPE
	Id   string
}

type Process struct {
	Pid     string
	PPid    string
	Name    string
	State   string
	Threads string
	Cgroups string
	Uids    string
	Command string
}

// The supported namespaces
const (
	NS_MOUNT  NSTYPE = "mnt"    // CLONE_NEWNS, filesystem mount points
	NS_UTS    NSTYPE = "uts"    // CLONE_NEWUTS, nodename and NIS domain name
	NS_IPC    NSTYPE = "ipc"    // CLONE_NEWIPC, interprocess communication
	NS_PID    NSTYPE = "pid"    // CLONE_NEWPID, process ID number space isolation
	NS_NET    NSTYPE = "net"    // CLONE_NEWNET, network system resources
	NS_USER   NSTYPE = "user"   // CLONE_NEWUSER, user and group ID number space isolation
	NS_CGROUP NSTYPE = "cgroup" // CLONE_NEWCGROUP, cgroup root directory
)

var (
	DEBUG           bool
	NS              []NSTYPE
	namespaces      map[Namespace][]Process
	processes       map[string][]Namespace
	MAX_COMMAND_LEN int
)

func debug(m string) {
	if DEBUG {
		fmt.Printf("DEBUG: %s\n", m)
	}
}

func init() {
	// note: cgroups are not included in the following:
	NS = []NSTYPE{NS_MOUNT, NS_UTS, NS_IPC, NS_PID, NS_NET, NS_USER}
	// for all default operations and lookups:
	namespaces = make(map[Namespace][]Process)
	// for lookups only (PID -> namespaces):
	processes = make(map[string][]Namespace)
	MAX_COMMAND_LEN = 20
}

func contains(s int, slist []int) bool {
	for _, b := range slist {
		if b == s {
			return true
		}
	}
	return false
}

// resolve populates the specified namespace of a process.
// For example:
//  namespaces.resolve(NS_USER, "1234")
func resolve(nstype NSTYPE, pid string) (*Namespace, error) {
	debug("namespace type: " + string(nstype))
	nsfile := filepath.Join("/proc", pid, "ns", string(nstype))
	debug(nsfile)
	if content, err := os.Readlink(nsfile); err == nil {
		debug(content)
		// turn something like user:[4026531837] into 4026531837
		nsnum := strings.Split(content, ":")[1]
		nsnum = nsnum[1 : len(nsnum)-1]
		ns := Namespace{}
		ns.Type = nstype
		ns.Id = string(nsnum)
		return &ns, nil
	} else {
		return nil, err
	}
}

// status reads out process information from /proc/$PID/status.
// For example:
//  namespaces.status("1234")
func status(pid string) (*Process, error) {
	sfile := filepath.Join("/proc", pid, "status")
	debug("reading " + sfile)
	// try to read out data about process status:
	if s, err := ioutil.ReadFile(sfile); err == nil {
		p := Process{}
		lines := strings.Split(string(s), "\n")
		for _, l := range lines {
			debug("status field " + l)
			if l != "" {
				k := strings.Split(l, ":")[0]
				v := strings.TrimSpace(strings.Split(l, ":")[1])
				switch k {
				case "Pid":
					p.Pid = v
				case "PPid":
					p.PPid = v
				case "Name":
					p.Name = v
				case "State":
					p.State = v
				case "Threads":
					p.Threads = v
				case "Uid":
					// Uid:	1000	1000	1000	1000
					p.Uids = v
				}
			}
		}
		// now try to read out data about cgroups:
		cfile := filepath.Join("/proc", pid, "cgroup")
		if cg, cerr := ioutil.ReadFile(cfile); cerr == nil {
			p.Cgroups = string(cg)
		}
		// try to read out process' command:
		cmdfile := filepath.Join("/proc", pid, "cmdline")
		if cmd, cerr := ioutil.ReadFile(cmdfile); cerr == nil {
			p.Command = strings.TrimSpace(string(cmd))
		}
		return &p, nil
	} else {
		return nil, err
	}
}

// usage reads out values of control files under /sys/fs/cgroup/
// given a process pid and a cgroup hierarchy ID cg.
// For example:
//  namespaces.usage("5", "1234")
func usage(cg string, pid string) (map[string]string, error) {
	base := "/sys/fs/cgroup/"
	for _, ns := range processes[pid] { // looking up namespaces of process
		debug("checking namespace " + ns.Id)
		for _, p := range namespaces[ns] { // checking to find process details
			debug("checking process " + p.Pid)
			if pid == p.Pid {
				cgroups := p.Cgroups
				lines := strings.Split(cgroups, "\n")
				for _, l := range lines {
					debug("line " + l)
					if l != "" {
						chierarchy := strings.Split(l, ":")[0]
						cname := strings.Split(l, ":")[1]
						cpath := strings.Split(l, ":")[2]
						if cg == chierarchy { // matches targeted cgroup
							cdir := filepath.Join(base, cname, cpath)
							cfiles, _ := ioutil.ReadDir(cdir)
							cmap := make(map[string]string)
							for _, f := range cfiles { // read out values per control file
								cfname := filepath.Join(cdir, f.Name())
								// note that in the following we're ignoring write-only files:
								if cvalue, err := ioutil.ReadFile(cfname); err == nil {
									cmap[f.Name()] = string(cvalue)
								}
							}
							return cmap, nil
						}
					}
				}
			}
		}
	}
	return nil, errors.New(fmt.Sprintf("No control files found for cgroup %s of process %s", cg, pid))
}

///////////////////////////////////////////////////////////////////////////////
// PUBLIC API
//

// Gather reads out process-related info from /proc and fills the global
// namespaces map with it. Note that only filenames that match the [0-9]* pattern
// are considered here since those are the ones representing processes, with
// the filename being the PID.
// For example:
//  namespaces.Gather()
func Gather() {
	if runtime.GOOS != "linux" {
		fmt.Println("Sorry, this is a Linux-specific tool.")
		os.Exit(1)
	}
	fn, _ := filepath.Glob("/proc/[0-9]*")
	for _, f := range fn { // each file representing a process
		_, pid := filepath.Split(f)
		debug("looking at process: " + pid)
		// establishing mappings:
		for _, tns := range NS {
			debug("for namespace: " + string(tns))
			if ns, e := resolve(tns, pid); e == nil {
				p, _ := status(pid)
				// (namespace -> list of processes) mapping:
				namespaces[*ns] = append(namespaces[*ns], *p)
				// (process -> list of namespaces) mapping:
				processes[pid] = append(processes[pid], *ns)
			} else {
				debug(fmt.Sprintf("%s of process %s", e, pid))
			}
		}
	}
}

// LookupCG displays details about a cgroup a process belongs to.
// Note that cgofp is expected to be in the format CGROUP_HIERARCHY:PID
// with allowed values for CGROUP_HIERARCHY being the cgroups v1 hierarchy
// values as found in /proc/groups - for more infos see also
// http://man7.org/linux/man-pages/man7/cgroups.7.html
// For example:
//  namespaces.LookupCG("2:1000")
func LookupCG(cgofp string) {
	rp := regexp.MustCompile("([0-9])+:([0-9])+")
	if rp.MatchString(cgofp) { // the provided argument matches the expected format
		cg := strings.Split(cgofp, ":")[0]
		pid := strings.Split(cgofp, ":")[1]
		debug(fmt.Sprintf("Looking up cgroup %s of process %s", cg, pid))
		if cm, err := usage(cg, pid); err == nil {
			ptable := tw.NewWriter(os.Stdout)
			ptable.SetHeader([]string{"CONTROLFILE", "VALUE"})
			ptable.SetCenterSeparator("")
			ptable.SetColumnSeparator("")
			ptable.SetRowSeparator("")
			ptable.SetAlignment(tw.ALIGN_LEFT)
			ptable.SetHeaderAlignment(tw.ALIGN_LEFT)
			debug("\n\n=== SUMMARY")
			debug(fmt.Sprintf("control files: %v", cm))
			for cf, v := range cm {
				row := []string{cf, v}
				ptable.Append(row)
			}
			ptable.Render()
		} else {
			fmt.Println(err)
		}
	} else {
		fmt.Println("Provided argument is not in expected format. It should be CGROUP_HIERARCHY:PID.")
		fmt.Println("For example: 2:1000 to list details of cgroup with hierarchy ID 2 the process with PID 1000 belongs to.")
	}
}

// LookupPID displays the namespaces a process is in.
// For example:
//  namespaces.LookupPID("1000")
func LookupPID(pid string) {
	ptable := tw.NewWriter(os.Stdout)
	ptable.SetHeader([]string{"NAMESPACE", "TYPE"})
	ptable.SetCenterSeparator("")
	ptable.SetColumnSeparator("")
	ptable.SetRowSeparator("")
	ptable.SetAlignment(tw.ALIGN_LEFT)
	ptable.SetHeaderAlignment(tw.ALIGN_LEFT)
	debug("\n\n=== SUMMARY")

	for _, ns := range processes[pid] {
		debug("for namespace " + ns.Id)
		row := []string{ns.Id, string(ns.Type)}
		ptable.Append(row)
	}
	ptable.Render()

}

// LookupNS displays details about a specific namespace.
// For example:
//  namespaces.LookupNS("4026532198")
func LookupNS(targetns string) {
	ptable := tw.NewWriter(os.Stdout)
	ptable.SetHeader([]string{"PID", "PPID", "NAME", "CMD", "NTHREADS", "CGROUPS", "STATE"})
	ptable.SetCenterSeparator("")
	ptable.SetColumnSeparator("")
	ptable.SetRowSeparator("")
	ptable.SetAlignment(tw.ALIGN_LEFT)
	ptable.SetHeaderAlignment(tw.ALIGN_LEFT)
	debug("\n\n=== SUMMARY")

	for _, tns := range NS {
		debug("for namespace " + string(tns))
		ns := Namespace{}
		ns.Type = tns
		ns.Id = targetns
		pl := namespaces[ns]
		for _, p := range pl {
			debug(fmt.Sprintf("looking in namespace %s at process %d\n", tns, p.Pid))
			// rendering process command line:
			cmd := p.Command
			if len(cmd) > MAX_COMMAND_LEN {
				cmd = cmd[:MAX_COMMAND_LEN]
			}
			row := []string{string(p.Pid), string(p.PPid), p.Name, cmd, string(p.Threads), p.Cgroups, p.State}
			ptable.Append(row)
		}
	}
	ptable.Render()
}

// Showall displays details about all active namespaces.
// For example:
//  namespaces.Showall()
func Showall() {
	ntable := tw.NewWriter(os.Stdout)
	ntable.SetHeader([]string{"NAMESPACE", "TYPE", "NPROCS", "USER", "CMD"})
	ntable.SetCenterSeparator("")
	ntable.SetColumnSeparator("")
	ntable.SetRowSeparator("")
	ntable.SetAlignment(tw.ALIGN_LEFT)
	ntable.SetHeaderAlignment(tw.ALIGN_LEFT)
	debug("\n\n=== SUMMARY")
	for n, pl := range namespaces {
		debug(fmt.Sprintf("namespace %s: %v\n", n.Id, pl))
		u := ""
		suids := make([]int, 0)
		for _, p := range pl {
			// using the effective UID here (which is the 2nd in the list):
			uid, _ := strconv.Atoi(strings.Fields(p.Uids)[1])
			if !contains(uid, suids) {
				suids = append(suids, int(uid))
			}
		}
		sort.Ints(suids)
		for _, uid := range suids {
			u += fmt.Sprintf("%d,", uid)
		}
		if strings.HasSuffix(u, ",") {
			u = u[0 : len(u)-1]
		}
		// rendering process command line:
		cmd := pl[0].Command
		if len(cmd) > MAX_COMMAND_LEN {
			cmd = cmd[:MAX_COMMAND_LEN]
		}
		// assembling one row (one namespace rendering)
		row := []string{string(n.Id), string(n.Type), strconv.Itoa(len(pl)), u, cmd}
		ntable.Append(row)
	}
	ntable.Render()
}
<|endoftext|>


<commit_before>package nameserver

import (
	"fmt"
	"log"
	"net"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/miekg/dns"
	. "github.com/weaveworks/weave/common"
	"github.com/weaveworks/weave/common/docker"
)

func httpErrorAndLog(level *log.Logger, w http.ResponseWriter, msg string,
	status int, logmsg string, logargs ...interface{}) {
	http.Error(w, msg, status)
	level.Printf("[http] "+logmsg, logargs...)
}

func extractFQDN(r *http.Request) (string, string) {
	if fqdnStr := r.FormValue("fqdn"); fqdnStr != "" {
		return fqdnStr, fqdnStr
	}
	return "*", ""
}

func ServeHTTP(listener net.Listener, version string, server *DNSServer, dockerCli *docker.Client) {

	muxRouter := mux.NewRouter()

	muxRouter.Methods("GET").Path("/status").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "weave DNS", version)
		fmt.Fprintln(w, server.Status())
		fmt.Fprintln(w, server.Zone.Status())
	})

	muxRouter.Methods("PUT").Path("/name/{id:.+}/{ip:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		reqError := func(msg string, logmsg string, logargs ...interface{}) {
			httpErrorAndLog(Warning, w, msg, http.StatusBadRequest, logmsg, logargs...)
		}

		vars := mux.Vars(r)
		idStr := vars["id"]
		ipStr := vars["ip"]
		name := r.FormValue("fqdn")

		if name == "" {
			reqError("Invalid FQDN", "Invalid FQDN in request: %s, %s", r.URL, r.Form)
			return
		}

		ip := net.ParseIP(ipStr)
		if ip == nil {
			reqError("Invalid IP", "Invalid IP in request: %s", ipStr)
			return
		}

		domain := server.Zone.Domain()
		if dns.IsSubDomain(domain, name) {
			Info.Printf("[http] Adding %s -> %s", name, ipStr)
			if err := server.Zone.AddRecord(idStr, name, ip); err != nil {
				if _, ok := err.(DuplicateError); !ok {
					httpErrorAndLog(
						Error, w, "Internal error", http.StatusInternalServerError,
						"Unexpected error from DB: %s", err)
					return
				} // oh, I already know this. whatever.
			}

			if dockerCli != nil {
				if !docker.IsContainerID(idStr) {
					Debug.Printf("[http] '%s' does not seem a container id", idStr)
					return
				}

				if running, err := dockerCli.IsContainerRunning(idStr); err != nil {
					Error.Printf("[http] Could not check container status: %s", err)
				} else if !running {
					Info.Printf("[http] '%s' is not running: removing", idStr)
					server.Zone.DeleteRecords(idStr, name, ip)
				}
			}
		} else {
			Info.Printf("[http] Ignoring name %s, not in %s", name, domain)
		}
	})

	muxRouter.Methods("DELETE").Path("/name/{id:.+}/{ip:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		idStr := vars["id"]
		ipStr := vars["ip"]

		ip := net.ParseIP(ipStr)
		if ip == nil {
			httpErrorAndLog(
				Warning, w, "Invalid IP in request", http.StatusBadRequest,
				"Invalid IP in request: %s", ipStr)
			return
		}

		fqdnStr, fqdn := extractFQDN(r)

		Info.Printf("[http] Deleting ID %s, IP %s, FQDN %s", idStr, ipStr, fqdnStr)
		server.Zone.DeleteRecords(idStr, fqdn, ip)
	})

	muxRouter.Methods("DELETE").Path("/name/{id:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		idStr := vars["id"]

		fqdnStr, fqdn := extractFQDN(r)

		Info.Printf("[http] Deleting ID %s, IP *, FQDN %s", idStr, fqdnStr)
		server.Zone.DeleteRecords(idStr, fqdn, net.IP{})
	})

	muxRouter.Methods("DELETE").Path("/name").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fqdnStr, fqdn := extractFQDN(r)

		Info.Printf("[http] Deleting ID *, IP *, FQDN %s", fqdnStr)
		server.Zone.DeleteRecords("", fqdn, net.IP{})
	})

	http.Handle("/", muxRouter)

	if err := http.Serve(listener, nil); err != nil {
		Error.Fatal("[http] Unable to serve http: ", err)
	}
}
<commit_msg>remove one level of indentation<commit_after>package nameserver

import (
	"fmt"
	"log"
	"net"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/miekg/dns"
	. "github.com/weaveworks/weave/common"
	"github.com/weaveworks/weave/common/docker"
)

func httpErrorAndLog(level *log.Logger, w http.ResponseWriter, msg string,
	status int, logmsg string, logargs ...interface{}) {
	http.Error(w, msg, status)
	level.Printf("[http] "+logmsg, logargs...)
}

func extractFQDN(r *http.Request) (string, string) {
	if fqdnStr := r.FormValue("fqdn"); fqdnStr != "" {
		return fqdnStr, fqdnStr
	}
	return "*", ""
}

func ServeHTTP(listener net.Listener, version string, server *DNSServer, dockerCli *docker.Client) {

	muxRouter := mux.NewRouter()

	muxRouter.Methods("GET").Path("/status").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "weave DNS", version)
		fmt.Fprintln(w, server.Status())
		fmt.Fprintln(w, server.Zone.Status())
	})

	muxRouter.Methods("PUT").Path("/name/{id:.+}/{ip:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		reqError := func(msg string, logmsg string, logargs ...interface{}) {
			httpErrorAndLog(Warning, w, msg, http.StatusBadRequest, logmsg, logargs...)
		}

		vars := mux.Vars(r)
		idStr := vars["id"]
		ipStr := vars["ip"]
		name := r.FormValue("fqdn")

		if name == "" {
			reqError("Invalid FQDN", "Invalid FQDN in request: %s, %s", r.URL, r.Form)
			return
		}

		ip := net.ParseIP(ipStr)
		if ip == nil {
			reqError("Invalid IP", "Invalid IP in request: %s", ipStr)
			return
		}

		domain := server.Zone.Domain()
		if !dns.IsSubDomain(domain, name) {
			Info.Printf("[http] Ignoring name %s, not in %s", name, domain)
			return
		}
		Info.Printf("[http] Adding %s -> %s", name, ipStr)
		if err := server.Zone.AddRecord(idStr, name, ip); err != nil {
			if _, ok := err.(DuplicateError); !ok {
				httpErrorAndLog(
					Error, w, "Internal error", http.StatusInternalServerError,
					"Unexpected error from DB: %s", err)
				return
			} // oh, I already know this. whatever.
		}

		if dockerCli != nil {
			if !docker.IsContainerID(idStr) {
				Debug.Printf("[http] '%s' does not seem to be a container id", idStr)
				return
			}

			if running, err := dockerCli.IsContainerRunning(idStr); err != nil {
				Error.Printf("[http] Could not check container status: %s", err)
			} else if !running {
				Info.Printf("[http] '%s' is not running: removing", idStr)
				server.Zone.DeleteRecords(idStr, name, ip)
			}
		}
	})

	muxRouter.Methods("DELETE").Path("/name/{id:.+}/{ip:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		idStr := vars["id"]
		ipStr := vars["ip"]

		ip := net.ParseIP(ipStr)
		if ip == nil {
			httpErrorAndLog(
				Warning, w, "Invalid IP in request", http.StatusBadRequest,
				"Invalid IP in request: %s", ipStr)
			return
		}

		fqdnStr, fqdn := extractFQDN(r)

		Info.Printf("[http] Deleting ID %s, IP %s, FQDN %s", idStr, ipStr, fqdnStr)
		server.Zone.DeleteRecords(idStr, fqdn, ip)
	})

	muxRouter.Methods("DELETE").Path("/name/{id:.+}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		idStr := vars["id"]

		fqdnStr, fqdn := extractFQDN(r)

		Info.Printf("[http] Deleting ID %s, IP *, FQDN %s", idStr, fqdnStr)
		server.Zone.DeleteRecords(idStr, fqdn, net.IP{})
	})

	muxRouter.Methods("DELETE").Path("/name").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fqdnStr, fqdn := extractFQDN(r)

		Info.Printf("[http] Deleting ID *, IP *, FQDN %s", fqdnStr)
		server.Zone.DeleteRecords("", fqdn, net.IP{})
	})

	http.Handle("/", muxRouter)

	if err := http.Serve(listener, nil); err != nil {
		Error.Fatal("[http] Unable to serve http: ", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/oauth2"

	"github.com/google/go-github/github"
	"github.com/howeyc/gopass"
)

var (
	client   *github.Client
	gistFile = filepath.Join(os.Getenv("HOME"), ".gist")
)

func init() {
	dt, err := ioutil.ReadFile(gistFile)
	if err != nil {
		log.Printf("*WARNING*: `%v`, you are Anonymous!", err)
		client = github.NewClient(nil)
	} else {
		ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: string(dt)})
		tc := oauth2.NewClient(oauth2.NoContext, ts)
		client = github.NewClient(tc)
	}
}

// Gist stands for gist related ops.
type Gist struct {
	*github.Client
}

// Create makes a gist.
func (g *Gist) Create(description string, anonymous, public bool, files ...string) (err error) {
	fs := make(map[github.GistFilename]github.GistFile, len(files))
	for _, v := range files {
		dat, err := ioutil.ReadFile(v)
		if err != nil {
			return err
		}
		c := string(dat)
		fs[github.GistFilename(v)] = github.GistFile{Filename: &v, Content: &c}
	}
	g0 := &github.Gist{Files: fs, Public: &public, Description: &description}
	if anonymous {
		*g.Client = *github.NewClient(nil)
	}
	g0, _, err = g.Gists.Create(g0)
	if err == nil {
		fmt.Println(*g0.HTMLURL)
	}
	return
}

// List gets user's gists.
func (g *Gist) List(public bool) (err error) {
	opt := &github.GistListOptions{
		ListOptions: github.ListOptions{
			PerPage: 20,
		},
	}
	for {
		gs, resp, err := g.Gists.List("", opt)
		if err != nil {
			return err
		}
		for _, i := range gs {
			if public && *i.Public {
				continue
			}
			for fn := range i.Files {
				fmt.Printf("%-64s%s\n", *i.HTMLURL, fn)
			}
		}
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}
	return
}

// Get querys a single gist detail.
func (g *Gist) Get(id string) (err error) {
	g0, _, err := g.Gists.Get(id)
	if err != nil {
		return
	}
	fmt.Println(strings.Repeat("-", 100))
	for _, f := range g0.Files {
		fmt.Printf("%v\t%v\n\n%v\n", *f.Filename, *f.Size, *f.Content)
		fmt.Println(strings.Repeat("-", 100))
	}
	return
}

// Delete deletes gaven gists by ids.
func (g *Gist) Delete(id ...string) error {
	c := make(chan error, len(id))
	for _, i := range id {
		go func(id string) {
			_, err := g.Gists.Delete(id)
			if err == nil {
				fmt.Printf("<id: %s> has been deleted ...\n", id)
			}
			c <- err
		}(i)
	}
	for i := 0; i < len(id); i++ {
		if err := <-c; err != nil {
			fmt.Println(err)
		}
	}
	return nil
}

// Token is a GitHub token entry.
type Token struct {
	ID  int    `json:"id"`
	URL string `json:"url"`
	App struct {
		Name     string `json:"name"`
		URL      string `json:"url"`
		ClientID string `json:"client_id"`
	} `json:"app"`
	Token          string      `json:"token"`
	HashedToken    string      `json:"hashed_token"`
	TokenLastEight string      `json:"token_last_eight"`
	Note           string      `json:"note"`
	NoteURL        interface{} `json:"note_url"`
	CreatedAt      time.Time   `json:"created_at"`
	UpdatedAt      time.Time   `json:"updated_at"`
	Scopes         []string    `json:"scopes"`
	Fingerprint    interface{} `json:"fingerprint"`
}

func ask() (user, pass string) {
	fmt.Print("GitHub username: ")
	if _, err := fmt.Scan(&user); err != nil {
		return
	}
	fmt.Print("GitHub password: ")
	p, err := gopass.GetPasswd()
	if err != nil {
		return
	}
	pass = string(p)
	return

}
func token(user, pass string) (err error) {
	fp := time.Now().Nanosecond()
	note := fmt.Sprintf(`{"note": "gist","scopes":["gist"],"fingerprint":"%v"}`, fp)
	url := "https://api.github.com/authorizations"
	req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(note)))
	if err != nil {
		return
	}

	req.SetBasicAuth(user, pass)
	req.Header.Set("Content-Type", "application/json")

	client := http.Client{Timeout: 10 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return
	}

	if resp.StatusCode == http.StatusUnauthorized {
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	var t Token
	err = json.Unmarshal(body, &t)
	if err != nil {
		return
	}

	return ioutil.WriteFile(gistFile, []byte(t.Token), 0644)
}
<commit_msg>Echo asterisks when password entered<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/oauth2"

	"github.com/google/go-github/github"
	"github.com/howeyc/gopass"
)

var (
	client   *github.Client
	gistFile = filepath.Join(os.Getenv("HOME"), ".gist")
)

func init() {
	dt, err := ioutil.ReadFile(gistFile)
	if err != nil {
		log.Printf("*WARNING*: `%v`, you are Anonymous!", err)
		client = github.NewClient(nil)
	} else {
		ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: string(dt)})
		tc := oauth2.NewClient(oauth2.NoContext, ts)
		client = github.NewClient(tc)
	}
}

// Gist stands for gist related ops.
type Gist struct {
	*github.Client
}

// Create makes a gist.
func (g *Gist) Create(description string, anonymous, public bool, files ...string) (err error) {
	fs := make(map[github.GistFilename]github.GistFile, len(files))
	for _, v := range files {
		dat, err := ioutil.ReadFile(v)
		if err != nil {
			return err
		}
		c := string(dat)
		fs[github.GistFilename(v)] = github.GistFile{Filename: &v, Content: &c}
	}
	g0 := &github.Gist{Files: fs, Public: &public, Description: &description}
	if anonymous {
		*g.Client = *github.NewClient(nil)
	}
	g0, _, err = g.Gists.Create(g0)
	if err == nil {
		fmt.Println(*g0.HTMLURL)
	}
	return
}

// List gets user's gists.
func (g *Gist) List(public bool) (err error) {
	opt := &github.GistListOptions{
		ListOptions: github.ListOptions{
			PerPage: 20,
		},
	}
	for {
		gs, resp, err := g.Gists.List("", opt)
		if err != nil {
			return err
		}
		for _, i := range gs {
			if public && *i.Public {
				continue
			}
			for fn := range i.Files {
				fmt.Printf("%-64s%s\n", *i.HTMLURL, fn)
			}
		}
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}
	return
}

// Get querys a single gist detail.
func (g *Gist) Get(id string) (err error) {
	g0, _, err := g.Gists.Get(id)
	if err != nil {
		return
	}
	fmt.Println(strings.Repeat("-", 100))
	for _, f := range g0.Files {
		fmt.Printf("%v\t%v\n\n%v\n", *f.Filename, *f.Size, *f.Content)
		fmt.Println(strings.Repeat("-", 100))
	}
	return
}

// Delete deletes gaven gists by ids.
func (g *Gist) Delete(id ...string) error {
	c := make(chan error, len(id))
	for _, i := range id {
		go func(id string) {
			_, err := g.Gists.Delete(id)
			if err == nil {
				fmt.Printf("<id: %s> has been deleted ...\n", id)
			}
			c <- err
		}(i)
	}
	for i := 0; i < len(id); i++ {
		if err := <-c; err != nil {
			fmt.Println(err)
		}
	}
	return nil
}

// Token is a GitHub token entry.
type Token struct {
	ID  int    `json:"id"`
	URL string `json:"url"`
	App struct {
		Name     string `json:"name"`
		URL      string `json:"url"`
		ClientID string `json:"client_id"`
	} `json:"app"`
	Token          string      `json:"token"`
	HashedToken    string      `json:"hashed_token"`
	TokenLastEight string      `json:"token_last_eight"`
	Note           string      `json:"note"`
	NoteURL        interface{} `json:"note_url"`
	CreatedAt      time.Time   `json:"created_at"`
	UpdatedAt      time.Time   `json:"updated_at"`
	Scopes         []string    `json:"scopes"`
	Fingerprint    interface{} `json:"fingerprint"`
}

func ask() (user, pass string) {
	fmt.Print("GitHub username: ")
	if _, err := fmt.Scan(&user); err != nil {
		return
	}
	fmt.Print("GitHub password: ")
	p, err := gopass.GetPasswdMasked()
	if err != nil {
		return
	}
	pass = string(p)
	return

}
func token(user, pass string) (err error) {
	fp := time.Now().Nanosecond()
	note := fmt.Sprintf(`{"note": "gist","scopes":["gist"],"fingerprint":"%v"}`, fp)
	url := "https://api.github.com/authorizations"
	req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(note)))
	if err != nil {
		return
	}

	req.SetBasicAuth(user, pass)
	req.Header.Set("Content-Type", "application/json")

	client := http.Client{Timeout: 10 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return
	}

	if resp.StatusCode == http.StatusUnauthorized {
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	var t Token
	err = json.Unmarshal(body, &t)
	if err != nil {
		return
	}

	return ioutil.WriteFile(gistFile, []byte(t.Token), 0644)
}
<|endoftext|>


<commit_before>package namesys

import (
	"fmt"
	"time"

	lru "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/golang-lru"
	mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
	proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
	"gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"

	key "github.com/ipfs/go-ipfs/blocks/key"
	pb "github.com/ipfs/go-ipfs/namesys/pb"
	path "github.com/ipfs/go-ipfs/path"
	routing "github.com/ipfs/go-ipfs/routing"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
	logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
	ci "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/crypto"
)

var log = logging.Logger("namesys")

// routingResolver implements NSResolver for the main IPFS SFS-like naming
type routingResolver struct {
	routing routing.IpfsRouting

	cache *lru.Cache
}

func (r *routingResolver) cacheGet(name string) (path.Path, bool) {
	if r.cache == nil {
		return "", false
	}

	ientry, ok := r.cache.Get(name)
	if !ok {
		return "", false
	}

	entry, ok := ientry.(cacheEntry)
	if !ok {
		// should never happen, purely for sanity
		log.Panicf("unexpected type %T in cache for %q.", ientry, name)
	}

	if time.Now().Before(entry.eol) {
		return entry.val, true
	}

	r.cache.Remove(name)

	return "", false
}

func (r *routingResolver) cacheSet(name string, val path.Path, rec *pb.IpnsEntry) {
	if r.cache == nil {
		return
	}

	// if completely unspecified, just use one minute
	ttl := DefaultResolverCacheTTL
	if rec.Ttl != nil {
		recttl := time.Duration(rec.GetTtl())
		if recttl >= 0 {
			ttl = recttl
		}
	}

	cacheTil := time.Now().Add(ttl)
	eol, ok := checkEOL(rec)
	if ok && eol.Before(cacheTil) {
		cacheTil = eol
	}

	r.cache.Add(name, cacheEntry{
		val: val,
		eol: cacheTil,
	})
}

type cacheEntry struct {
	val path.Path
	eol time.Time
}

// NewRoutingResolver constructs a name resolver using the IPFS Routing system
// to implement SFS-like naming on top.
// cachesize is the limit of the number of entries in the lru cache. Setting it
// to '0' will disable caching.
func NewRoutingResolver(route routing.IpfsRouting, cachesize int) *routingResolver {
	if route == nil {
		panic("attempt to create resolver with nil routing system")
	}

	var cache *lru.Cache
	if cachesize > 0 {
		cache, _ = lru.New(cachesize)
	}

	return &routingResolver{
		routing: route,
		cache:   cache,
	}
}

// Resolve implements Resolver.
func (r *routingResolver) Resolve(ctx context.Context, name string) (path.Path, error) {
	return r.ResolveN(ctx, name, DefaultDepthLimit)
}

// ResolveN implements Resolver.
func (r *routingResolver) ResolveN(ctx context.Context, name string, depth int) (path.Path, error) {
	return resolve(ctx, r, name, depth, "/ipns/")
}

// resolveOnce implements resolver. Uses the IPFS routing system to
// resolve SFS-like names.
func (r *routingResolver) resolveOnce(ctx context.Context, name string) (path.Path, error) {
	log.Debugf("RoutingResolve: '%s'", name)
	cached, ok := r.cacheGet(name)
	if ok {
		return cached, nil
	}

	hash, err := mh.FromB58String(name)
	if err != nil {
		// name should be a multihash. if it isn't, error out here.
		log.Warningf("RoutingResolve: bad input hash: [%s]\n", name)
		return "", err
	}

	// use the routing system to get the name.
	// /ipns/<name>
	h := []byte("/ipns/" + string(hash))

	var entry *pb.IpnsEntry
	var pubkey ci.PubKey

	resp := make(chan error, 2)
	go func() {
		ipnsKey := key.Key(h)
		val, err := r.routing.GetValue(ctx, ipnsKey)
		if err != nil {
			log.Warning("RoutingResolve get failed.")
			resp <- err
		}

		entry = new(pb.IpnsEntry)
		err = proto.Unmarshal(val, entry)
		if err != nil {
			resp <- err
		}
		resp <- nil
	}()

	go func() {
		// name should be a public key retrievable from ipfs
		pubk, err := routing.GetPublicKey(r.routing, ctx, hash)
		if err != nil {
			resp <- err
		}
		pubkey = pubk
		resp <- nil
	}()

	for i := 0; i < 2; i++ {
		err = <-resp
		if err != nil {
			return "", err
		}
	}

	hsh, _ := pubkey.Hash()
	log.Debugf("pk hash = %s", key.Key(hsh))

	// check sig with pk
	if ok, err := pubkey.Verify(ipnsEntryDataForSig(entry), entry.GetSignature()); err != nil || !ok {
		return "", fmt.Errorf("Invalid value. Not signed by PrivateKey corresponding to %v", pubkey)
	}

	// ok sig checks out. this is a valid name.

	// check for old style record:
	valh, err := mh.Cast(entry.GetValue())
	if err != nil {
		// Not a multihash, probably a new record
		p, err := path.ParsePath(string(entry.GetValue()))
		if err != nil {
			return "", err
		}

		r.cacheSet(name, p, entry)
		return p, nil
	} else {
		// Its an old style multihash record
		log.Warning("Detected old style multihash record")
		p := path.FromKey(key.Key(valh))
		r.cacheSet(name, p, entry)
		return p, nil
	}
}

func checkEOL(e *pb.IpnsEntry) (time.Time, bool) {
	if e.GetValidityType() == pb.IpnsEntry_EOL {
		eol, err := u.ParseRFC3339(string(e.GetValidity()))
		if err != nil {
			return time.Time{}, false
		}
		return eol, true
	}
	return time.Time{}, false
}
<commit_msg>ipfs name resolve --local fixed multihash error<commit_after>package namesys

import (
	"fmt"
	"strings"
	"time"

	lru "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/golang-lru"
	mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
	proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
	"gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"

	key "github.com/ipfs/go-ipfs/blocks/key"
	pb "github.com/ipfs/go-ipfs/namesys/pb"
	path "github.com/ipfs/go-ipfs/path"
	routing "github.com/ipfs/go-ipfs/routing"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
	logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log"
	ci "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/crypto"
)

var log = logging.Logger("namesys")

// routingResolver implements NSResolver for the main IPFS SFS-like naming
type routingResolver struct {
	routing routing.IpfsRouting

	cache *lru.Cache
}

func (r *routingResolver) cacheGet(name string) (path.Path, bool) {
	if r.cache == nil {
		return "", false
	}

	ientry, ok := r.cache.Get(name)
	if !ok {
		return "", false
	}

	entry, ok := ientry.(cacheEntry)
	if !ok {
		// should never happen, purely for sanity
		log.Panicf("unexpected type %T in cache for %q.", ientry, name)
	}

	if time.Now().Before(entry.eol) {
		return entry.val, true
	}

	r.cache.Remove(name)

	return "", false
}

func (r *routingResolver) cacheSet(name string, val path.Path, rec *pb.IpnsEntry) {
	if r.cache == nil {
		return
	}

	// if completely unspecified, just use one minute
	ttl := DefaultResolverCacheTTL
	if rec.Ttl != nil {
		recttl := time.Duration(rec.GetTtl())
		if recttl >= 0 {
			ttl = recttl
		}
	}

	cacheTil := time.Now().Add(ttl)
	eol, ok := checkEOL(rec)
	if ok && eol.Before(cacheTil) {
		cacheTil = eol
	}

	r.cache.Add(name, cacheEntry{
		val: val,
		eol: cacheTil,
	})
}

type cacheEntry struct {
	val path.Path
	eol time.Time
}

// NewRoutingResolver constructs a name resolver using the IPFS Routing system
// to implement SFS-like naming on top.
// cachesize is the limit of the number of entries in the lru cache. Setting it
// to '0' will disable caching.
func NewRoutingResolver(route routing.IpfsRouting, cachesize int) *routingResolver {
	if route == nil {
		panic("attempt to create resolver with nil routing system")
	}

	var cache *lru.Cache
	if cachesize > 0 {
		cache, _ = lru.New(cachesize)
	}

	return &routingResolver{
		routing: route,
		cache:   cache,
	}
}

// Resolve implements Resolver.
func (r *routingResolver) Resolve(ctx context.Context, name string) (path.Path, error) {
	return r.ResolveN(ctx, name, DefaultDepthLimit)
}

// ResolveN implements Resolver.
func (r *routingResolver) ResolveN(ctx context.Context, name string, depth int) (path.Path, error) {
	return resolve(ctx, r, name, depth, "/ipns/")
}

// resolveOnce implements resolver. Uses the IPFS routing system to
// resolve SFS-like names.
func (r *routingResolver) resolveOnce(ctx context.Context, name string) (path.Path, error) {
	log.Debugf("RoutingResolve: '%s'", name)
	cached, ok := r.cacheGet(name)
	if ok {
		return cached, nil
	}

	name = strings.TrimPrefix(name, "/ipns/")
	hash, err := mh.FromB58String(name)
	if err != nil {
		// name should be a multihash. if it isn't, error out here.
		log.Warningf("RoutingResolve: bad input hash: [%s]\n", name)
		return "", err
	}

	// use the routing system to get the name.
	// /ipns/<name>
	h := []byte("/ipns/" + string(hash))

	var entry *pb.IpnsEntry
	var pubkey ci.PubKey

	resp := make(chan error, 2)
	go func() {
		ipnsKey := key.Key(h)
		val, err := r.routing.GetValue(ctx, ipnsKey)
		if err != nil {
			log.Warning("RoutingResolve get failed.")
			resp <- err
		}

		entry = new(pb.IpnsEntry)
		err = proto.Unmarshal(val, entry)
		if err != nil {
			resp <- err
		}
		resp <- nil
	}()

	go func() {
		// name should be a public key retrievable from ipfs
		pubk, err := routing.GetPublicKey(r.routing, ctx, hash)
		if err != nil {
			resp <- err
		}
		pubkey = pubk
		resp <- nil
	}()

	for i := 0; i < 2; i++ {
		err = <-resp
		if err != nil {
			return "", err
		}
	}

	hsh, _ := pubkey.Hash()
	log.Debugf("pk hash = %s", key.Key(hsh))

	// check sig with pk
	if ok, err := pubkey.Verify(ipnsEntryDataForSig(entry), entry.GetSignature()); err != nil || !ok {
		return "", fmt.Errorf("Invalid value. Not signed by PrivateKey corresponding to %v", pubkey)
	}

	// ok sig checks out. this is a valid name.

	// check for old style record:
	valh, err := mh.Cast(entry.GetValue())
	if err != nil {
		// Not a multihash, probably a new record
		p, err := path.ParsePath(string(entry.GetValue()))
		if err != nil {
			return "", err
		}

		r.cacheSet(name, p, entry)
		return p, nil
	} else {
		// Its an old style multihash record
		log.Warning("Detected old style multihash record")
		p := path.FromKey(key.Key(valh))
		r.cacheSet(name, p, entry)
		return p, nil
	}
}

func checkEOL(e *pb.IpnsEntry) (time.Time, bool) {
	if e.GetValidityType() == pb.IpnsEntry_EOL {
		eol, err := u.ParseRFC3339(string(e.GetValidity()))
		if err != nil {
			return time.Time{}, false
		}
		return eol, true
	}
	return time.Time{}, false
}
<|endoftext|>


<commit_before>// Copyright © 2016 Govinda Fichtner <govinda.fichtner@googlemail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"compress/gzip"
	"fmt"
	"github.com/fsouza/go-dockerclient"
	"github.com/spf13/cobra"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

var loggingPath = "/var/log/device-init"
var logFile = filepath.Join(loggingPath, "preloaded_images.log")

// preload-imagesCmd represents the preload-images command
var preload_imagesCmd = &cobra.Command{
	Use:   "preload-images",
	Short: "Preload Docker images",
	Long:  `Preload Docker images that are defined in device-init.yaml.`,
	Run: func(cmd *cobra.Command, args []string) {
		docker_preload_images()
	},
}

func docker_preload_images() {
	readDockerConfig()

	for _, imageFile := range myDockerConfig.Images {

		if _, err := os.Stat(imageFile); err == nil {

			if validFileType(imageFile) {
				importImage(imageFile)
			} else {
				continue
			}

		} else {
			fmt.Println("Image file does not exist:", imageFile)
		}

	}

}

func init() {
	dockerCmd.AddCommand(preload_imagesCmd)
}

func validFileType(path string) bool {
	gz, _ := filepath.Match("*.tar.gz", filepath.Base(path))
	tar, _ := filepath.Match("*.tar", filepath.Base(path))

	if gz || tar {
		return true
	} else {
		return false
	}
}

func importImage(path string) {
	var loadOptions docker.LoadImageOptions

	endpoint := "unix:///var/run/docker.sock"
	client, _ := docker.NewClient(endpoint)

	if !imageAlreadyImported(path) {

		plainFile, err := os.Open(path)
		if err != nil {
			fmt.Println("Could not open file:", err)
		}
		defer plainFile.Close()

		if is_compressed(path) {
			gzipFile, err := gzip.NewReader(plainFile)
			if err != nil {
				fmt.Println("Could not open zipped file:", err)
			}
			loadOptions.InputStream = gzipFile
		} else {
			loadOptions.InputStream = plainFile
		}

		err = client.LoadImage(loadOptions)
		if err != nil {
			fmt.Println("Could not import Docker image:", err)
		} else {
			logImportedImage(path)
		}
		fmt.Println("Imported image:", path)
	} else {
		fmt.Println("Already imported image:", path)
	}
}

func is_compressed(path string) bool {
	isCompressed := false
	if gz, _ := filepath.Match("*.tar.gz", filepath.Base(path)); gz {
		file, err := os.Open(path)
		if err != nil {
			fmt.Println("Could not open file:", err)
		}
		defer file.Close()

		buff := make([]byte, 512)
		_, err = file.Read(buff)
		if err != nil {
			fmt.Println("Could not read file:", err)
		}

		filetype := http.DetectContentType(buff)
		if filetype == "application/x-gzip" {
			isCompressed = true
		}
	}
	return isCompressed
}

func logImportedImage(path string) {
	err := os.MkdirAll(loggingPath, 0755)
	if err != nil {
		fmt.Println("Could not create logging dir:", err)
	}

	if !imageAlreadyImported(path) {
		var f *os.File
		if _, err := os.Stat(logFile); err == nil {
			f, err = os.OpenFile(logFile, os.O_APPEND|os.O_WRONLY, 0666)
		} else {
			f, err = os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0666)
		}
		if err != nil {
			fmt.Println("Could not open logfile:", err)
		}
		defer f.Close()

		if _, err := f.WriteString(path); err != nil {
			fmt.Println("Could not write to logfile:", err)
		}
	}
}

func imageAlreadyImported(path string) bool {
	imported := false

	if _, err := os.Stat(logFile); err == nil {
		input, err := ioutil.ReadFile(logFile)
		if err != nil {
			fmt.Println("Could not open logfile:", err)
		}

		for _, line := range strings.Split(string(input), "\n") {
			if strings.Contains(line, path) {
				imported = true
			}
		}
	}

	return imported
}
<commit_msg>rename function is_compressed to isCompressed<commit_after>// Copyright © 2016 Govinda Fichtner <govinda.fichtner@googlemail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"compress/gzip"
	"fmt"
	"github.com/fsouza/go-dockerclient"
	"github.com/spf13/cobra"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

var loggingPath = "/var/log/device-init"
var logFile = filepath.Join(loggingPath, "preloaded_images.log")

// preload-imagesCmd represents the preload-images command
var preload_imagesCmd = &cobra.Command{
	Use:   "preload-images",
	Short: "Preload Docker images",
	Long:  `Preload Docker images that are defined in device-init.yaml.`,
	Run: func(cmd *cobra.Command, args []string) {
		docker_preload_images()
	},
}

func docker_preload_images() {
	readDockerConfig()

	for _, imageFile := range myDockerConfig.Images {

		if _, err := os.Stat(imageFile); err == nil {

			if validFileType(imageFile) {
				importImage(imageFile)
			} else {
				continue
			}

		} else {
			fmt.Println("Image file does not exist:", imageFile)
		}

	}

}

func init() {
	dockerCmd.AddCommand(preload_imagesCmd)
}

func validFileType(path string) bool {
	gz, _ := filepath.Match("*.tar.gz", filepath.Base(path))
	tar, _ := filepath.Match("*.tar", filepath.Base(path))

	if gz || tar {
		return true
	} else {
		return false
	}
}

func importImage(path string) {
	var loadOptions docker.LoadImageOptions

	endpoint := "unix:///var/run/docker.sock"
	client, _ := docker.NewClient(endpoint)

	if !imageAlreadyImported(path) {

		plainFile, err := os.Open(path)
		if err != nil {
			fmt.Println("Could not open file:", err)
		}
		defer plainFile.Close()

		if isCompressed(path) {
			gzipFile, err := gzip.NewReader(plainFile)
			if err != nil {
				fmt.Println("Could not open zipped file:", err)
			}
			loadOptions.InputStream = gzipFile
		} else {
			loadOptions.InputStream = plainFile
		}

		err = client.LoadImage(loadOptions)
		if err != nil {
			fmt.Println("Could not import Docker image:", err)
		} else {
			logImportedImage(path)
		}
		fmt.Println("Imported image:", path)
	} else {
		fmt.Println("Already imported image:", path)
	}
}

func isCompressed(path string) bool {
	compressed := false
	if gz, _ := filepath.Match("*.tar.gz", filepath.Base(path)); gz {
		file, err := os.Open(path)
		if err != nil {
			fmt.Println("Could not open file:", err)
		}
		defer file.Close()

		buff := make([]byte, 512)
		_, err = file.Read(buff)
		if err != nil {
			fmt.Println("Could not read file:", err)
		}

		filetype := http.DetectContentType(buff)
		if filetype == "application/x-gzip" {
			compressed = true
		}
	}
	return compressed
}

func logImportedImage(path string) {
	err := os.MkdirAll(loggingPath, 0755)
	if err != nil {
		fmt.Println("Could not create logging dir:", err)
	}

	if !imageAlreadyImported(path) {
		var f *os.File
		if _, err := os.Stat(logFile); err == nil {
			f, err = os.OpenFile(logFile, os.O_APPEND|os.O_WRONLY, 0666)
		} else {
			f, err = os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0666)
		}
		if err != nil {
			fmt.Println("Could not open logfile:", err)
		}
		defer f.Close()

		if _, err := f.WriteString(path); err != nil {
			fmt.Println("Could not write to logfile:", err)
		}
	}
}

func imageAlreadyImported(path string) bool {
	imported := false

	if _, err := os.Stat(logFile); err == nil {
		input, err := ioutil.ReadFile(logFile)
		if err != nil {
			fmt.Println("Could not open logfile:", err)
		}

		for _, line := range strings.Split(string(input), "\n") {
			if strings.Contains(line, path) {
				imported = true
			}
		}
	}

	return imported
}
<|endoftext|>


<commit_before>// Copyright © 2017 Orinoco Payments
// 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 cmd

import (
	"fmt"
	"math/big"

	etherutils "github.com/orinocopay/go-etherutils"
	"github.com/orinocopay/go-etherutils/cli"
	"github.com/orinocopay/go-etherutils/ens"
	"github.com/spf13/cobra"
)

var auctionRevealPassphrase string
var auctionRevealAddressStr string
var auctionRevealGasPriceStr string
var auctionRevealBidPriceStr string
var auctionRevealSalt string

// auctionRevealCmd represents the auctionReveal set command
var auctionRevealCmd = &cobra.Command{
	Use:   "reveal",
	Short: "Reveal a bid in an auction for an ENS name",
	Long: `Reveal the auction for a name with the Ethereum Name Service (ENS).  For example:

    ens auction reveal --address=0x5FfC014343cd971B7eb70732021E26C35B744cc4 --passphrase="my secret passphrase" --bid="0.01 Ether" enstest.eth

The keystore for the address must be local (i.e. listed with 'get accounts list') and unlockable with the supplied passphrase.

In quiet mode this will return 0 if the transaction to reveal the bid is sent successfully, otherwise 1.`,
	Run: func(cmd *cobra.Command, args []string) {
		cli.Assert(auctionStartSalt != "", quiet, "Salt is required")

		// Ensure that the name is in a suitable state
		registrarContract, err := ens.RegistrarContract(client, rpcclient)
		inState, err := ens.NameInState(registrarContract, args[0], "Revealing")
		cli.ErrAssert(inState, err, quiet, "Name not in a suitable state for bid to be revealed")

		// Fetch the wallet and account for the address
		auctionRevealAddress, err := ens.Resolve(client, auctionRevealAddressStr, rpcclient)
		cli.ErrCheck(err, quiet, "Failed to obtain auction address")
		wallet, err := cli.ObtainWallet(chainID, auctionRevealAddress)
		cli.ErrCheck(err, quiet, "Failed to obtain a wallet for the address")
		account, err := cli.ObtainAccount(wallet, auctionRevealAddress, auctionRevealPassphrase)
		cli.ErrCheck(err, quiet, "Failed to obtain an account for the address")

		gasLimit := big.NewInt(500000)
		gasPrice, err := etherutils.StringToWei(auctionRevealGasPriceStr)
		cli.ErrCheck(err, quiet, "Invalid gas price")

		// Set up our session
		session := ens.CreateRegistrarSession(chainID, &wallet, account, auctionRevealPassphrase, registrarContract, gasLimit, gasPrice)

		bidPrice, err := etherutils.StringToWei(auctionRevealBidPriceStr)
		cli.ErrCheck(err, quiet, "Invalid bid price")

		// Reveal the bid
		tx, err := ens.RevealBid(session, args[0], &auctionRevealAddress, *bidPrice, auctionRevealSalt)
		cli.ErrCheck(err, quiet, "Failed to send transaction")
		if !quiet {
			fmt.Println("Transaction ID is", tx.Hash().Hex())
		}
	},
}

func init() {
	auctionCmd.AddCommand(auctionRevealCmd)

	auctionRevealCmd.Flags().StringVarP(&auctionRevealPassphrase, "passphrase", "p", "", "Passphrase for the account that owns the bidding address")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealAddressStr, "address", "a", "", "Address doing the bidding")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealGasPriceStr, "gasprice", "g", "20 GWei", "Gas price for the transaction")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealBidPriceStr, "bid", "b", "0.01 Ether", "Bid price for the name")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealSalt, "salt", "s", "", "Memorable phrase needed when revealing bid")
}
<commit_msg>Fix reveal salt option<commit_after>// Copyright © 2017 Orinoco Payments
// 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 cmd

import (
	"fmt"
	"math/big"

	etherutils "github.com/orinocopay/go-etherutils"
	"github.com/orinocopay/go-etherutils/cli"
	"github.com/orinocopay/go-etherutils/ens"
	"github.com/spf13/cobra"
)

var auctionRevealPassphrase string
var auctionRevealAddressStr string
var auctionRevealGasPriceStr string
var auctionRevealBidPriceStr string
var auctionRevealSalt string

// auctionRevealCmd represents the auctionReveal set command
var auctionRevealCmd = &cobra.Command{
	Use:   "reveal",
	Short: "Reveal a bid in an auction for an ENS name",
	Long: `Reveal the auction for a name with the Ethereum Name Service (ENS).  For example:

    ens auction reveal --address=0x5FfC014343cd971B7eb70732021E26C35B744cc4 --passphrase="my secret passphrase" --bid="0.01 Ether" enstest.eth

The keystore for the address must be local (i.e. listed with 'get accounts list') and unlockable with the supplied passphrase.

In quiet mode this will return 0 if the transaction to reveal the bid is sent successfully, otherwise 1.`,
	Run: func(cmd *cobra.Command, args []string) {
		cli.Assert(auctionRevealSalt != "", quiet, "Salt is required")

		// Ensure that the name is in a suitable state
		registrarContract, err := ens.RegistrarContract(client, rpcclient)
		inState, err := ens.NameInState(registrarContract, args[0], "Revealing")
		cli.ErrAssert(inState, err, quiet, "Name not in a suitable state for bid to be revealed")

		// Fetch the wallet and account for the address
		auctionRevealAddress, err := ens.Resolve(client, auctionRevealAddressStr, rpcclient)
		cli.ErrCheck(err, quiet, "Failed to obtain auction address")
		wallet, err := cli.ObtainWallet(chainID, auctionRevealAddress)
		cli.ErrCheck(err, quiet, "Failed to obtain a wallet for the address")
		account, err := cli.ObtainAccount(wallet, auctionRevealAddress, auctionRevealPassphrase)
		cli.ErrCheck(err, quiet, "Failed to obtain an account for the address")

		gasLimit := big.NewInt(500000)
		gasPrice, err := etherutils.StringToWei(auctionRevealGasPriceStr)
		cli.ErrCheck(err, quiet, "Invalid gas price")

		// Set up our session
		session := ens.CreateRegistrarSession(chainID, &wallet, account, auctionRevealPassphrase, registrarContract, gasLimit, gasPrice)

		bidPrice, err := etherutils.StringToWei(auctionRevealBidPriceStr)
		cli.ErrCheck(err, quiet, "Invalid bid price")

		// Reveal the bid
		tx, err := ens.RevealBid(session, args[0], &auctionRevealAddress, *bidPrice, auctionRevealSalt)
		cli.ErrCheck(err, quiet, "Failed to send transaction")
		if !quiet {
			fmt.Println("Transaction ID is", tx.Hash().Hex())
		}
	},
}

func init() {
	auctionCmd.AddCommand(auctionRevealCmd)

	auctionRevealCmd.Flags().StringVarP(&auctionRevealPassphrase, "passphrase", "p", "", "Passphrase for the account that owns the bidding address")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealAddressStr, "address", "a", "", "Address doing the bidding")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealGasPriceStr, "gasprice", "g", "20 GWei", "Gas price for the transaction")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealBidPriceStr, "bid", "b", "0.01 Ether", "Bid price for the name")
	auctionRevealCmd.Flags().StringVarP(&auctionRevealSalt, "salt", "s", "", "Memorable phrase needed when revealing bid")
}
<|endoftext|>