<commit_before>// Copyright (c) 2016 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/ghodss/yaml"
	"github.com/golang/glog"
	"github.com/tigera/libcalico-go/lib/api"
	"github.com/tigera/libcalico-go/lib/api/unversioned"
	"github.com/tigera/libcalico-go/lib/client"
	"github.com/tigera/libcalico-go/lib/resourcemgr"
	"github.com/tigera/libcalico-go/lib/types"
)

// Create a new CalicoClient using connection information in the specified
// filename (if it exists), dropping back to environment variables for any
// parameter not loaded from file.
func NewClient(cf *string) (*client.Client, error) {
	if _, err := os.Stat(*cf); err != nil {
		cf = nil
	}

	cfg, err := client.LoadClientConfig(cf)
	if err != nil {
		return nil, err
	}
	glog.V(2).Infof("Loaded client config: type=%v %#v", cfg.BackendType, cfg.BackendConfig)

	c, err := client.New(cfg)
	if err != nil {
		return nil, err
	}

	return c, err
}

// Convert loaded resources to a slice of resources for easier processing.
// The loaded resources may be a slice containing resources and resource lists, or
// may be a single resource or a single resource list.  This function handles the
// different possible options to convert to a single slice of resources.
func convertToSliceOfResources(loaded interface{}) []unversioned.Resource {
	r := []unversioned.Resource{}
	glog.V(2).Infof("Converting resource to slice: %v\n", loaded)

	switch reflect.TypeOf(loaded).Kind() {
	case reflect.Slice:
		// Recursively call this to add each resource in the supplied slice to
		// return slice.
		s := reflect.ValueOf(loaded)
		for i := 0; i < s.Len(); i++ {
			r = append(r, convertToSliceOfResources(s.Index(i).Interface())...)
		}
	case reflect.Struct:
		// This is a resource or resource list.  If a resource, add to our return
		// slice.  If a resource list, add each item to our return slice.
		lr := loaded.(unversioned.Resource)
		if strings.HasSuffix(lr.GetTypeMetadata().Kind, "List") {
			items := reflect.ValueOf(loaded).Elem().FieldByName("Items")
			for i := 0; i < items.Len(); i++ {
				r = append(r, items.Index(i).Interface().(unversioned.Resource))
			}
		} else {
			r = append(r, lr)
		}
	case reflect.Ptr:
		// This is a resource or resource list.  If a resource, add to our return
		// slice.  If a resource list, add each item to our return slice.
		lr := reflect.ValueOf(loaded).Elem().Interface().(unversioned.Resource)
		if strings.HasSuffix(lr.GetTypeMetadata().Kind, "List") {
			items := reflect.ValueOf(loaded).Elem().FieldByName("Items")
			for i := 0; i < items.Len(); i++ {
				r = append(r, items.Index(i).Interface().(unversioned.Resource))
			}
		} else {
			r = append(r, lr)
		}
	default:
		panic(errors.New(fmt.Sprintf("unhandled type %v converting to resource slice",
			reflect.TypeOf(loaded).Kind())))
	}

	glog.V(2).Infof("Returning slice: %v\n", r)
	return r
}

// Return a resource instance from the command line arguments.
func getResourceFromArguments(args map[string]interface{}) (unversioned.Resource, error) {
	kind := args["<KIND>"].(string)
	stringOrBlank := func(argName string) string {
		if args[argName] != nil {
			return args[argName].(string)
		}
		return ""
	}
	name := stringOrBlank("<NAME>")
	hostname := stringOrBlank("--hostname")
	switch kind {
	case "hostEndpoint":
		h := api.NewHostEndpoint()
		h.Metadata.Name = name
		h.Metadata.Hostname = hostname
		return *h, nil
	case "workloadEndpoint":
		h := api.NewWorkloadEndpoint() //TODO Need to add orchestrator ID and workload ID
		h.Metadata.Name = name
		h.Metadata.Hostname = hostname
		return *h, nil
	case "profile":
		p := api.NewProfile()
		p.Metadata.Name = name
		return *p, nil
	case "policy":
		p := api.NewPolicy()
		p.Metadata.Name = name
		return *p, nil
	case "pool":
		p := api.NewPool()
		if name != "" {
			_, cidr, err := types.ParseCIDR(name)
			if err != nil {
				return nil, err
			}
			p.Metadata.CIDR = *cidr
		}
		return *p, nil

	default:
		return nil, fmt.Errorf("Resource type '%s' is not unsupported", kind)
	}
}

// Interface to execute a command for a specific resource type.
type commandInterface interface {
	execute(client *client.Client, resource unversioned.Resource) (unversioned.Resource, error)
}

// Results from executing a CLI command
type commandResults struct {
	// Whether the input file was invalid.
	fileInvalid bool

	// The number of resources that are being configured.
	numResources int

	// The number of resources that were actually configured.  This will
	// never be 0 without an associated error.
	numHandled int

	// The associated error.
	err error

	// The single type of resource that is being configured, or blank
	// if multiple resource types are being configured in a single shot.
	singleKind string

	// The results returned from each invocation
	resources []unversioned.Resource
}

// Common function for configuration commands create, replace and delete.  All
// these commands:
// 	-  Load resources from file (or if not specified determine the resource from
// 	   the command line options).
// 	-  Convert the loaded resources into a list of resources (easier to handle)
// 	-  Process each resource individually, collate results and exit on the first error.
func executeConfigCommand(args map[string]interface{}, cmd commandInterface) commandResults {
	var r interface{}
	var err error
	var resources []unversioned.Resource

	glog.V(2).Info("Executing config command")

	if filename := args["--filename"]; filename != nil {
		// Filename is specified, load the resource from file and convert to a slice
		// of resources for easier handling.
		if r, err = resourcemgr.CreateResourceFromFile(filename.(string)); err != nil {
			return commandResults{err: err, fileInvalid: true}
		}

		resources = convertToSliceOfResources(r)
	} else if r, err := getResourceFromArguments(args); err != nil {
		return commandResults{err: err, fileInvalid: true}
	} else {
		// We extracted a single resource type with identifiers from the CLI, convert to
		// a list for simpler handling.
		resources = []unversioned.Resource{r}
	}

	if len(resources) == 0 {
		return commandResults{err: errors.New("no resources specified")}
	}

	if glog.V(2) {
		glog.Infof("Resources: %v\n", resources)
		d, err := yaml.Marshal(resources)
		if err != nil {
			return commandResults{err: err}
		}
		glog.Infof("Data: %s\n", string(d))
	}

	// Load the client config and connect.
	cf := args["--config"].(string)
	client, err := NewClient(&cf)
	if err != nil {
		return commandResults{err: err}
	}
	glog.V(2).Infof("Client: %v\n", client)

	// Initialise the command results with the number of resources and the name of the
	// kind of resource (if only dealing with a single resource).
	var results commandResults
	var kind string
	count := make(map[string]int)
	for _, r := range resources {
		kind = r.GetTypeMetadata().Kind
		count[kind] = count[kind] + 1
		results.numResources = results.numResources + 1
	}
	if len(count) == 1 {
		results.singleKind = kind
	}

	// Now execute the command on each resource in order, exiting as soon as we hit an
	// error.
	for _, r := range resources {
		r, err = cmd.execute(client, r)
		if err != nil {
			results.err = err
			break
		}
		results.resources = append(results.resources, r)
		results.numHandled = results.numHandled + 1
	}

	return results
}
<commit_msg>Split up types into functionally related packages<commit_after>// Copyright (c) 2016 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
	"errors"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/ghodss/yaml"
	"github.com/golang/glog"
	"github.com/tigera/libcalico-go/lib/api"
	"github.com/tigera/libcalico-go/lib/api/unversioned"
	"github.com/tigera/libcalico-go/lib/client"
	"github.com/tigera/libcalico-go/lib/resourcemgr"
	"github.com/tigera/libcalico-go/lib/net"
)

// Create a new CalicoClient using connection information in the specified
// filename (if it exists), dropping back to environment variables for any
// parameter not loaded from file.
func NewClient(cf *string) (*client.Client, error) {
	if _, err := os.Stat(*cf); err != nil {
		cf = nil
	}

	cfg, err := client.LoadClientConfig(cf)
	if err != nil {
		return nil, err
	}
	glog.V(2).Infof("Loaded client config: type=%v %#v", cfg.BackendType, cfg.BackendConfig)

	c, err := client.New(cfg)
	if err != nil {
		return nil, err
	}

	return c, err
}

// Convert loaded resources to a slice of resources for easier processing.
// The loaded resources may be a slice containing resources and resource lists, or
// may be a single resource or a single resource list.  This function handles the
// different possible options to convert to a single slice of resources.
func convertToSliceOfResources(loaded interface{}) []unversioned.Resource {
	r := []unversioned.Resource{}
	glog.V(2).Infof("Converting resource to slice: %v\n", loaded)

	switch reflect.TypeOf(loaded).Kind() {
	case reflect.Slice:
		// Recursively call this to add each resource in the supplied slice to
		// return slice.
		s := reflect.ValueOf(loaded)
		for i := 0; i < s.Len(); i++ {
			r = append(r, convertToSliceOfResources(s.Index(i).Interface())...)
		}
	case reflect.Struct:
		// This is a resource or resource list.  If a resource, add to our return
		// slice.  If a resource list, add each item to our return slice.
		lr := loaded.(unversioned.Resource)
		if strings.HasSuffix(lr.GetTypeMetadata().Kind, "List") {
			items := reflect.ValueOf(loaded).Elem().FieldByName("Items")
			for i := 0; i < items.Len(); i++ {
				r = append(r, items.Index(i).Interface().(unversioned.Resource))
			}
		} else {
			r = append(r, lr)
		}
	case reflect.Ptr:
		// This is a resource or resource list.  If a resource, add to our return
		// slice.  If a resource list, add each item to our return slice.
		lr := reflect.ValueOf(loaded).Elem().Interface().(unversioned.Resource)
		if strings.HasSuffix(lr.GetTypeMetadata().Kind, "List") {
			items := reflect.ValueOf(loaded).Elem().FieldByName("Items")
			for i := 0; i < items.Len(); i++ {
				r = append(r, items.Index(i).Interface().(unversioned.Resource))
			}
		} else {
			r = append(r, lr)
		}
	default:
		panic(errors.New(fmt.Sprintf("unhandled type %v converting to resource slice",
			reflect.TypeOf(loaded).Kind())))
	}

	glog.V(2).Infof("Returning slice: %v\n", r)
	return r
}

// Return a resource instance from the command line arguments.
func getResourceFromArguments(args map[string]interface{}) (unversioned.Resource, error) {
	kind := args["<KIND>"].(string)
	stringOrBlank := func(argName string) string {
		if args[argName] != nil {
			return args[argName].(string)
		}
		return ""
	}
	name := stringOrBlank("<NAME>")
	hostname := stringOrBlank("--hostname")
	switch kind {
	case "hostEndpoint":
		h := api.NewHostEndpoint()
		h.Metadata.Name = name
		h.Metadata.Hostname = hostname
		return *h, nil
	case "workloadEndpoint":
		h := api.NewWorkloadEndpoint() //TODO Need to add orchestrator ID and workload ID
		h.Metadata.Name = name
		h.Metadata.Hostname = hostname
		return *h, nil
	case "profile":
		p := api.NewProfile()
		p.Metadata.Name = name
		return *p, nil
	case "policy":
		p := api.NewPolicy()
		p.Metadata.Name = name
		return *p, nil
	case "pool":
		p := api.NewPool()
		if name != "" {
			_, cidr, err := net.ParseCIDR(name)
			if err != nil {
				return nil, err
			}
			p.Metadata.CIDR = *cidr
		}
		return *p, nil

	default:
		return nil, fmt.Errorf("Resource type '%s' is not unsupported", kind)
	}
}

// Interface to execute a command for a specific resource type.
type commandInterface interface {
	execute(client *client.Client, resource unversioned.Resource) (unversioned.Resource, error)
}

// Results from executing a CLI command
type commandResults struct {
	// Whether the input file was invalid.
	fileInvalid bool

	// The number of resources that are being configured.
	numResources int

	// The number of resources that were actually configured.  This will
	// never be 0 without an associated error.
	numHandled int

	// The associated error.
	err error

	// The single type of resource that is being configured, or blank
	// if multiple resource types are being configured in a single shot.
	singleKind string

	// The results returned from each invocation
	resources []unversioned.Resource
}

// Common function for configuration commands create, replace and delete.  All
// these commands:
// 	-  Load resources from file (or if not specified determine the resource from
// 	   the command line options).
// 	-  Convert the loaded resources into a list of resources (easier to handle)
// 	-  Process each resource individually, collate results and exit on the first error.
func executeConfigCommand(args map[string]interface{}, cmd commandInterface) commandResults {
	var r interface{}
	var err error
	var resources []unversioned.Resource

	glog.V(2).Info("Executing config command")

	if filename := args["--filename"]; filename != nil {
		// Filename is specified, load the resource from file and convert to a slice
		// of resources for easier handling.
		if r, err = resourcemgr.CreateResourceFromFile(filename.(string)); err != nil {
			return commandResults{err: err, fileInvalid: true}
		}

		resources = convertToSliceOfResources(r)
	} else if r, err := getResourceFromArguments(args); err != nil {
		return commandResults{err: err, fileInvalid: true}
	} else {
		// We extracted a single resource type with identifiers from the CLI, convert to
		// a list for simpler handling.
		resources = []unversioned.Resource{r}
	}

	if len(resources) == 0 {
		return commandResults{err: errors.New("no resources specified")}
	}

	if glog.V(2) {
		glog.Infof("Resources: %v\n", resources)
		d, err := yaml.Marshal(resources)
		if err != nil {
			return commandResults{err: err}
		}
		glog.Infof("Data: %s\n", string(d))
	}

	// Load the client config and connect.
	cf := args["--config"].(string)
	client, err := NewClient(&cf)
	if err != nil {
		return commandResults{err: err}
	}
	glog.V(2).Infof("Client: %v\n", client)

	// Initialise the command results with the number of resources and the name of the
	// kind of resource (if only dealing with a single resource).
	var results commandResults
	var kind string
	count := make(map[string]int)
	for _, r := range resources {
		kind = r.GetTypeMetadata().Kind
		count[kind] = count[kind] + 1
		results.numResources = results.numResources + 1
	}
	if len(count) == 1 {
		results.singleKind = kind
	}

	// Now execute the command on each resource in order, exiting as soon as we hit an
	// error.
	for _, r := range resources {
		r, err = cmd.execute(client, r)
		if err != nil {
			results.err = err
			break
		}
		results.resources = append(results.resources, r)
		results.numHandled = results.numHandled + 1
	}

	return results
}
<|endoftext|>


<commit_before>package logger

import (
	"os"
	"fmt"
)

const (
	ERROR string = "ERROR"
	INFO = "INFO"
)

var Logger Log

func init() {
	Logger = CreateLogger()
}

type CliLogger struct {
	logLevel string
}

func CreateLogger() (logger *CliLogger) {
	logger = new(CliLogger)
	logger.setLevel()
	return
}

func (logger *CliLogger) setLevel() {
	if os.Getenv("JFROG_CLI_LOG_LEVEL") == ERROR {
		logger.logLevel = ERROR
	} else {
		logger.logLevel = INFO
	}
}

func (logger CliLogger) Info(a ...interface{}) {
	if logger.logLevel != ERROR {
		fmt.Println(a...)
	}
}

func (logger CliLogger) Error(a ...interface{}) {
	fmt.Println(a...)
}

type Log interface {
	Info(a ...interface{})
	Error(a ...interface{})
}

<commit_msg>Add logger<commit_after>package logger

import (
	"os"
	"fmt"
)

const (
	ERROR string = "ERROR"
	INFO = "INFO"
)

var Logger Log

func init() {
	Logger = createLogger()
}

type CliLogger struct {
	logLevel string
}

func createLogger() (logger *CliLogger) {
	logger = new(CliLogger)
	logger.setLevel()
	return
}

func (logger *CliLogger) setLevel() {
	if os.Getenv("JFROG_CLI_LOG_LEVEL") == ERROR {
		logger.logLevel = ERROR
	} else {
		logger.logLevel = INFO
	}
}

func (logger CliLogger) Info(a ...interface{}) {
	if logger.logLevel != ERROR {
		fmt.Println(a...)
	}
}

func (logger CliLogger) Error(a ...interface{}) {
	fmt.Println(a...)
}

type Log interface {
	Info(a ...interface{})
	Error(a ...interface{})
}

<|endoftext|>


<commit_before>// This file is subject to a 1-clause BSD license.
// Its contents can be found in the enclosed LICENSE file.

package ipintel

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/jteeuwen/ircb/cmd"
	"github.com/jteeuwen/ircb/plugin"
	"github.com/jteeuwen/ircb/proto"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

var regMibbit = regexp.MustCompile(`^[a-fA-F0-9]{8}$`)

const url = "http://api.neustar.biz/ipi/std/v1/ipinfo/%s?apikey=%s&sig=%s&format=json"

func init() { plugin.Register(New) }

type Plugin struct {
	*plugin.Base
}

func New(profile string) plugin.Plugin {
	p := new(Plugin)
	p.Base = plugin.New(profile, "ipintel")
	return p
}

func (p *Plugin) Load(c *proto.Client) (err error) {
	err = p.Base.Load(c)
	if err != nil {
		return
	}

	ini := p.LoadConfig()
	if ini == nil {
		log.Fatalf("[ipintel] No configuration found.")
		return
	}

	key := ini.Section("api").S("key", "")
	if len(key) == 0 {
		log.Fatalf("[ipintel] No API key found.")
		return
	}

	shared := ini.Section("api").S("shared", "")
	if len(shared) == 0 {
		log.Fatalf("[ipintel] No API shared secret found.")
		return
	}

	drift := ini.Section("api").I64("drift", 0)
	if len(shared) == 0 {
		log.Fatalf("[ipintel] No API shared secret found.")
		return
	}

	w := new(cmd.Command)
	w.Name = "loc"
	w.Description = "Fetch geo-location data for the given IP address."
	w.Restricted = false
	w.Params = []cmd.Param{
		{Name: "ip", Description: "IPv4 address to look up", Pattern: cmd.RegIPv4},
	}
	w.Execute = func(cmd *cmd.Command, c *proto.Client, m *proto.Message) {
		hash := md5.New()
		stamp := fmt.Sprintf("%d", time.Now().UTC().Unix()+drift)
		io.WriteString(hash, key+shared+stamp)

		sig := fmt.Sprintf("%x", hash.Sum(nil))
		target := fmt.Sprintf(url, cmd.Params[0].Value, key, sig)

		resp, err := http.Get(target)
		if err != nil {
			log.Printf("[ipintel]: %v", err)
			return
		}

		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()

		if err != nil {
			log.Printf("[ipintel]: %v", err)
			return
		}

		var data Response
		err = json.Unmarshal(body, &data)
		if err != nil {
			log.Printf("[ipintel]: %v", err)
			return
		}

		inf := data.IPInfo

		c.PrivMsg(m.Receiver,
			"%s: %s (%s), Network org.: %s, Carrier: %s, TLD: %s, SLD: %s. "+
				"Location: %s/%s/%s/%s (%f, %f). Postalcode: %s, Timezone: %d",
			m.SenderName,

			inf.IPAddress, inf.IPType,
			inf.Network.Organization,
			inf.Network.Carrier,
			inf.Network.Domain.TLD,
			inf.Network.Domain.SLD,

			inf.Location.Continent,
			inf.Location.CountryData.Name,
			inf.Location.StateData.Name,
			inf.Location.CityData.Name,
			inf.Location.Latitude,
			inf.Location.Longitude,
			inf.Location.CityData.PostalCode,
			inf.Location.CityData.TimeZone,
		)
	}

	cmd.Register(w)

	w = new(cmd.Command)
	w.Name = "mibbit"
	w.Description = "Resolve a mibbit address to a real IP address."
	w.Restricted = false
	w.Params = []cmd.Param{
		{Name: "hex", Description: "Mibbit hex string", Pattern: regMibbit},
	}
	w.Execute = func(cmd *cmd.Command, c *proto.Client, m *proto.Message) {
		hex := cmd.Params[0].Value

		var ip [4]uint64
		var err error

		ip[0], err = strconv.ParseUint(hex[:2], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		ip[1], err = strconv.ParseUint(hex[2:4], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		ip[2], err = strconv.ParseUint(hex[4:6], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		ip[3], err = strconv.ParseUint(hex[6:], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		address := fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
		names, err := net.LookupAddr(address)

		if err != nil || len(names) == 0 {
			c.PrivMsg(m.Receiver, "%s: %s is %s", m.SenderName, hex, address)
		} else {
			c.PrivMsg(m.Receiver, "%s: %s is %s / %s",
				m.SenderName, hex, address, names[0])
		}
	}

	cmd.Register(w)

	return
}
<commit_msg>Adds google maps link to ipintel plugin output.<commit_after>// This file is subject to a 1-clause BSD license.
// Its contents can be found in the enclosed LICENSE file.

package ipintel

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/jteeuwen/ircb/cmd"
	"github.com/jteeuwen/ircb/plugin"
	"github.com/jteeuwen/ircb/proto"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

var regMibbit = regexp.MustCompile(`^[a-fA-F0-9]{8}$`)

const url = "http://api.neustar.biz/ipi/std/v1/ipinfo/%s?apikey=%s&sig=%s&format=json"

func init() { plugin.Register(New) }

type Plugin struct {
	*plugin.Base
}

func New(profile string) plugin.Plugin {
	p := new(Plugin)
	p.Base = plugin.New(profile, "ipintel")
	return p
}

func (p *Plugin) Load(c *proto.Client) (err error) {
	err = p.Base.Load(c)
	if err != nil {
		return
	}

	ini := p.LoadConfig()
	if ini == nil {
		log.Fatalf("[ipintel] No configuration found.")
		return
	}

	key := ini.Section("api").S("key", "")
	if len(key) == 0 {
		log.Fatalf("[ipintel] No API key found.")
		return
	}

	shared := ini.Section("api").S("shared", "")
	if len(shared) == 0 {
		log.Fatalf("[ipintel] No API shared secret found.")
		return
	}

	drift := ini.Section("api").I64("drift", 0)
	if len(shared) == 0 {
		log.Fatalf("[ipintel] No API shared secret found.")
		return
	}

	w := new(cmd.Command)
	w.Name = "loc"
	w.Description = "Fetch geo-location data for the given IP address."
	w.Restricted = false
	w.Params = []cmd.Param{
		{Name: "ip", Description: "IPv4 address to look up", Pattern: cmd.RegIPv4},
	}
	w.Execute = func(cmd *cmd.Command, c *proto.Client, m *proto.Message) {
		hash := md5.New()
		stamp := fmt.Sprintf("%d", time.Now().UTC().Unix()+drift)
		io.WriteString(hash, key+shared+stamp)

		sig := fmt.Sprintf("%x", hash.Sum(nil))
		target := fmt.Sprintf(url, cmd.Params[0].Value, key, sig)

		resp, err := http.Get(target)
		if err != nil {
			log.Printf("[ipintel]: %v", err)
			return
		}

		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()

		if err != nil {
			log.Printf("[ipintel]: %v", err)
			return
		}

		var data Response
		err = json.Unmarshal(body, &data)
		if err != nil {
			log.Printf("[ipintel]: %v", err)
			return
		}

		inf := data.IPInfo
		mapsURL := fmt.Sprintf("https://maps.google.com/maps?q=%s,%s",
			inf.Location.Latitude, inf.Location.Longitude)

		c.PrivMsg(m.Receiver,
			"%s: %s (%s), Network org.: %s, Carrier: %s, TLD: %s, SLD: %s. "+
				"Location: %s/%s/%s/%s (%f, %f). Postalcode: %s, Timezone: %d, %s",
			m.SenderName,

			inf.IPAddress, inf.IPType,
			inf.Network.Organization,
			inf.Network.Carrier,
			inf.Network.Domain.TLD,
			inf.Network.Domain.SLD,

			inf.Location.Continent,
			inf.Location.CountryData.Name,
			inf.Location.StateData.Name,
			inf.Location.CityData.Name,
			inf.Location.Latitude,
			inf.Location.Longitude,
			inf.Location.CityData.PostalCode,
			inf.Location.CityData.TimeZone,

			mapsURL,
		)
	}

	cmd.Register(w)

	w = new(cmd.Command)
	w.Name = "mibbit"
	w.Description = "Resolve a mibbit address to a real IP address."
	w.Restricted = false
	w.Params = []cmd.Param{
		{Name: "hex", Description: "Mibbit hex string", Pattern: regMibbit},
	}
	w.Execute = func(cmd *cmd.Command, c *proto.Client, m *proto.Message) {
		hex := cmd.Params[0].Value

		var ip [4]uint64
		var err error

		ip[0], err = strconv.ParseUint(hex[:2], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		ip[1], err = strconv.ParseUint(hex[2:4], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		ip[2], err = strconv.ParseUint(hex[4:6], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		ip[3], err = strconv.ParseUint(hex[6:], 16, 8)
		if err != nil {
			c.PrivMsg(m.Receiver, "%s: invalid mibbit address.", m.SenderName)
			return
		}

		address := fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
		names, err := net.LookupAddr(address)

		if err != nil || len(names) == 0 {
			c.PrivMsg(m.Receiver, "%s: %s is %s", m.SenderName, hex, address)
		} else {
			c.PrivMsg(m.Receiver, "%s: %s is %s / %s",
				m.SenderName, hex, address, names[0])
		}
	}

	cmd.Register(w)

	return
}
<|endoftext|>


<commit_before>// Copyright ©2018 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rtests

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"go-hep.org/x/hep/groot/rbytes"
	"go-hep.org/x/hep/groot/root"
)

type ROOTer interface {
	root.Object
	rbytes.Marshaler
	rbytes.Unmarshaler
}

func XrdRemote(fname string) string {
	const remote = "root://ccxrootdgotest.in2p3.fr:9001/tmp/rootio"
	return remote + "/" + fname
}

var (
	HasROOT   = false // HasROOT is true when a C++ ROOT installation could be detected.
	ErrNoROOT = errors.New("rtests: no C++ ROOT installed")
	rootCmd   = ""
	rootCling = ""
)

// RunCxxROOT executes the function fct in the provided C++ code with optional arguments args.
// RunCxxROOT creates a temporary file named '<fct>.C' from the provided C++ code and
// executes it via ROOT C++.
// RunCxxROOT returns the combined stdout/stderr output and an error, if any.
func RunCxxROOT(fct string, code []byte, args ...interface{}) ([]byte, error) {
	tmp, err := os.MkdirTemp("", "groot-rtests-")
	if err != nil {
		return nil, fmt.Errorf("could not create tmpdir: %w", err)
	}
	defer os.RemoveAll(tmp)

	// create a dummy header file for ROOT-dictionary generation purposes.
	_ = os.WriteFile(filepath.Join(tmp, "__groot-Event.h"), []byte(""), 0644)

	fname := filepath.Join(tmp, fct+".C")
	err = os.WriteFile(fname, []byte(code), 0644)
	if err != nil {
		return nil, fmt.Errorf("could not generate ROOT macro %q: %w", fname, err)
	}

	o := new(strings.Builder)
	fmt.Fprintf(o, "%s(", fname)
	for i, arg := range args {
		format := ""
		if i > 0 {
			format = ", "
		}
		switch arg.(type) {
		case string:
			format += "%q"
		default:
			format += "%v"
		}
		fmt.Fprintf(o, format, arg)
	}
	fmt.Fprintf(o, ")")

	if !HasROOT {
		return nil, ErrNoROOT
	}

	cmd := exec.Command(rootCmd, "-l", "-b", "-x", "-q", o.String())
	out, err := cmd.CombinedOutput()
	if err != nil {
		return out, ROOTError{Err: err, Cmd: cmd.Path, Args: cmd.Args, Out: out}
	}

	return out, nil
}

// GenROOTDictCode generates the ROOT dictionary code from the given event
// and linkdef definitions.
// GenROOTDictCode invokes rootcling and returns the generated code.
func GenROOTDictCode(event, linkdef string) ([]byte, error) {
	if !HasROOT {
		return nil, ErrNoROOT
	}

	tmp, err := os.MkdirTemp("", "groot-rtests-")
	if err != nil {
		return nil, fmt.Errorf("rtests: could not create tmp dir: %w", err)
	}
	defer os.RemoveAll(tmp)

	var (
		fname = filepath.Join(tmp, "__groot-Event.h")
		link  = filepath.Join(tmp, "LinkDef.h")
		dname = filepath.Join(tmp, "dict.cxx")
	)

	err = os.WriteFile(fname, []byte(event), 0644)
	if err != nil {
		return nil, fmt.Errorf("rtests: could not write event header file: %w", err)
	}

	err = os.WriteFile(link, []byte(linkdef), 0644)
	if err != nil {
		return nil, fmt.Errorf("rtests: could not write event header file: %w", err)
	}

	cmd := exec.Command(
		rootCling,
		filepath.Base(dname),
		filepath.Base(fname),
		filepath.Base(link),
	)
	cmd.Dir = tmp

	out, err := cmd.CombinedOutput()
	if err != nil {
		return nil, ROOTError{Err: err, Cmd: cmd.Path, Args: cmd.Args, Out: out}
	}

	dict, err := os.ReadFile(dname)
	if err != nil {
		return nil, fmt.Errorf("rtests: could not read dict file: %w", err)
	}

	return dict, nil
}

type ROOTError struct {
	Err  error
	Cmd  string
	Args []string
	Out  []byte
}

func (err ROOTError) Error() string {
	return fmt.Sprintf(
		"could not run '%s': %v\noutput:\n%s",
		strings.Join(append([]string{err.Cmd}, err.Args...), " "),
		err.Err,
		err.Out,
	)
}

func (err ROOTError) Unwrap() error {
	return err.Err
}

func init() {
	cmd, err := exec.LookPath("root.exe")
	if err != nil {
		return
	}
	HasROOT = true
	rootCmd = cmd

	cmd, err = exec.LookPath("rootcling")
	if err != nil {
		cmd, err = exec.LookPath("rootcling.exe")
	}

	if err != nil {
		return
	}
	rootCling = cmd
}

var (
	_ error                       = (*ROOTError)(nil)
	_ interface{ Unwrap() error } = (*ROOTError)(nil)
)
<commit_msg>groot/internal/rtests: make sure macros are run thru ACliC<commit_after>// Copyright ©2018 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rtests

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"go-hep.org/x/hep/groot/rbytes"
	"go-hep.org/x/hep/groot/root"
)

type ROOTer interface {
	root.Object
	rbytes.Marshaler
	rbytes.Unmarshaler
}

func XrdRemote(fname string) string {
	const remote = "root://ccxrootdgotest.in2p3.fr:9001/tmp/rootio"
	return remote + "/" + fname
}

var (
	HasROOT   = false // HasROOT is true when a C++ ROOT installation could be detected.
	ErrNoROOT = errors.New("rtests: no C++ ROOT installed")
	rootCmd   = ""
	rootCling = ""
)

// RunCxxROOT executes the function fct in the provided C++ code with optional arguments args.
// RunCxxROOT creates a temporary file named '<fct>.C' from the provided C++ code and
// executes it via ROOT C++.
// RunCxxROOT returns the combined stdout/stderr output and an error, if any.
func RunCxxROOT(fct string, code []byte, args ...interface{}) ([]byte, error) {
	tmp, err := os.MkdirTemp("", "groot-rtests-")
	if err != nil {
		return nil, fmt.Errorf("could not create tmpdir: %w", err)
	}
	defer os.RemoveAll(tmp)

	// create a dummy header file for ROOT-dictionary generation purposes.
	_ = os.WriteFile(filepath.Join(tmp, "__groot-Event.h"), []byte(""), 0644)

	fname := filepath.Join(tmp, fct+".C")
	err = os.WriteFile(fname, []byte(code), 0644)
	if err != nil {
		return nil, fmt.Errorf("could not generate ROOT macro %q: %w", fname, err)
	}

	o := new(strings.Builder)
	fmt.Fprintf(o, "%s+(", fname)
	for i, arg := range args {
		format := ""
		if i > 0 {
			format = ", "
		}
		switch arg.(type) {
		case string:
			format += "%q"
		default:
			format += "%v"
		}
		fmt.Fprintf(o, format, arg)
	}
	fmt.Fprintf(o, ")")

	if !HasROOT {
		return nil, ErrNoROOT
	}

	cmd := exec.Command(rootCmd, "-l", "-b", "-x", "-q", o.String())
	out, err := cmd.CombinedOutput()
	if err != nil {
		return out, ROOTError{Err: err, Cmd: cmd.Path, Args: cmd.Args, Out: out}
	}

	return out, nil
}

// GenROOTDictCode generates the ROOT dictionary code from the given event
// and linkdef definitions.
// GenROOTDictCode invokes rootcling and returns the generated code.
func GenROOTDictCode(event, linkdef string) ([]byte, error) {
	if !HasROOT {
		return nil, ErrNoROOT
	}

	tmp, err := os.MkdirTemp("", "groot-rtests-")
	if err != nil {
		return nil, fmt.Errorf("rtests: could not create tmp dir: %w", err)
	}
	defer os.RemoveAll(tmp)

	var (
		fname = filepath.Join(tmp, "__groot-Event.h")
		link  = filepath.Join(tmp, "LinkDef.h")
		dname = filepath.Join(tmp, "dict.cxx")
	)

	err = os.WriteFile(fname, []byte(event), 0644)
	if err != nil {
		return nil, fmt.Errorf("rtests: could not write event header file: %w", err)
	}

	err = os.WriteFile(link, []byte(linkdef), 0644)
	if err != nil {
		return nil, fmt.Errorf("rtests: could not write event header file: %w", err)
	}

	cmd := exec.Command(
		rootCling,
		filepath.Base(dname),
		filepath.Base(fname),
		filepath.Base(link),
	)
	cmd.Dir = tmp

	out, err := cmd.CombinedOutput()
	if err != nil {
		return nil, ROOTError{Err: err, Cmd: cmd.Path, Args: cmd.Args, Out: out}
	}

	dict, err := os.ReadFile(dname)
	if err != nil {
		return nil, fmt.Errorf("rtests: could not read dict file: %w", err)
	}

	return dict, nil
}

type ROOTError struct {
	Err  error
	Cmd  string
	Args []string
	Out  []byte
}

func (err ROOTError) Error() string {
	return fmt.Sprintf(
		"could not run '%s': %v\noutput:\n%s",
		strings.Join(append([]string{err.Cmd}, err.Args...), " "),
		err.Err,
		err.Out,
	)
}

func (err ROOTError) Unwrap() error {
	return err.Err
}

func init() {
	cmd, err := exec.LookPath("root.exe")
	if err != nil {
		return
	}
	HasROOT = true
	rootCmd = cmd

	cmd, err = exec.LookPath("rootcling")
	if err != nil {
		cmd, err = exec.LookPath("rootcling.exe")
	}

	if err != nil {
		return
	}
	rootCling = cmd
}

var (
	_ error                       = (*ROOTError)(nil)
	_ interface{ Unwrap() error } = (*ROOTError)(nil)
)
<|endoftext|>


<commit_before>package sorter

// BubbleSort is popular but inefficient sorting algoritm
// it swaps adjacent elements by repeatedly
func BubbleSort(arr []int) []int {
	var temp int

	for i := 0; i < len(arr)-1; i++ {
		for j := len(arr) - 1; j > i; j-- {
			if arr[j] < arr[j-1] {
				temp = arr[j]
				arr[j] = arr[j-1]
				arr[j-1] = temp
			}
		}
	}

	return arr
}
<commit_msg>bubblesort: use one line swap<commit_after>package sorter

// BubbleSort is popular but inefficient sorting algorithm
// it swaps adjacent elements by repeatedly
func BubbleSort(arr []int) []int {
	for i := 0; i < len(arr)-1; i++ {
		for j := len(arr) - 1; j > i; j-- {
			if arr[j] < arr[j-1] {
				arr[j], arr[j-1] = arr[j-1], arr[j]
			}
		}
	}

	return arr
}
<|endoftext|>


<commit_before>package main

func main () {

}
<commit_msg>FIX: notifier: actually wait forever.<commit_after>package main

import (
	"os"
	"os/signal"
)

func main () {
	// Wait forever
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
	os.Exit(0)
}
<|endoftext|>


<commit_before>package parallel

import(
	"time"
)

type WorkInterface interface {
	LockInterface

	// wrapper around sync.WaitGroup.Wait(). must be thread safe (for example with sync.Once).
	// only works if Start() or it's wrapper Do() are used.
	WaitInterface

	// used to enable other packages to implement a custom worker
	Initialise(aworkers uint)

	// start workers - 1 in separate goroutines and run one
	// worker in this goroutine. the worker should block till the work is done.
	// it is not guaranteed that all work will be processed nor that the last
	// worker is really the last finishing (which can mean, that workers still
	// processing work can be interrupted and shut down by program termination).
	// intended for webservers, where the workers run in endless loops.
	Run(worker func())

	// wrapper around Start() which Waits() until all workers finish and then returns
	Do(worker func())

	// Start() N workers
	Start(worker func()) WorkInterface

	// start one feeding goroutine. can be used multiple times
	Feed(feeder func()) WorkInterface

	// use time.Tick to execute a function periodically
	Tick(duration time.Duration, tick func()) chan bool

	// after duration, call cancel function
	Timeout(duration time.Duration, cancel func()) WorkInterface

	// suggest a buffer size, best according to number of CPUs
	// FIXME remove max uint argument
	SuggestBufferSize(max uint) uint

	// suggest a buffer size for filesystem i/o
	SuggestFileBufferSize() uint
}

type LockInterface interface {
	Lock()
	Unlock()
}

// wait for something
type WaitInterface interface {
	Wait()
}
<commit_msg>parallel: make interfaces more fine grade<commit_after>package parallel

import(
	"time"
)

type WorkInterface interface {
	LockInterface

	// wrapper around sync.WaitGroup.Wait(). must be thread safe (for example with sync.Once).
	// only works if Start() or it's wrapper Do() are used.
	WaitInterface

	// used to enable other packages to implement a custom worker
	Initialise(aworkers uint)

	// start workers - 1 in separate goroutines and run one
	// worker in this goroutine. the worker should block till the work is done.
	// it is not guaranteed that all work will be processed nor that the last
	// worker is really the last finishing (which can mean, that workers still
	// processing work can be interrupted and shut down by program termination).
	// intended for webservers, where the workers run in endless loops.
	Run(worker func())

	// wrapper around Start() which Waits() until all workers finish and then returns
	Do(worker func())

	// Start() N workers
	Start(worker func()) WorkInterface

	// start one feeding goroutine. can be used multiple times
	Feed(feeder func()) WorkInterface

	// suggest a buffer size, best according to number of CPUs
	// FIXME remove max uint argument
	SuggestBufferSize(max uint) uint

	// suggest a buffer size for filesystem i/o
	SuggestFileBufferSize() uint

//	SetFeedRecover(to func())
}

type WorkHelpInterface interface {
	// suggest a buffer size, best according to number of CPUs
	SuggestBufferSize() uint

	// suggest a buffer size for filesystem i/o
	SuggestFileBufferSize() uint
}

type TickWorkInterface interface {
	// use time.Tick to execute a function periodically
	Tick(duration time.Duration, tick func()) chan bool
}

type TimeoutWorkInterface interface {
	// after duration, call cancel function
	Timeout(duration time.Duration, cancel func()) WorkInterface
}

// backup copy
type LockInterface interface {
	Lock()
	Unlock()
}

// wait for something
type WaitInterface interface {
	Wait()
}

type DoneInterface interface {
	Done()
}

type WaitGroupInterface interface {
	WaitInterface
	DoneInterface
	Add(delta int)
}
<|endoftext|>


<commit_before>// +build e2e

package token

import (
	"testing"

	"github.com/twinj/uuid"

	redis "gopkg.in/redis.v5"
)

func TestRedisStore(t *testing.T) {
	k, v := uuid.NewV4().String(), []byte(uuid.NewV4().String())
	s := &redisStore{client: redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})}
	err := s.Set(k, v)
	if err != nil {
		t.Errorf("Expected error to be nil, got %v", err)
	}
	got, err := s.Get(k)
	if err != nil {
		t.Errorf("Expected error to be nil, got %v", err)
	}
	if string(got) != string(v) {
		t.Errorf("Got %v, expected %v", got, v)
	}
}
<commit_msg>Expand tests for redis<commit_after>// +build e2e

package token

import (
	"testing"

	"github.com/twinj/uuid"

	redis "gopkg.in/redis.v5"
)

func TestSetAndGet(t *testing.T) {
	k, v := uuid.NewV4().String(), []byte(uuid.NewV4().String())
	s := &redisStore{client: redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})}
	err := s.Set(k, v)
	if err != nil {
		t.Errorf("Expected error to be nil, got %v", err)
	}
	got, err := s.Get(k)
	if err != nil {
		t.Errorf("Expected error to be nil, got %v", err)
	}
	if string(got) != string(v) {
		t.Errorf("Got %v, expected %v", got, v)
	}
}

func TestGetOfNonExistentKey(t *testing.T) {
	s := &redisStore{client: redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})}
	_, err := s.Get("notexistent")
	if err == nil {
		t.Errorf("Expected an error, got %v", err)
	}
}
<|endoftext|>


<commit_before>package zfs

/*
#include <stdlib.h>
#include <dirent.h>
#include <mntent.h>

const char* PROC_MOUNTS = "/proc/mounts";
const char* OPEN_MODE = "r";
*/
import "C"

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"
	"unsafe"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/graphdriver"
	"github.com/docker/docker/pkg/parsers"
	zfs "github.com/mistifyio/go-zfs"
)

type ZfsOptions struct {
	fsName    string
	mountPath string
}

func init() {
	graphdriver.Register("zfs", Init)
}

type Logger struct{}

func (*Logger) Log(cmd []string) {
	log.Debugf("[zfs] %s", strings.Join(cmd, " "))
}

func Init(base string, opt []string) (graphdriver.Driver, error) {
	var err error
	options, err := parseOptions(opt)
	if err != nil {
		return nil, err
	}
	options.mountPath = base

	rootdir := path.Dir(base)

	if options.fsName == "" {
		err = checkRootdirFs(rootdir)
		if err != nil {
			return nil, err
		}
	}

	if _, err := exec.LookPath("zfs"); err != nil {
		return nil, fmt.Errorf("zfs command is not available: %v", err)
	}

	file, err := os.OpenFile("/dev/zfs", os.O_RDWR, 600)
	if err != nil {
		return nil, fmt.Errorf("cannot open /dev/zfs: %v", err)
	}
	defer file.Close()

	if options.fsName == "" {
		options.fsName, err = lookupZfsDataset(rootdir)
		if err != nil {
			return nil, err
		}
	}

	zfs.SetLogger(new(Logger))

	dataset, err := zfs.GetDataset(options.fsName)
	if err != nil {
		return nil, fmt.Errorf("Cannot open %s", options.fsName)
	}

	d := &Driver{
		dataset: dataset,
		options: options,
	}
	return graphdriver.NaiveDiffDriver(d), nil
}

func parseOptions(opt []string) (ZfsOptions, error) {
	var options ZfsOptions
	options.fsName = ""
	for _, option := range opt {
		key, val, err := parsers.ParseKeyValueOpt(option)
		if err != nil {
			return options, err
		}
		key = strings.ToLower(key)
		switch key {
		case "zfs.fsname":
			options.fsName = val
		default:
			return options, fmt.Errorf("Unknown option %s", key)
		}
	}
	return options, nil
}

func checkRootdirFs(rootdir string) error {
	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return fmt.Errorf("Failed to access '%s': %s", rootdir, err)
	}

	if graphdriver.FsMagic(buf.Type) != graphdriver.FsMagicZfs {
		log.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir)
		return graphdriver.ErrPrerequisites
	}
	return nil
}

func lookupZfsDataset(rootdir string) (string, error) {
	var stat syscall.Stat_t
	if err := syscall.Stat(rootdir, &stat); err != nil {
		return "", fmt.Errorf("Failed to access '%s': %s", rootdir, err)
	}
	wantedDev := stat.Dev

	Cfp, err := C.setmntent(C.PROC_MOUNTS, C.OPEN_MODE)
	if err != nil {
		return "", fmt.Errorf("Failed to open /proc/mounts: %v", err)
	}
	defer C.endmntent(Cfp)

	var Cmnt C.struct_mntent
	buf := string(make([]byte, 256, 256))
	Cbuf := C.CString(buf)
	defer C.free(unsafe.Pointer(Cbuf))

	for C.getmntent_r(Cfp, &Cmnt, Cbuf, 256) != nil {
		dir := C.GoString(Cmnt.mnt_dir)
		if err := syscall.Stat(dir, &stat); err != nil {
			log.Debugf("[zfs] failed to stat '%s' while scanning for zfs mount: %v", dir, err)
			continue // may fail on fuse file systems
		}

		fs := C.GoString(Cmnt.mnt_type)
		if stat.Dev == wantedDev && fs == "zfs" {
			return C.GoString(Cmnt.mnt_fsname), nil
		}
	}

	return "", fmt.Errorf("Failed to find zfs dataset mounted on '%s' in /proc/mounts", rootdir)
}

type Driver struct {
	dataset *zfs.Dataset
	options ZfsOptions
}

func (d *Driver) String() string {
	return "zfs"
}

func (d *Driver) Cleanup() error {
	return nil
}

func (d *Driver) Status() [][2]string {
	parts := strings.Split(d.dataset.Name, "/")
	pool, err := zfs.GetZpool(parts[0])

	var poolName, poolHealth string
	if err == nil {
		poolName = pool.Name
		poolHealth = pool.Health
	} else {
		poolName = fmt.Sprintf("error while getting pool information %v", err)
		poolHealth = "not available"
	}

	quota := "no"
	if d.dataset.Quota != 0 {
		quota = strconv.FormatUint(d.dataset.Quota, 10)
	}

	return [][2]string{
		{"Zpool", poolName},
		{"Zpool Health", poolHealth},
		{"Parent Dataset", d.dataset.Name},
		{"Space Used By Parent", strconv.FormatUint(d.dataset.Used, 10)},
		{"Space Available", strconv.FormatUint(d.dataset.Avail, 10)},
		{"Parent Quota", quota},
		{"Compression", d.dataset.Compression},
	}
}

func cloneFilesystem(id, parent, mountpoint string) error {
	parentDataset, err := zfs.GetDataset(parent)
	if err != nil {
		return err
	}
	snapshotName := fmt.Sprintf("%d", time.Now().Nanosecond())
	snapshot, err := parentDataset.Snapshot(snapshotName /*recursive */, false)
	if err != nil {
		return err
	}

	_, err = snapshot.Clone(id, map[string]string{
		"mountpoint": mountpoint,
	})
	if err != nil {
		snapshot.Destroy(zfs.DestroyDeferDeletion)
		return err
	}
	return snapshot.Destroy(zfs.DestroyDeferDeletion)
}

func (d *Driver) ZfsPath(id string) string {
	return d.options.fsName + "/" + id
}

func (d *Driver) Create(id string, parent string) error {
	datasetName := d.ZfsPath(id)
	dataset, err := zfs.GetDataset(datasetName)
	if err == nil {
		// cleanup existing dataset from an aborted build
		err := dataset.Destroy(zfs.DestroyRecursiveClones)
		if err != nil {
			log.Warnf("[zfs] failed to destroy dataset '%s': %v", dataset.Name, err)
		}
	} else if zfsError, ok := err.(*zfs.Error); ok {
		if !strings.HasSuffix(zfsError.Stderr, "dataset does not exist\n") {
			return err
		}
	} else {
		return err
	}

	mountPoint := path.Join(d.options.mountPath, "graph", id)
	if parent == "" {
		_, err := zfs.CreateFilesystem(datasetName, map[string]string{
			"mountpoint": mountPoint,
		})
		return err
	}
	return cloneFilesystem(datasetName, d.ZfsPath(parent), mountPoint)
}

func (d *Driver) Remove(id string) error {
	dataset, err := zfs.GetDataset(d.ZfsPath(id))
	if dataset == nil {
		return err
	}

	return dataset.Destroy(zfs.DestroyRecursive)
}

func (d *Driver) Get(id, mountLabel string) (string, error) {
	dataset, err := zfs.GetDataset(d.ZfsPath(id))
	if err != nil {
		return "", err
	}
	return dataset.Mountpoint, nil
}

func (d *Driver) Put(id string) error {
	// FS is already mounted
	return nil
}

func (d *Driver) Exists(id string) bool {
	_, err := zfs.GetDataset(d.ZfsPath(id))
	return err == nil
}
<commit_msg>zfs: replace c for /proc/mounts parsing with go<commit_after>package zfs

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/graphdriver"
	"github.com/docker/docker/pkg/mount"
	"github.com/docker/docker/pkg/parsers"
	zfs "github.com/mistifyio/go-zfs"
)

type ZfsOptions struct {
	fsName    string
	mountPath string
}

func init() {
	graphdriver.Register("zfs", Init)
}

type Logger struct{}

func (*Logger) Log(cmd []string) {
	log.Debugf("[zfs] %s", strings.Join(cmd, " "))
}

func Init(base string, opt []string) (graphdriver.Driver, error) {
	var err error
	options, err := parseOptions(opt)
	if err != nil {
		return nil, err
	}
	options.mountPath = base

	rootdir := path.Dir(base)

	if options.fsName == "" {
		err = checkRootdirFs(rootdir)
		if err != nil {
			return nil, err
		}
	}

	if _, err := exec.LookPath("zfs"); err != nil {
		return nil, fmt.Errorf("zfs command is not available: %v", err)
	}

	file, err := os.OpenFile("/dev/zfs", os.O_RDWR, 600)
	if err != nil {
		return nil, fmt.Errorf("cannot open /dev/zfs: %v", err)
	}
	defer file.Close()

	if options.fsName == "" {
		options.fsName, err = lookupZfsDataset(rootdir)
		if err != nil {
			return nil, err
		}
	}

	zfs.SetLogger(new(Logger))

	dataset, err := zfs.GetDataset(options.fsName)
	if err != nil {
		return nil, fmt.Errorf("Cannot open %s", options.fsName)
	}

	d := &Driver{
		dataset: dataset,
		options: options,
	}
	return graphdriver.NaiveDiffDriver(d), nil
}

func parseOptions(opt []string) (ZfsOptions, error) {
	var options ZfsOptions
	options.fsName = ""
	for _, option := range opt {
		key, val, err := parsers.ParseKeyValueOpt(option)
		if err != nil {
			return options, err
		}
		key = strings.ToLower(key)
		switch key {
		case "zfs.fsname":
			options.fsName = val
		default:
			return options, fmt.Errorf("Unknown option %s", key)
		}
	}
	return options, nil
}

func checkRootdirFs(rootdir string) error {
	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return fmt.Errorf("Failed to access '%s': %s", rootdir, err)
	}

	if graphdriver.FsMagic(buf.Type) != graphdriver.FsMagicZfs {
		log.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir)
		return graphdriver.ErrPrerequisites
	}
	return nil
}

func lookupZfsDataset(rootdir string) (string, error) {
	var stat syscall.Stat_t
	if err := syscall.Stat(rootdir, &stat); err != nil {
		return "", fmt.Errorf("Failed to access '%s': %s", rootdir, err)
	}
	wantedDev := stat.Dev

	mounts, err := mount.GetMounts()
	if err != nil {
		return "", err
	}
	for _, m := range mounts {
		if err := syscall.Stat(m.Mountpoint, &stat); err != nil {
			log.Debugf("[zfs] failed to stat '%s' while scanning for zfs mount: %v", m.Mountpoint, err)
			continue // may fail on fuse file systems
		}

		if stat.Dev == wantedDev && m.Fstype == "zfs" {
			return m.Source, nil
		}
	}

	return "", fmt.Errorf("Failed to find zfs dataset mounted on '%s' in /proc/mounts", rootdir)
}

type Driver struct {
	dataset *zfs.Dataset
	options ZfsOptions
}

func (d *Driver) String() string {
	return "zfs"
}

func (d *Driver) Cleanup() error {
	return nil
}

func (d *Driver) Status() [][2]string {
	parts := strings.Split(d.dataset.Name, "/")
	pool, err := zfs.GetZpool(parts[0])

	var poolName, poolHealth string
	if err == nil {
		poolName = pool.Name
		poolHealth = pool.Health
	} else {
		poolName = fmt.Sprintf("error while getting pool information %v", err)
		poolHealth = "not available"
	}

	quota := "no"
	if d.dataset.Quota != 0 {
		quota = strconv.FormatUint(d.dataset.Quota, 10)
	}

	return [][2]string{
		{"Zpool", poolName},
		{"Zpool Health", poolHealth},
		{"Parent Dataset", d.dataset.Name},
		{"Space Used By Parent", strconv.FormatUint(d.dataset.Used, 10)},
		{"Space Available", strconv.FormatUint(d.dataset.Avail, 10)},
		{"Parent Quota", quota},
		{"Compression", d.dataset.Compression},
	}
}

func cloneFilesystem(id, parent, mountpoint string) error {
	parentDataset, err := zfs.GetDataset(parent)
	if err != nil {
		return err
	}
	snapshotName := fmt.Sprintf("%d", time.Now().Nanosecond())
	snapshot, err := parentDataset.Snapshot(snapshotName /*recursive */, false)
	if err != nil {
		return err
	}

	_, err = snapshot.Clone(id, map[string]string{
		"mountpoint": mountpoint,
	})
	if err != nil {
		snapshot.Destroy(zfs.DestroyDeferDeletion)
		return err
	}
	return snapshot.Destroy(zfs.DestroyDeferDeletion)
}

func (d *Driver) ZfsPath(id string) string {
	return d.options.fsName + "/" + id
}

func (d *Driver) Create(id string, parent string) error {
	datasetName := d.ZfsPath(id)
	dataset, err := zfs.GetDataset(datasetName)
	if err == nil {
		// cleanup existing dataset from an aborted build
		err := dataset.Destroy(zfs.DestroyRecursiveClones)
		if err != nil {
			log.Warnf("[zfs] failed to destroy dataset '%s': %v", dataset.Name, err)
		}
	} else if zfsError, ok := err.(*zfs.Error); ok {
		if !strings.HasSuffix(zfsError.Stderr, "dataset does not exist\n") {
			return err
		}
	} else {
		return err
	}

	mountPoint := path.Join(d.options.mountPath, "graph", id)
	if parent == "" {
		_, err := zfs.CreateFilesystem(datasetName, map[string]string{
			"mountpoint": mountPoint,
		})
		return err
	}
	return cloneFilesystem(datasetName, d.ZfsPath(parent), mountPoint)
}

func (d *Driver) Remove(id string) error {
	dataset, err := zfs.GetDataset(d.ZfsPath(id))
	if dataset == nil {
		return err
	}

	return dataset.Destroy(zfs.DestroyRecursive)
}

func (d *Driver) Get(id, mountLabel string) (string, error) {
	dataset, err := zfs.GetDataset(d.ZfsPath(id))
	if err != nil {
		return "", err
	}
	return dataset.Mountpoint, nil
}

func (d *Driver) Put(id string) error {
	// FS is already mounted
	return nil
}

func (d *Driver) Exists(id string) bool {
	_, err := zfs.GetDataset(d.ZfsPath(id))
	return err == nil
}
<|endoftext|>


<commit_before>package npc

import (
	"encoding/json"

	log "github.com/Sirupsen/logrus"
	"github.com/coreos/go-iptables/iptables"
	"k8s.io/client-go/pkg/api/unversioned"
	coreapi "k8s.io/client-go/pkg/api/v1"
	extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
	"k8s.io/client-go/pkg/types"
	"k8s.io/client-go/pkg/util/uuid"

	"github.com/weaveworks/weave/npc/ipset"
)

type ns struct {
	ipt *iptables.IPTables // interface to iptables
	ips ipset.Interface    // interface to ipset

	name      string                               // k8s Namespace name
	namespace *coreapi.Namespace                   // k8s Namespace object
	pods      map[types.UID]*coreapi.Pod           // k8s Pod objects by UID
	policies  map[types.UID]*extnapi.NetworkPolicy // k8s NetworkPolicy objects by UID

	uid     types.UID     // surrogate UID to own allPods selector
	allPods *selectorSpec // hash:ip ipset of all pod IPs in this namespace

	nsSelectors  *selectorSet
	podSelectors *selectorSet
	rules        *ruleSet
}

func newNS(name string, ipt *iptables.IPTables, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
	allPods, err := newSelectorSpec(&unversioned.LabelSelector{}, name, ipset.HashIP)
	if err != nil {
		return nil, err
	}

	ns := &ns{
		ipt:         ipt,
		ips:         ips,
		name:        name,
		pods:        make(map[types.UID]*coreapi.Pod),
		policies:    make(map[types.UID]*extnapi.NetworkPolicy),
		uid:         uuid.NewUUID(),
		allPods:     allPods,
		nsSelectors: nsSelectors,
		rules:       newRuleSet(ipt)}

	ns.podSelectors = newSelectorSet(ips, ns.onNewPodSelector)

	if err := ns.podSelectors.provision(ns.uid, nil, map[string]*selectorSpec{ns.allPods.key: ns.allPods}); err != nil {
		return nil, err
	}

	return ns, nil
}

func (ns *ns) empty() bool {
	return len(ns.pods) == 0 && len(ns.policies) == 0 && ns.namespace == nil
}

func (ns *ns) destroy() error {
	if err := ns.podSelectors.deprovision(ns.uid, map[string]*selectorSpec{ns.allPods.key: ns.allPods}, nil); err != nil {
		return err
	}
	return nil
}

func (ns *ns) onNewPodSelector(selector *selector) error {
	for _, pod := range ns.pods {
		if hasIP(pod) {
			if selector.matches(pod.ObjectMeta.Labels) {
				if err := selector.addEntry(pod.Status.PodIP); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

func (ns *ns) addPod(obj *coreapi.Pod) error {
	ns.pods[obj.ObjectMeta.UID] = obj

	if !hasIP(obj) {
		return nil
	}

	return ns.podSelectors.addToMatching(obj.ObjectMeta.Labels, obj.Status.PodIP)
}

func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
	delete(ns.pods, oldObj.ObjectMeta.UID)
	ns.pods[newObj.ObjectMeta.UID] = newObj

	if !hasIP(oldObj) && !hasIP(newObj) {
		return nil
	}

	if hasIP(oldObj) && !hasIP(newObj) {
		return ns.podSelectors.delFromMatching(oldObj.ObjectMeta.Labels, oldObj.Status.PodIP)
	}

	if !hasIP(oldObj) && hasIP(newObj) {
		return ns.podSelectors.addToMatching(newObj.ObjectMeta.Labels, newObj.Status.PodIP)
	}

	if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) ||
		oldObj.Status.PodIP != newObj.Status.PodIP {

		for _, ps := range ns.podSelectors.entries {
			oldMatch := ps.matches(oldObj.ObjectMeta.Labels)
			newMatch := ps.matches(newObj.ObjectMeta.Labels)
			if oldMatch == newMatch && oldObj.Status.PodIP == newObj.Status.PodIP {
				continue
			}
			if oldMatch {
				if err := ps.delEntry(oldObj.Status.PodIP); err != nil {
					return err
				}
			}
			if newMatch {
				if err := ps.addEntry(newObj.Status.PodIP); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (ns *ns) deletePod(obj *coreapi.Pod) error {
	delete(ns.pods, obj.ObjectMeta.UID)

	if !hasIP(obj) {
		return nil
	}

	return ns.podSelectors.delFromMatching(obj.ObjectMeta.Labels, obj.Status.PodIP)
}

func (ns *ns) addNetworkPolicy(obj *extnapi.NetworkPolicy) error {
	ns.policies[obj.ObjectMeta.UID] = obj

	// Analyse policy, determine which rules and ipsets are required
	rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
	if err != nil {
		return err
	}

	// Provision required resources in dependency order
	if err := ns.nsSelectors.provision(obj.ObjectMeta.UID, nil, nsSelectors); err != nil {
		return err
	}
	if err := ns.podSelectors.provision(obj.ObjectMeta.UID, nil, podSelectors); err != nil {
		return err
	}
	if err := ns.rules.provision(obj.ObjectMeta.UID, nil, rules); err != nil {
		return err
	}

	return nil
}

func (ns *ns) updateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error {
	delete(ns.policies, oldObj.ObjectMeta.UID)
	ns.policies[newObj.ObjectMeta.UID] = newObj

	// Analyse the old and the new policy so we can determine differences
	oldRules, oldNsSelectors, oldPodSelectors, err := ns.analysePolicy(oldObj)
	if err != nil {
		return err
	}
	newRules, newNsSelectors, newPodSelectors, err := ns.analysePolicy(newObj)
	if err != nil {
		return err
	}

	// Deprovision unused and provision newly required resources in dependency order
	if err := ns.rules.deprovision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
		return err
	}
	if err := ns.nsSelectors.deprovision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
		return err
	}
	if err := ns.podSelectors.deprovision(oldObj.ObjectMeta.UID, oldPodSelectors, newPodSelectors); err != nil {
		return err
	}
	if err := ns.nsSelectors.provision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
		return err
	}
	if err := ns.podSelectors.provision(oldObj.ObjectMeta.UID, oldPodSelectors, newNsSelectors); err != nil {
		return err
	}
	if err := ns.rules.provision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
		return err
	}

	return nil
}

func (ns *ns) deleteNetworkPolicy(obj *extnapi.NetworkPolicy) error {
	delete(ns.policies, obj.ObjectMeta.UID)

	// Analyse network policy to free resources
	rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
	if err != nil {
		return err
	}

	// Deprovision unused resources in dependency order
	if err := ns.rules.deprovision(obj.ObjectMeta.UID, rules, nil); err != nil {
		return err
	}
	if err := ns.nsSelectors.deprovision(obj.ObjectMeta.UID, nsSelectors, nil); err != nil {
		return err
	}
	if err := ns.podSelectors.deprovision(obj.ObjectMeta.UID, podSelectors, nil); err != nil {
		return err
	}

	return nil
}

func bypassRule(nsIpsetName ipset.Name) []string {
	return []string{"-m", "set", "--match-set", string(nsIpsetName), "dst", "-j", "ACCEPT"}
}

func (ns *ns) ensureBypassRule(nsIpsetName ipset.Name) error {
	return ns.ipt.Append(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName)...)
}

func (ns *ns) deleteBypassRule(nsIpsetName ipset.Name) error {
	return ns.ipt.Delete(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName)...)
}

func (ns *ns) addNamespace(obj *coreapi.Namespace) error {
	ns.namespace = obj

	// Insert a rule to bypass policies if namespace is DefaultAllow
	if !isDefaultDeny(obj) {
		return ns.ensureBypassRule(ns.allPods.ipsetName)
	}

	// Add namespace ipset to matching namespace selectors
	return ns.nsSelectors.addToMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
}

func (ns *ns) updateNamespace(oldObj, newObj *coreapi.Namespace) error {
	ns.namespace = newObj

	// Update bypass rule if ingress default has changed
	oldDefaultDeny := isDefaultDeny(oldObj)
	newDefaultDeny := isDefaultDeny(newObj)

	if oldDefaultDeny != newDefaultDeny {
		if oldDefaultDeny {
			return ns.ensureBypassRule(ns.allPods.ipsetName)
		}
		if newDefaultDeny {
			return ns.deleteBypassRule(ns.allPods.ipsetName)
		}
	}

	// Re-evaluate namespace selector membership if labels have changed
	if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) {
		for _, selector := range ns.nsSelectors.entries {
			oldMatch := selector.matches(oldObj.ObjectMeta.Labels)
			newMatch := selector.matches(newObj.ObjectMeta.Labels)
			if oldMatch == newMatch {
				continue
			}
			if oldMatch {
				if err := selector.delEntry(string(ns.allPods.ipsetName)); err != nil {
					return err
				}
			}
			if newMatch {
				if err := selector.addEntry(string(ns.allPods.ipsetName)); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (ns *ns) deleteNamespace(obj *coreapi.Namespace) error {
	ns.namespace = nil

	// Remove bypass rule
	if !isDefaultDeny(obj) {
		return ns.deleteBypassRule(ns.allPods.ipsetName)
	}

	// Remove namespace ipset from any matching namespace selectors
	return ns.nsSelectors.delFromMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
}

func hasIP(pod *coreapi.Pod) bool {
	// Ensure pod has an IP address and isn't sharing the host network namespace
	return len(pod.Status.PodIP) > 0 && !pod.Spec.HostNetwork
}

func equals(a, b map[string]string) bool {
	if len(a) != len(b) {
		return false
	}
	for ak, av := range a {
		if b[ak] != av {
			return false
		}
	}
	return true
}

func isDefaultDeny(namespace *coreapi.Namespace) bool {
	nnpJson, found := namespace.ObjectMeta.Annotations["net.beta.kubernetes.io/network-policy"]
	if !found {
		return false
	}

	var nnp NamespaceNetworkPolicy
	if err := json.Unmarshal([]byte(nnpJson), &nnp); err != nil {
		log.Warn("Ignoring network policy annotation: unmarshal failed:", err)
		// If we can't understand the annotation, behave as if it isn't present
		return false
	}

	return nnp.Ingress != nil &&
		nnp.Ingress.Isolation != nil &&
		*(nnp.Ingress.Isolation) == DefaultDeny
}
<commit_msg>Only look at IP addresses on pods that haven't finished<commit_after>package npc

import (
	"encoding/json"

	log "github.com/Sirupsen/logrus"
	"github.com/coreos/go-iptables/iptables"
	"k8s.io/client-go/pkg/api/unversioned"
	coreapi "k8s.io/client-go/pkg/api/v1"
	extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
	"k8s.io/client-go/pkg/types"
	"k8s.io/client-go/pkg/util/uuid"

	"github.com/weaveworks/weave/npc/ipset"
)

type ns struct {
	ipt *iptables.IPTables // interface to iptables
	ips ipset.Interface    // interface to ipset

	name      string                               // k8s Namespace name
	namespace *coreapi.Namespace                   // k8s Namespace object
	pods      map[types.UID]*coreapi.Pod           // k8s Pod objects by UID
	policies  map[types.UID]*extnapi.NetworkPolicy // k8s NetworkPolicy objects by UID

	uid     types.UID     // surrogate UID to own allPods selector
	allPods *selectorSpec // hash:ip ipset of all pod IPs in this namespace

	nsSelectors  *selectorSet
	podSelectors *selectorSet
	rules        *ruleSet
}

func newNS(name string, ipt *iptables.IPTables, ips ipset.Interface, nsSelectors *selectorSet) (*ns, error) {
	allPods, err := newSelectorSpec(&unversioned.LabelSelector{}, name, ipset.HashIP)
	if err != nil {
		return nil, err
	}

	ns := &ns{
		ipt:         ipt,
		ips:         ips,
		name:        name,
		pods:        make(map[types.UID]*coreapi.Pod),
		policies:    make(map[types.UID]*extnapi.NetworkPolicy),
		uid:         uuid.NewUUID(),
		allPods:     allPods,
		nsSelectors: nsSelectors,
		rules:       newRuleSet(ipt)}

	ns.podSelectors = newSelectorSet(ips, ns.onNewPodSelector)

	if err := ns.podSelectors.provision(ns.uid, nil, map[string]*selectorSpec{ns.allPods.key: ns.allPods}); err != nil {
		return nil, err
	}

	return ns, nil
}

func (ns *ns) empty() bool {
	return len(ns.pods) == 0 && len(ns.policies) == 0 && ns.namespace == nil
}

func (ns *ns) destroy() error {
	if err := ns.podSelectors.deprovision(ns.uid, map[string]*selectorSpec{ns.allPods.key: ns.allPods}, nil); err != nil {
		return err
	}
	return nil
}

func (ns *ns) onNewPodSelector(selector *selector) error {
	for _, pod := range ns.pods {
		if hasIP(pod) {
			if selector.matches(pod.ObjectMeta.Labels) {
				if err := selector.addEntry(pod.Status.PodIP); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

func (ns *ns) addPod(obj *coreapi.Pod) error {
	ns.pods[obj.ObjectMeta.UID] = obj

	if !hasIP(obj) {
		return nil
	}

	return ns.podSelectors.addToMatching(obj.ObjectMeta.Labels, obj.Status.PodIP)
}

func (ns *ns) updatePod(oldObj, newObj *coreapi.Pod) error {
	delete(ns.pods, oldObj.ObjectMeta.UID)
	ns.pods[newObj.ObjectMeta.UID] = newObj

	if !hasIP(oldObj) && !hasIP(newObj) {
		return nil
	}

	if hasIP(oldObj) && !hasIP(newObj) {
		return ns.podSelectors.delFromMatching(oldObj.ObjectMeta.Labels, oldObj.Status.PodIP)
	}

	if !hasIP(oldObj) && hasIP(newObj) {
		return ns.podSelectors.addToMatching(newObj.ObjectMeta.Labels, newObj.Status.PodIP)
	}

	if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) ||
		oldObj.Status.PodIP != newObj.Status.PodIP {

		for _, ps := range ns.podSelectors.entries {
			oldMatch := ps.matches(oldObj.ObjectMeta.Labels)
			newMatch := ps.matches(newObj.ObjectMeta.Labels)
			if oldMatch == newMatch && oldObj.Status.PodIP == newObj.Status.PodIP {
				continue
			}
			if oldMatch {
				if err := ps.delEntry(oldObj.Status.PodIP); err != nil {
					return err
				}
			}
			if newMatch {
				if err := ps.addEntry(newObj.Status.PodIP); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (ns *ns) deletePod(obj *coreapi.Pod) error {
	delete(ns.pods, obj.ObjectMeta.UID)

	if !hasIP(obj) {
		return nil
	}

	return ns.podSelectors.delFromMatching(obj.ObjectMeta.Labels, obj.Status.PodIP)
}

func (ns *ns) addNetworkPolicy(obj *extnapi.NetworkPolicy) error {
	ns.policies[obj.ObjectMeta.UID] = obj

	// Analyse policy, determine which rules and ipsets are required
	rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
	if err != nil {
		return err
	}

	// Provision required resources in dependency order
	if err := ns.nsSelectors.provision(obj.ObjectMeta.UID, nil, nsSelectors); err != nil {
		return err
	}
	if err := ns.podSelectors.provision(obj.ObjectMeta.UID, nil, podSelectors); err != nil {
		return err
	}
	if err := ns.rules.provision(obj.ObjectMeta.UID, nil, rules); err != nil {
		return err
	}

	return nil
}

func (ns *ns) updateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error {
	delete(ns.policies, oldObj.ObjectMeta.UID)
	ns.policies[newObj.ObjectMeta.UID] = newObj

	// Analyse the old and the new policy so we can determine differences
	oldRules, oldNsSelectors, oldPodSelectors, err := ns.analysePolicy(oldObj)
	if err != nil {
		return err
	}
	newRules, newNsSelectors, newPodSelectors, err := ns.analysePolicy(newObj)
	if err != nil {
		return err
	}

	// Deprovision unused and provision newly required resources in dependency order
	if err := ns.rules.deprovision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
		return err
	}
	if err := ns.nsSelectors.deprovision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
		return err
	}
	if err := ns.podSelectors.deprovision(oldObj.ObjectMeta.UID, oldPodSelectors, newPodSelectors); err != nil {
		return err
	}
	if err := ns.nsSelectors.provision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
		return err
	}
	if err := ns.podSelectors.provision(oldObj.ObjectMeta.UID, oldPodSelectors, newNsSelectors); err != nil {
		return err
	}
	if err := ns.rules.provision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
		return err
	}

	return nil
}

func (ns *ns) deleteNetworkPolicy(obj *extnapi.NetworkPolicy) error {
	delete(ns.policies, obj.ObjectMeta.UID)

	// Analyse network policy to free resources
	rules, nsSelectors, podSelectors, err := ns.analysePolicy(obj)
	if err != nil {
		return err
	}

	// Deprovision unused resources in dependency order
	if err := ns.rules.deprovision(obj.ObjectMeta.UID, rules, nil); err != nil {
		return err
	}
	if err := ns.nsSelectors.deprovision(obj.ObjectMeta.UID, nsSelectors, nil); err != nil {
		return err
	}
	if err := ns.podSelectors.deprovision(obj.ObjectMeta.UID, podSelectors, nil); err != nil {
		return err
	}

	return nil
}

func bypassRule(nsIpsetName ipset.Name) []string {
	return []string{"-m", "set", "--match-set", string(nsIpsetName), "dst", "-j", "ACCEPT"}
}

func (ns *ns) ensureBypassRule(nsIpsetName ipset.Name) error {
	return ns.ipt.Append(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName)...)
}

func (ns *ns) deleteBypassRule(nsIpsetName ipset.Name) error {
	return ns.ipt.Delete(TableFilter, DefaultChain, bypassRule(ns.allPods.ipsetName)...)
}

func (ns *ns) addNamespace(obj *coreapi.Namespace) error {
	ns.namespace = obj

	// Insert a rule to bypass policies if namespace is DefaultAllow
	if !isDefaultDeny(obj) {
		return ns.ensureBypassRule(ns.allPods.ipsetName)
	}

	// Add namespace ipset to matching namespace selectors
	return ns.nsSelectors.addToMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
}

func (ns *ns) updateNamespace(oldObj, newObj *coreapi.Namespace) error {
	ns.namespace = newObj

	// Update bypass rule if ingress default has changed
	oldDefaultDeny := isDefaultDeny(oldObj)
	newDefaultDeny := isDefaultDeny(newObj)

	if oldDefaultDeny != newDefaultDeny {
		if oldDefaultDeny {
			return ns.ensureBypassRule(ns.allPods.ipsetName)
		}
		if newDefaultDeny {
			return ns.deleteBypassRule(ns.allPods.ipsetName)
		}
	}

	// Re-evaluate namespace selector membership if labels have changed
	if !equals(oldObj.ObjectMeta.Labels, newObj.ObjectMeta.Labels) {
		for _, selector := range ns.nsSelectors.entries {
			oldMatch := selector.matches(oldObj.ObjectMeta.Labels)
			newMatch := selector.matches(newObj.ObjectMeta.Labels)
			if oldMatch == newMatch {
				continue
			}
			if oldMatch {
				if err := selector.delEntry(string(ns.allPods.ipsetName)); err != nil {
					return err
				}
			}
			if newMatch {
				if err := selector.addEntry(string(ns.allPods.ipsetName)); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (ns *ns) deleteNamespace(obj *coreapi.Namespace) error {
	ns.namespace = nil

	// Remove bypass rule
	if !isDefaultDeny(obj) {
		return ns.deleteBypassRule(ns.allPods.ipsetName)
	}

	// Remove namespace ipset from any matching namespace selectors
	return ns.nsSelectors.delFromMatching(obj.ObjectMeta.Labels, string(ns.allPods.ipsetName))
}

func hasIP(pod *coreapi.Pod) bool {
	// Ensure pod isn't dead, has an IP address and isn't sharing the host network namespace
	return pod.Status.Phase != "Succeeded" && pod.Status.Phase != "Failed" &&
		len(pod.Status.PodIP) > 0 && !pod.Spec.HostNetwork
}

func equals(a, b map[string]string) bool {
	if len(a) != len(b) {
		return false
	}
	for ak, av := range a {
		if b[ak] != av {
			return false
		}
	}
	return true
}

func isDefaultDeny(namespace *coreapi.Namespace) bool {
	nnpJson, found := namespace.ObjectMeta.Annotations["net.beta.kubernetes.io/network-policy"]
	if !found {
		return false
	}

	var nnp NamespaceNetworkPolicy
	if err := json.Unmarshal([]byte(nnpJson), &nnp); err != nil {
		log.Warn("Ignoring network policy annotation: unmarshal failed:", err)
		// If we can't understand the annotation, behave as if it isn't present
		return false
	}

	return nnp.Ingress != nil &&
		nnp.Ingress.Isolation != nil &&
		*(nnp.Ingress.Isolation) == DefaultDeny
}
<|endoftext|>


<commit_before>package system

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/command/container"
	"github.com/docker/cli/cli/command/image"
	"github.com/docker/cli/cli/command/network"
	"github.com/docker/cli/cli/command/volume"
	"github.com/docker/cli/opts"
	"github.com/docker/docker/api/types/versions"
	units "github.com/docker/go-units"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

type pruneOptions struct {
	force           bool
	all             bool
	pruneBuildCache bool
	pruneVolumes    bool
	filter          opts.FilterOpt
}

// newPruneCommand creates a new cobra.Command for `docker prune`
func newPruneCommand(dockerCli command.Cli) *cobra.Command {
	options := pruneOptions{filter: opts.NewFilterOpt(), pruneBuildCache: true}

	cmd := &cobra.Command{
		Use:   "prune [OPTIONS]",
		Short: "Remove unused data",
		Args:  cli.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runPrune(dockerCli, options)
		},
		Tags: map[string]string{"version": "1.25"},
	}

	flags := cmd.Flags()
	flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
	flags.BoolVarP(&options.all, "all", "a", false, "Remove all unused images not just dangling ones")
	flags.BoolVar(&options.pruneVolumes, "volumes", false, "Prune volumes")
	flags.Var(&options.filter, "filter", "Provide filter values (e.g. 'label=<key>=<value>')")
	// "filter" flag is available in 1.28 (docker 17.04) and up
	flags.SetAnnotation("filter", "version", []string{"1.28"})

	return cmd
}

const confirmationTemplate = `WARNING! This will remove:
{{- range $_, $warning := . }}
        - {{ $warning }}
{{- end }}
Are you sure you want to continue?`

// runBuildCachePrune executes a prune command for build cache
func runBuildCachePrune(dockerCli command.Cli, _ opts.FilterOpt) (uint64, string, error) {
	report, err := dockerCli.Client().BuildCachePrune(context.Background())
	if err != nil {
		return 0, "", err
	}
	return report.SpaceReclaimed, "", nil
}

func runPrune(dockerCli command.Cli, options pruneOptions) error {
	if versions.LessThan(dockerCli.Client().ClientVersion(), "1.31") {
		options.pruneBuildCache = false
	}
	if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), confirmationMessage(options)) {
		return nil
	}
	imagePrune := func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error) {
		return image.RunPrune(dockerCli, options.all, options.filter)
	}
	pruneFuncs := []func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error){
		container.RunPrune,
		network.RunPrune,
	}
	if options.pruneVolumes {
		pruneFuncs = append(pruneFuncs, volume.RunPrune)
	}
	pruneFuncs = append(pruneFuncs, imagePrune)
	if options.pruneBuildCache {
		pruneFuncs = append(pruneFuncs, runBuildCachePrune)
	}

	var spaceReclaimed uint64
	for _, pruneFn := range pruneFuncs {
		spc, output, err := pruneFn(dockerCli, options.filter)
		if err != nil {
			return err
		}
		spaceReclaimed += spc
		if output != "" {
			fmt.Fprintln(dockerCli.Out(), output)
		}
	}

	fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))

	return nil
}

// confirmationMessage constructs a confirmation message that depends on the cli options.
func confirmationMessage(options pruneOptions) string {
	t := template.Must(template.New("confirmation message").Parse(confirmationTemplate))

	warnings := []string{
		"all stopped containers",
		"all networks not used by at least one container",
	}
	if options.pruneVolumes {
		warnings = append(warnings, "all volumes not used by at least one container")
	}
	if options.all {
		warnings = append(warnings, "all images without at least one container associated to them")
	} else {
		warnings = append(warnings, "all dangling images")
	}
	if options.pruneBuildCache {
		warnings = append(warnings, "all build cache")
	}

	var buffer bytes.Buffer
	t.Execute(&buffer, &warnings)
	return buffer.String()
}
<commit_msg>Error if "until" filter is combined with "--volumes" on system prune<commit_after>package system

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/command/container"
	"github.com/docker/cli/cli/command/image"
	"github.com/docker/cli/cli/command/network"
	"github.com/docker/cli/cli/command/volume"
	"github.com/docker/cli/opts"
	"github.com/docker/docker/api/types/versions"
	units "github.com/docker/go-units"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

type pruneOptions struct {
	force           bool
	all             bool
	pruneBuildCache bool
	pruneVolumes    bool
	filter          opts.FilterOpt
}

// newPruneCommand creates a new cobra.Command for `docker prune`
func newPruneCommand(dockerCli command.Cli) *cobra.Command {
	options := pruneOptions{filter: opts.NewFilterOpt(), pruneBuildCache: true}

	cmd := &cobra.Command{
		Use:   "prune [OPTIONS]",
		Short: "Remove unused data",
		Args:  cli.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return runPrune(dockerCli, options)
		},
		Tags: map[string]string{"version": "1.25"},
	}

	flags := cmd.Flags()
	flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
	flags.BoolVarP(&options.all, "all", "a", false, "Remove all unused images not just dangling ones")
	flags.BoolVar(&options.pruneVolumes, "volumes", false, "Prune volumes")
	flags.Var(&options.filter, "filter", "Provide filter values (e.g. 'label=<key>=<value>')")
	// "filter" flag is available in 1.28 (docker 17.04) and up
	flags.SetAnnotation("filter", "version", []string{"1.28"})

	return cmd
}

const confirmationTemplate = `WARNING! This will remove:
{{- range $_, $warning := . }}
        - {{ $warning }}
{{- end }}
Are you sure you want to continue?`

// runBuildCachePrune executes a prune command for build cache
func runBuildCachePrune(dockerCli command.Cli, _ opts.FilterOpt) (uint64, string, error) {
	report, err := dockerCli.Client().BuildCachePrune(context.Background())
	if err != nil {
		return 0, "", err
	}
	return report.SpaceReclaimed, "", nil
}

func runPrune(dockerCli command.Cli, options pruneOptions) error {
	// TODO version this once "until" filter is supported for volumes
	if options.pruneVolumes && options.filter.Value().Include("until") {
		return fmt.Errorf(`ERROR: The "until" filter is not supported with "--volumes"`)
	}
	if versions.LessThan(dockerCli.Client().ClientVersion(), "1.31") {
		options.pruneBuildCache = false
	}
	if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), confirmationMessage(options)) {
		return nil
	}
	imagePrune := func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error) {
		return image.RunPrune(dockerCli, options.all, options.filter)
	}
	pruneFuncs := []func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error){
		container.RunPrune,
		network.RunPrune,
	}
	if options.pruneVolumes {
		pruneFuncs = append(pruneFuncs, volume.RunPrune)
	}
	pruneFuncs = append(pruneFuncs, imagePrune)
	if options.pruneBuildCache {
		pruneFuncs = append(pruneFuncs, runBuildCachePrune)
	}

	var spaceReclaimed uint64
	for _, pruneFn := range pruneFuncs {
		spc, output, err := pruneFn(dockerCli, options.filter)
		if err != nil {
			return err
		}
		spaceReclaimed += spc
		if output != "" {
			fmt.Fprintln(dockerCli.Out(), output)
		}
	}

	fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))

	return nil
}

// confirmationMessage constructs a confirmation message that depends on the cli options.
func confirmationMessage(options pruneOptions) string {
	t := template.Must(template.New("confirmation message").Parse(confirmationTemplate))

	warnings := []string{
		"all stopped containers",
		"all networks not used by at least one container",
	}
	if options.pruneVolumes {
		warnings = append(warnings, "all volumes not used by at least one container")
	}
	if options.all {
		warnings = append(warnings, "all images without at least one container associated to them")
	} else {
		warnings = append(warnings, "all dangling images")
	}
	if options.pruneBuildCache {
		warnings = append(warnings, "all build cache")
	}

	var buffer bytes.Buffer
	t.Execute(&buffer, &warnings)
	return buffer.String()
}
<|endoftext|>


<commit_before>package version

import (
	"testing"

	"github.com/cloudflare/cfssl/cli"
)

func TestVersionString(t *testing.T) {
	version := versionString()
	if version != "1.2.0" {
		t.Fatal("version string is not returned correctly")
	}
}

func TestVersionMain(t *testing.T) {
	args := []string{"cfssl", "version"}
	err := versionMain(args, cli.Config{})
	if err != nil {
		t.Fatal("version main failed")
	}
}
<commit_msg>Update version test.<commit_after>package version

import (
	"testing"

	"github.com/cloudflare/cfssl/cli"
)

func TestVersionString(t *testing.T) {
	version := versionString()
	if version != "1.3.0" {
		t.Fatal("version string is not returned correctly")
	}
}

func TestVersionMain(t *testing.T) {
	args := []string{"cfssl", "version"}
	err := versionMain(args, cli.Config{})
	if err != nil {
		t.Fatal("version main failed")
	}
}
<|endoftext|>