<commit_before>package core

import (
	"fmt"

	"github.com/af83/edwig/audit"
	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type SubscriptionRequestDispatcher interface {
	Dispatch(*siri.XMLSubscriptionRequest) (*siri.SIRISubscriptionResponse, error)
	CancelSubscription(*siri.XMLDeleteSubscriptionRequest) *siri.SIRIDeleteSubscriptionResponse
}

type SIRISubscriptionRequestDispatcherFactory struct{}

type SIRISubscriptionRequestDispatcher struct {
	model.ClockConsumer
	model.UUIDConsumer

	siriConnector

	xmlRequest siri.XMLSubscriptionRequest
}

func (factory *SIRISubscriptionRequestDispatcherFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_url")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_credential")
	return ok
}

func (factory *SIRISubscriptionRequestDispatcherFactory) CreateConnector(partner *Partner) Connector {
	return NewSIRISubscriptionRequestDispatcher(partner)
}

func NewSIRISubscriptionRequestDispatcher(partner *Partner) *SIRISubscriptionRequestDispatcher {
	siriSubscriptionRequest := &SIRISubscriptionRequestDispatcher{}
	siriSubscriptionRequest.partner = partner

	return siriSubscriptionRequest
}

func (connector *SIRISubscriptionRequestDispatcher) Dispatch(request *siri.XMLSubscriptionRequest) (*siri.SIRISubscriptionResponse, error) {
	logStashEvent := connector.newLogStashEvent()

	logXMLSubscriptionRequest(logStashEvent, request)

	response := siri.SIRISubscriptionResponse{
		Address:            connector.Partner().Address(),
		ResponderRef:       connector.SIRIPartner().RequestorRef(),
		ResponseTimestamp:  connector.Clock().Now(),
		RequestMessageRef:  request.MessageIdentifier(),
		ServiceStartedTime: connector.Partner().Referential().StartedAt(),
	}

	if len(request.XMLSubscriptionGMEntries()) > 0 {
		gmbc, ok := connector.Partner().Connector(SIRI_GENERAL_MESSAGE_SUBSCRIPTION_BROADCASTER)
		if !ok {
			return nil, fmt.Errorf("No GeneralMessageSubscriptionBroadcaster Connector")
		}
		for _, sgm := range gmbc.(*SIRIGeneralMessageSubscriptionBroadcaster).HandleSubscriptionRequest(request) {
			response.ResponseStatus = append(response.ResponseStatus, sgm)
		}
		logSIRISubscriptionResponse(logStashEvent, &response, "GeneralMessageSubscriptionBroadcaster")
		audit.CurrentLogStash().WriteEvent(logStashEvent)
		return &response, nil
	}

	if len(request.XMLSubscriptionSMEntries()) > 0 {
		smbc, ok := connector.Partner().Connector(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER)
		if !ok {
			return nil, fmt.Errorf("No StopMonitoringSubscriptionBroadcaster Connector")
		}
		for _, smr := range smbc.(*SIRIStopMonitoringSubscriptionBroadcaster).HandleSubscriptionRequest(request) {
			response.ResponseStatus = append(response.ResponseStatus, smr)
		}
		logSIRISubscriptionResponse(logStashEvent, &response, "StopMonitoringSubscriptionBroadcaster")
		audit.CurrentLogStash().WriteEvent(logStashEvent)
		return &response, nil
	}

	if len(request.XMLSubscriptionETTEntries()) > 0 {
		smbc, ok := connector.Partner().Connector(SIRI_ESTIMATED_TIMETABLE_SUBSCRIPTION_BROADCASTER)
		if !ok {
			return nil, fmt.Errorf("No EstimatedTimeTableSubscriptionBroadcaster Connector")
		}
		for _, smr := range smbc.(*SIRIEstimatedTimeTableSubscriptionBroadcaster).HandleSubscriptionRequest(request) {
			response.ResponseStatus = append(response.ResponseStatus, smr)
		}
		logSIRISubscriptionResponse(logStashEvent, &response, "EstimatedTimeTableSubscriptionBroadcaster")
		audit.CurrentLogStash().WriteEvent(logStashEvent)
		return &response, nil
	}

	return nil, fmt.Errorf("Subscription not supported")
}

func (connector *SIRISubscriptionRequestDispatcher) CancelSubscription(r *siri.XMLDeleteSubscriptionRequest) *siri.SIRIDeleteSubscriptionResponse {
	logStashEvent := connector.newLogStashEvent()

	logXMLCancelSubscriptionRequest(logStashEvent, r)

	currentTime := connector.Clock().Now()
	resp := &siri.SIRIDeleteSubscriptionResponse{
		ResponderRef:      connector.SIRIPartner().RequestorRef(),
		RequestMessageRef: r.MessageIdentifier(),
		ResponseTimestamp: currentTime,
	}

	defer func() {
		logSIRICancelSubscriptionResponse(logStashEvent, resp)
		audit.CurrentLogStash().WriteEvent(logStashEvent)
	}()

	if r.CancelAll() {
		for _, subscription := range connector.Partner().Subscriptions().FindBroadcastSubscriptions() {
			responseStatus := &siri.SIRITerminationResponseStatus{
				SubscriberRef:     r.RequestorRef(),
				SubscriptionRef:   subscription.ExternalId(),
				ResponseTimestamp: currentTime,
				Status:            true,
			}
			resp.ResponseStatus = append(resp.ResponseStatus, responseStatus)
		}
		connector.Partner().CancelBroadcastSubscriptions()
		return resp
	}

	responseStatus := &siri.SIRITerminationResponseStatus{
		SubscriberRef:     r.RequestorRef(),
		SubscriptionRef:   r.SubscriptionRef(),
		ResponseTimestamp: currentTime,
	}

	resp.ResponseStatus = append(resp.ResponseStatus, responseStatus)

	sub, ok := connector.Partner().Subscriptions().FindByExternalId(r.SubscriptionRef())
	if !ok {
		logger.Log.Debugf("Could not Unsubscribe to unknow subscription %v", r.SubscriptionRef())

		responseStatus.ErrorType = "InvalidDataReferencesError"
		responseStatus.ErrorText = fmt.Sprintf("Subscription not found: '%s'", r.SubscriptionRef())
		return resp
	}

	responseStatus.Status = true

	sub.Delete()
	return resp
}

func (connector *SIRISubscriptionRequestDispatcher) newLogStashEvent() audit.LogStashEvent {
	return connector.partner.NewLogStashEvent()
}

func logXMLSubscriptionRequest(logStashEvent audit.LogStashEvent, request *siri.XMLSubscriptionRequest) {
	logStashEvent["consumerAddress"] = request.ConsumerAddress()
	logStashEvent["messageIdentifier"] = request.MessageIdentifier()
	logStashEvent["requestorRef"] = request.RequestorRef()
	logStashEvent["requestTimestamp"] = request.RequestTimestamp().String()
	logStashEvent["requestXML"] = request.RawXML()
}

func logSIRISubscriptionResponse(logStashEvent audit.LogStashEvent, response *siri.SIRISubscriptionResponse, connector string) {
	logStashEvent["connector"] = connector
	logStashEvent["type"] = "subscriptionRequest"
	logStashEvent["address"] = response.Address
	logStashEvent["responderRef"] = response.ResponderRef
	logStashEvent["requestMessageRef"] = response.RequestMessageRef
	logStashEvent["responseTimestamp"] = response.ResponseTimestamp.String()
	logStashEvent["serviceStartedTime"] = response.ServiceStartedTime.String()
	xml, err := response.BuildXML()
	if err != nil {
		logStashEvent["responseXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["responseXML"] = xml
}

func logXMLCancelSubscriptionRequest(logStashEvent audit.LogStashEvent, request *siri.XMLDeleteSubscriptionRequest) {
	logStashEvent["messageIdentifier"] = request.MessageIdentifier()
	logStashEvent["requestorRef"] = request.RequestorRef()
	logStashEvent["requestTimestamp"] = request.RequestTimestamp().String()
	if request.CancelAll() {
		logStashEvent["subscriptionToCancel"] = "All"
	} else {
		logStashEvent["subscriptionToCancel"] = request.SubscriptionRef()
	}
	logStashEvent["requestXML"] = request.RawXML()
}

func logSIRICancelSubscriptionResponse(logStashEvent audit.LogStashEvent, response *siri.SIRIDeleteSubscriptionResponse) {
	logStashEvent["responderRef"] = response.ResponderRef
	logStashEvent["requestMessageRef"] = response.RequestMessageRef
	logStashEvent["responseTimestamp"] = response.ResponseTimestamp.String()
	xml, err := response.BuildXML()
	if err != nil {
		logStashEvent["responseXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["responseXML"] = xml
}
<commit_msg>Wrong type, corrected<commit_after>package core

import (
	"fmt"

	"github.com/af83/edwig/audit"
	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type SubscriptionRequestDispatcher interface {
	Dispatch(*siri.XMLSubscriptionRequest) (*siri.SIRISubscriptionResponse, error)
	CancelSubscription(*siri.XMLDeleteSubscriptionRequest) *siri.SIRIDeleteSubscriptionResponse
}

type SIRISubscriptionRequestDispatcherFactory struct{}

type SIRISubscriptionRequestDispatcher struct {
	model.ClockConsumer
	model.UUIDConsumer

	siriConnector

	xmlRequest siri.XMLSubscriptionRequest
}

func (factory *SIRISubscriptionRequestDispatcherFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_url")
	ok = ok && apiPartner.ValidatePresenceOfSetting("remote_credential")
	return ok
}

func (factory *SIRISubscriptionRequestDispatcherFactory) CreateConnector(partner *Partner) Connector {
	return NewSIRISubscriptionRequestDispatcher(partner)
}

func NewSIRISubscriptionRequestDispatcher(partner *Partner) *SIRISubscriptionRequestDispatcher {
	siriSubscriptionRequest := &SIRISubscriptionRequestDispatcher{}
	siriSubscriptionRequest.partner = partner

	return siriSubscriptionRequest
}

func (connector *SIRISubscriptionRequestDispatcher) Dispatch(request *siri.XMLSubscriptionRequest) (*siri.SIRISubscriptionResponse, error) {
	logStashEvent := connector.newLogStashEvent()

	logXMLSubscriptionRequest(logStashEvent, request)

	response := siri.SIRISubscriptionResponse{
		Address:            connector.Partner().Address(),
		ResponderRef:       connector.SIRIPartner().RequestorRef(),
		ResponseTimestamp:  connector.Clock().Now(),
		RequestMessageRef:  request.MessageIdentifier(),
		ServiceStartedTime: connector.Partner().Referential().StartedAt(),
	}

	if len(request.XMLSubscriptionGMEntries()) > 0 {
		gmbc, ok := connector.Partner().Connector(SIRI_GENERAL_MESSAGE_SUBSCRIPTION_BROADCASTER)
		if !ok {
			return nil, fmt.Errorf("No GeneralMessageSubscriptionBroadcaster Connector")
		}
		for _, sgm := range gmbc.(*SIRIGeneralMessageSubscriptionBroadcaster).HandleSubscriptionRequest(request) {
			response.ResponseStatus = append(response.ResponseStatus, sgm)
		}
		logSIRISubscriptionResponse(logStashEvent, &response, "GeneralMessageSubscriptionBroadcaster")
		audit.CurrentLogStash().WriteEvent(logStashEvent)
		return &response, nil
	}

	if len(request.XMLSubscriptionSMEntries()) > 0 {
		smbc, ok := connector.Partner().Connector(SIRI_STOP_MONITORING_SUBSCRIPTION_BROADCASTER)
		if !ok {
			return nil, fmt.Errorf("No StopMonitoringSubscriptionBroadcaster Connector")
		}
		for _, smr := range smbc.(*SIRIStopMonitoringSubscriptionBroadcaster).HandleSubscriptionRequest(request) {
			response.ResponseStatus = append(response.ResponseStatus, smr)
		}
		logSIRISubscriptionResponse(logStashEvent, &response, "StopMonitoringSubscriptionBroadcaster")
		audit.CurrentLogStash().WriteEvent(logStashEvent)
		return &response, nil
	}

	if len(request.XMLSubscriptionETTEntries()) > 0 {
		smbc, ok := connector.Partner().Connector(SIRI_ESTIMATED_TIMETABLE_SUBSCRIPTION_BROADCASTER)
		if !ok {
			return nil, fmt.Errorf("No EstimatedTimeTableSubscriptionBroadcaster Connector")
		}
		for _, smr := range smbc.(*SIRIEstimatedTimeTableSubscriptionBroadcaster).HandleSubscriptionRequest(request) {
			response.ResponseStatus = append(response.ResponseStatus, smr)
		}
		logSIRISubscriptionResponse(logStashEvent, &response, "EstimatedTimeTableSubscriptionBroadcaster")
		audit.CurrentLogStash().WriteEvent(logStashEvent)
		return &response, nil
	}

	return nil, fmt.Errorf("Subscription not supported")
}

func (connector *SIRISubscriptionRequestDispatcher) CancelSubscription(r *siri.XMLDeleteSubscriptionRequest) *siri.SIRIDeleteSubscriptionResponse {
	logStashEvent := connector.newLogStashEvent()

	logXMLCancelSubscriptionRequest(logStashEvent, r)

	currentTime := connector.Clock().Now()
	resp := &siri.SIRIDeleteSubscriptionResponse{
		ResponderRef:      connector.SIRIPartner().RequestorRef(),
		RequestMessageRef: r.MessageIdentifier(),
		ResponseTimestamp: currentTime,
	}

	defer func() {
		logSIRICancelSubscriptionResponse(logStashEvent, resp)
		audit.CurrentLogStash().WriteEvent(logStashEvent)
	}()

	if r.CancelAll() {
		for _, subscription := range connector.Partner().Subscriptions().FindBroadcastSubscriptions() {
			responseStatus := &siri.SIRITerminationResponseStatus{
				SubscriberRef:     r.RequestorRef(),
				SubscriptionRef:   subscription.ExternalId(),
				ResponseTimestamp: currentTime,
				Status:            true,
			}
			resp.ResponseStatus = append(resp.ResponseStatus, responseStatus)
		}
		connector.Partner().CancelBroadcastSubscriptions()
		return resp
	}

	responseStatus := &siri.SIRITerminationResponseStatus{
		SubscriberRef:     r.RequestorRef(),
		SubscriptionRef:   r.SubscriptionRef(),
		ResponseTimestamp: currentTime,
	}

	resp.ResponseStatus = append(resp.ResponseStatus, responseStatus)

	sub, ok := connector.Partner().Subscriptions().FindByExternalId(r.SubscriptionRef())
	if !ok {
		logger.Log.Debugf("Could not Unsubscribe to unknow subscription %v", r.SubscriptionRef())

		responseStatus.ErrorType = "InvalidDataReferencesError"
		responseStatus.ErrorText = fmt.Sprintf("Subscription not found: '%s'", r.SubscriptionRef())
		return resp
	}

	responseStatus.Status = true

	sub.Delete()
	return resp
}

func (connector *SIRISubscriptionRequestDispatcher) newLogStashEvent() audit.LogStashEvent {
	return connector.partner.NewLogStashEvent()
}

func logXMLSubscriptionRequest(logStashEvent audit.LogStashEvent, request *siri.XMLSubscriptionRequest) {
	logStashEvent["consumerAddress"] = request.ConsumerAddress()
	logStashEvent["messageIdentifier"] = request.MessageIdentifier()
	logStashEvent["requestorRef"] = request.RequestorRef()
	logStashEvent["requestTimestamp"] = request.RequestTimestamp().String()
	logStashEvent["requestXML"] = request.RawXML()
}

func logSIRISubscriptionResponse(logStashEvent audit.LogStashEvent, response *siri.SIRISubscriptionResponse, connector string) {
	logStashEvent["connector"] = connector
	logStashEvent["type"] = "subscriptionResponse"
	logStashEvent["address"] = response.Address
	logStashEvent["responderRef"] = response.ResponderRef
	logStashEvent["requestMessageRef"] = response.RequestMessageRef
	logStashEvent["responseTimestamp"] = response.ResponseTimestamp.String()
	logStashEvent["serviceStartedTime"] = response.ServiceStartedTime.String()
	xml, err := response.BuildXML()
	if err != nil {
		logStashEvent["responseXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["responseXML"] = xml
}

func logXMLCancelSubscriptionRequest(logStashEvent audit.LogStashEvent, request *siri.XMLDeleteSubscriptionRequest) {
	logStashEvent["messageIdentifier"] = request.MessageIdentifier()
	logStashEvent["requestorRef"] = request.RequestorRef()
	logStashEvent["requestTimestamp"] = request.RequestTimestamp().String()
	if request.CancelAll() {
		logStashEvent["subscriptionToCancel"] = "All"
	} else {
		logStashEvent["subscriptionToCancel"] = request.SubscriptionRef()
	}
	logStashEvent["requestXML"] = request.RawXML()
}

func logSIRICancelSubscriptionResponse(logStashEvent audit.LogStashEvent, response *siri.SIRIDeleteSubscriptionResponse) {
	logStashEvent["responderRef"] = response.ResponderRef
	logStashEvent["requestMessageRef"] = response.RequestMessageRef
	logStashEvent["responseTimestamp"] = response.ResponseTimestamp.String()
	xml, err := response.BuildXML()
	if err != nil {
		logStashEvent["responseXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["responseXML"] = xml
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/coreos/go-systemd/activation"
)

const listenFdsStart = 3
const resendCount = 3

var errNoMoreTries = errors.New("no more tries")

type DHCP struct {
	mux    sync.Mutex
	leases map[string]*DHCPLease
}

func newDHCP() *DHCP {
	return &DHCP{
		leases: make(map[string]*DHCPLease),
	}
}

// Allocate acquires an IP from a DHCP server for a specified container.
// The acquired lease will be maintained until Release() is called.
func (d *DHCP) Allocate(args *skel.CmdArgs, result *current.Result) error {
	conf := types.NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("error parsing netconf: %v", err)
	}

	clientID := args.ContainerID + "/" + conf.Name
	l, err := AcquireLease(clientID, args.Netns, args.IfName)
	if err != nil {
		return err
	}

	ipn, err := l.IPNet()
	if err != nil {
		l.Stop()
		return err
	}

	d.setLease(args.ContainerID, conf.Name, l)

	result.IPs = []*current.IPConfig{{
		Version: "4",
		Address: *ipn,
		Gateway: l.Gateway(),
	}}
	result.Routes = l.Routes()

	return nil
}

// Release stops maintenance of the lease acquired in Allocate()
// and sends a release msg to the DHCP server.
func (d *DHCP) Release(args *skel.CmdArgs, reply *struct{}) error {
	conf := types.NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("error parsing netconf: %v", err)
	}

	if l := d.getLease(args.ContainerID, conf.Name); l != nil {
		l.Stop()
		return nil
	}

	return fmt.Errorf("lease not found: %v/%v", args.ContainerID, conf.Name)
}

func (d *DHCP) getLease(contID, netName string) *DHCPLease {
	d.mux.Lock()
	defer d.mux.Unlock()

	// TODO(eyakubovich): hash it to avoid collisions
	l, ok := d.leases[contID+netName]
	if !ok {
		return nil
	}
	return l
}

func (d *DHCP) setLease(contID, netName string, l *DHCPLease) {
	d.mux.Lock()
	defer d.mux.Unlock()

	// TODO(eyakubovich): hash it to avoid collisions
	d.leases[contID+netName] = l
}

func getListener() (net.Listener, error) {
	l, err := activation.Listeners(true)
	if err != nil {
		return nil, err
	}

	switch {
	case len(l) == 0:
		if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil {
			return nil, err
		}
		return net.Listen("unix", socketPath)

	case len(l) == 1:
		if l[0] == nil {
			return nil, fmt.Errorf("LISTEN_FDS=1 but no FD found")
		}
		return l[0], nil

	default:
		return nil, fmt.Errorf("Too many (%v) FDs passed through socket activation", len(l))
	}
}

func runDaemon(pidfilePath string) error {
	// since other goroutines (on separate threads) will change namespaces,
	// ensure the RPC server does not get scheduled onto those
	runtime.LockOSThread()

	// Write the pidfile
	if pidfilePath != "" {
		if !filepath.IsAbs(pidfilePath) {
			return fmt.Errorf("Error writing pidfile %q: path not absolute", pidfilePath)
		}
		if err := ioutil.WriteFile(pidfilePath, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
			return fmt.Errorf("Error writing pidfile %q: %v", pidfilePath, err)
		}
	}

	l, err := getListener()
	if err != nil {
		return fmt.Errorf("Error getting listener: %v", err)
	}

	dhcp := newDHCP()
	rpc.Register(dhcp)
	rpc.HandleHTTP()
	http.Serve(l, nil)
	return nil
}
<commit_msg>Don't let DHCP delete fail on missing lease<commit_after>// Copyright 2015 CNI authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/coreos/go-systemd/activation"
)

const listenFdsStart = 3
const resendCount = 3

var errNoMoreTries = errors.New("no more tries")

type DHCP struct {
	mux    sync.Mutex
	leases map[string]*DHCPLease
}

func newDHCP() *DHCP {
	return &DHCP{
		leases: make(map[string]*DHCPLease),
	}
}

// Allocate acquires an IP from a DHCP server for a specified container.
// The acquired lease will be maintained until Release() is called.
func (d *DHCP) Allocate(args *skel.CmdArgs, result *current.Result) error {
	conf := types.NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("error parsing netconf: %v", err)
	}

	clientID := args.ContainerID + "/" + conf.Name
	l, err := AcquireLease(clientID, args.Netns, args.IfName)
	if err != nil {
		return err
	}

	ipn, err := l.IPNet()
	if err != nil {
		l.Stop()
		return err
	}

	d.setLease(args.ContainerID, conf.Name, l)

	result.IPs = []*current.IPConfig{{
		Version: "4",
		Address: *ipn,
		Gateway: l.Gateway(),
	}}
	result.Routes = l.Routes()

	return nil
}

// Release stops maintenance of the lease acquired in Allocate()
// and sends a release msg to the DHCP server.
func (d *DHCP) Release(args *skel.CmdArgs, reply *struct{}) error {
	conf := types.NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("error parsing netconf: %v", err)
	}

	if l := d.getLease(args.ContainerID, conf.Name); l != nil {
		l.Stop()
	}

	return nil
}

func (d *DHCP) getLease(contID, netName string) *DHCPLease {
	d.mux.Lock()
	defer d.mux.Unlock()

	// TODO(eyakubovich): hash it to avoid collisions
	l, ok := d.leases[contID+netName]
	if !ok {
		return nil
	}
	return l
}

func (d *DHCP) setLease(contID, netName string, l *DHCPLease) {
	d.mux.Lock()
	defer d.mux.Unlock()

	// TODO(eyakubovich): hash it to avoid collisions
	d.leases[contID+netName] = l
}

func getListener() (net.Listener, error) {
	l, err := activation.Listeners(true)
	if err != nil {
		return nil, err
	}

	switch {
	case len(l) == 0:
		if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil {
			return nil, err
		}
		return net.Listen("unix", socketPath)

	case len(l) == 1:
		if l[0] == nil {
			return nil, fmt.Errorf("LISTEN_FDS=1 but no FD found")
		}
		return l[0], nil

	default:
		return nil, fmt.Errorf("Too many (%v) FDs passed through socket activation", len(l))
	}
}

func runDaemon(pidfilePath string) error {
	// since other goroutines (on separate threads) will change namespaces,
	// ensure the RPC server does not get scheduled onto those
	runtime.LockOSThread()

	// Write the pidfile
	if pidfilePath != "" {
		if !filepath.IsAbs(pidfilePath) {
			return fmt.Errorf("Error writing pidfile %q: path not absolute", pidfilePath)
		}
		if err := ioutil.WriteFile(pidfilePath, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
			return fmt.Errorf("Error writing pidfile %q: %v", pidfilePath, err)
		}
	}

	l, err := getListener()
	if err != nil {
		return fmt.Errorf("Error getting listener: %v", err)
	}

	dhcp := newDHCP()
	rpc.Register(dhcp)
	rpc.HandleHTTP()
	http.Serve(l, nil)
	return nil
}
<|endoftext|>


<commit_before>package trust

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/docker/notary/client"
	"github.com/docker/notary/tuf/data"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/trust"
	"github.com/docker/distribution/reference"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/registry"
	"github.com/spf13/cobra"
)

func newRevokeCommand(dockerCli command.Cli) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "revoke [OPTIONS] IMAGE[:TAG]",
		Short: "Remove trust for an image",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return revokeTrust(dockerCli, args[0])
		},
	}
	return cmd
}

func askConfirm(input io.Reader) bool {
	var res string
	if _, err := fmt.Fscanln(input, &res); err != nil {
		return false
	}
	if strings.EqualFold(res, "y") || strings.EqualFold(res, "yes") {
		return true
	}
	return false
}

func revokeTrust(cli command.Cli, remote string) error {
	ref, repoInfo, authConfig, err := getImageReferencesAndAuth(cli, remote)
	if err != nil {
		return err
	}
	switch ref.(type) {
	case reference.Digested, reference.Canonical:
		return fmt.Errorf("Cannot remove signature for digest")
	case reference.NamedTagged:
		if err := revokeSingleSig(cli, ref.(reference.NamedTagged), repoInfo, *authConfig); err != nil {
			return fmt.Errorf("Could not remove signature")
		}
		return nil
	default:
		if err := revokeAllSigs(cli, ref, repoInfo, *authConfig); err != nil {
			return fmt.Errorf("Could not remove all signatures")
		}
		return nil
	}
}

func revokeSingleSig(cli command.Cli, ref reference.NamedTagged, repoInfo *registry.RepositoryInfo, authConfig types.AuthConfig) error {
	tag := ref.Tag()
	// TODO(riyazdf): can we allow for a memory changelist?
	notaryRepo, err := trust.GetNotaryRepository(cli, repoInfo, authConfig, "push", "pull")
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	// Figure out which roles this is published to and which keys we have on-disk
	targetSigs, err := notaryRepo.GetAllTargetMetadataByName(tag)
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}
	roles := []data.RoleName{}
	for _, sig := range targetSigs {
		roles = append(roles, sig.Role.Name)
	}

	// TODO: check which role the target is signed into and do some key-matching against what the user has
	// in particular: should check if it's in targets/releases first, and then targets
	// if the user doesn't have any helpful keys, error out early

	// Remove from all roles
	if err := notaryRepo.RemoveTarget(tag, roles...); err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	// Publish change
	if err := notaryRepo.Publish(); err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	fmt.Println("Successfully deleted signature")
	return nil
}

func revokeAllSigs(cli command.Cli, ref reference.Named, repoInfo *registry.RepositoryInfo, authConfig types.AuthConfig) error {
	in := os.Stdin
	fmt.Printf(
		"Please confirm you would like to delete all signature data for: %s (y/n)\n",
		repoInfo.Name,
	)
	// TODO: Also add force (-y) flag
	deleteRemote := askConfirm(in)
	if !deleteRemote {
		fmt.Println("\nAborting action.")
		return nil
	}

	server, err := trust.Server(repoInfo.Index)
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	tr, err := trust.GetTransport(repoInfo, server, authConfig, "*")
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	notaryRepo, err := trust.GetNotaryRepositoryWithTransport(cli, repoInfo, server, tr)
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	// Delete trust data for this repo
	if err := client.DeleteTrustData(trust.GetTrustDirectoryName(), notaryRepo.GetGUN(), server, tr, deleteRemote); err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	fmt.Println("Successfully deleted all signature data")
	return nil
}
<commit_msg>Use the cli printer to print messages<commit_after>package trust

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/docker/notary/client"
	"github.com/docker/notary/tuf/data"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/trust"
	"github.com/docker/distribution/reference"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/registry"
	"github.com/spf13/cobra"
)

func newRevokeCommand(dockerCli command.Cli) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "revoke [OPTIONS] IMAGE[:TAG]",
		Short: "Remove trust for an image",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return revokeTrust(dockerCli, args[0])
		},
	}
	return cmd
}

func askConfirm(input io.Reader) bool {
	var res string
	if _, err := fmt.Fscanln(input, &res); err != nil {
		return false
	}
	if strings.EqualFold(res, "y") || strings.EqualFold(res, "yes") {
		return true
	}
	return false
}

func revokeTrust(cli command.Cli, remote string) error {
	ref, repoInfo, authConfig, err := getImageReferencesAndAuth(cli, remote)
	if err != nil {
		return err
	}
	switch ref.(type) {
	case reference.Digested, reference.Canonical:
		return fmt.Errorf("Cannot remove signature for digest")
	case reference.NamedTagged:
		if err := revokeSingleSig(cli, ref.(reference.NamedTagged), repoInfo, *authConfig); err != nil {
			return fmt.Errorf("Could not remove signature")
		}
		return nil
	default:
		if err := revokeAllSigs(cli, ref, repoInfo, *authConfig); err != nil {
			return fmt.Errorf("Could not remove all signatures")
		}
		return nil
	}
}

func revokeSingleSig(cli command.Cli, ref reference.NamedTagged, repoInfo *registry.RepositoryInfo, authConfig types.AuthConfig) error {
	tag := ref.Tag()
	// TODO(riyazdf): can we allow for a memory changelist?
	notaryRepo, err := trust.GetNotaryRepository(cli, repoInfo, authConfig, "push", "pull")
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	// Figure out which roles this is published to and which keys we have on-disk
	targetSigs, err := notaryRepo.GetAllTargetMetadataByName(tag)
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}
	roles := []data.RoleName{}
	for _, sig := range targetSigs {
		roles = append(roles, sig.Role.Name)
	}

	// TODO: check which role the target is signed into and do some key-matching against what the user has
	// in particular: should check if it's in targets/releases first, and then targets
	// if the user doesn't have any helpful keys, error out early

	// Remove from all roles
	if err := notaryRepo.RemoveTarget(tag, roles...); err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	// Publish change
	if err := notaryRepo.Publish(); err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	fmt.Fprintf(cli.Out(), "Successfully deleted signature")
	return nil
}

func revokeAllSigs(cli command.Cli, ref reference.Named, repoInfo *registry.RepositoryInfo, authConfig types.AuthConfig) error {
	in := os.Stdin
	fmt.Fprintf(
		cli.Out(),
		"Please confirm you would like to delete all signature data for: %s (y/n)\n",
		repoInfo.Name,
	)
	// TODO: Also add force (-y) flag
	deleteRemote := askConfirm(in)
	if !deleteRemote {
		fmt.Fprintf(cli.Out(), "\nAborting action.\n")
		return nil
	}

	server, err := trust.Server(repoInfo.Index)
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	tr, err := trust.GetTransport(repoInfo, server, authConfig, "*")
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	notaryRepo, err := trust.GetNotaryRepositoryWithTransport(cli, repoInfo, server, tr)
	if err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	// Delete trust data for this repo
	if err := client.DeleteTrustData(trust.GetTrustDirectoryName(), notaryRepo.GetGUN(), server, tr, deleteRemote); err != nil {
		return trust.NotaryError(ref.Name(), err)
	}

	fmt.Fprintf(cli.Out(), "Successfully deleted all signature data")
	return nil
}
<|endoftext|>


<commit_before>package chart

import (
	"fmt"
	"math"

	"github.com/wcharczuk/go-chart/matrix"
)

// PolynomialRegressionSeries implements a polynomial regression over a given
// inner series.
type PolynomialRegressionSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	Limit       int
	Offset      int
	Degree      int
	InnerSeries ValueProvider

	coeffs []float64
}

// GetName returns the name of the time series.
func (prs PolynomialRegressionSeries) GetName() string {
	return prs.Name
}

// GetStyle returns the line style.
func (prs PolynomialRegressionSeries) GetStyle() Style {
	return prs.Style
}

// GetYAxis returns which YAxis the series draws on.
func (prs PolynomialRegressionSeries) GetYAxis() YAxisType {
	return prs.YAxis
}

// Len returns the number of elements in the series.
func (prs PolynomialRegressionSeries) Len() int {
	return Math.MinInt(prs.GetLimit(), prs.InnerSeries.Len()-prs.GetOffset())
}

// GetLimit returns the window size.
func (prs PolynomialRegressionSeries) GetLimit() int {
	if prs.Limit == 0 {
		return prs.InnerSeries.Len()
	}
	return prs.Limit
}

// GetEndIndex returns the effective limit end.
func (prs PolynomialRegressionSeries) GetEndIndex() int {
	windowEnd := prs.GetOffset() + prs.GetLimit()
	innerSeriesLastIndex := prs.InnerSeries.Len() - 1
	return Math.MinInt(windowEnd, innerSeriesLastIndex)
}

// GetOffset returns the data offset.
func (prs PolynomialRegressionSeries) GetOffset() int {
	if prs.Offset == 0 {
		return 0
	}
	return prs.Offset
}

// Validate validates the series.
func (prs *PolynomialRegressionSeries) Validate() error {
	if prs.InnerSeries == nil {
		return fmt.Errorf("linear regression series requires InnerSeries to be set")
	}

	endIndex := prs.GetEndIndex()
	if endIndex >= prs.InnerSeries.Len() {
		return fmt.Errorf("invalid window; inner series has length %d but end index is %d", prs.InnerSeries.Len(), endIndex)
	}

	return nil
}

// GetValue returns the series value for a given index.
func (prs *PolynomialRegressionSeries) GetValue(index int) (x, y float64) {
	if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 {
		return
	}

	if prs.coeffs == nil {
		coeffs, err := prs.computeCoefficients()
		if err != nil {
			panic(err)
		}
		prs.coeffs = coeffs
	}

	offset := prs.GetOffset()
	effectiveIndex := Math.MinInt(index+offset, prs.InnerSeries.Len())
	x, y = prs.InnerSeries.GetValue(effectiveIndex)
	y = prs.apply(x)
	return
}

// GetLastValue computes the last poly regression value.
func (prs *PolynomialRegressionSeries) GetLastValue() (x, y float64) {
	if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 {
		return
	}
	if prs.coeffs == nil {
		coeffs, err := prs.computeCoefficients()
		if err != nil {
			panic(err)
		}
		prs.coeffs = coeffs
	}
	endIndex := prs.GetEndIndex()
	x, y = prs.InnerSeries.GetValue(endIndex)
	y = prs.apply(x)
	return
}

func (prs *PolynomialRegressionSeries) apply(v float64) (out float64) {
	for index, coeff := range prs.coeffs {
		out = out + (coeff * math.Pow(v, float64(index)))
	}
	return
}

func (prs *PolynomialRegressionSeries) computeCoefficients() ([]float64, error) {
	xvalues, yvalues := prs.values()
	return matrix.Poly(xvalues, yvalues, prs.Degree)
}

func (prs *PolynomialRegressionSeries) values() (xvalues, yvalues []float64) {
	startIndex := prs.GetOffset()
	endIndex := prs.GetEndIndex()

	xvalues = make([]float64, endIndex-startIndex)
	yvalues = make([]float64, endIndex-startIndex)

	for index := startIndex; index < endIndex; index++ {
		x, y := prs.InnerSeries.GetValue(index)
		xvalues[index] = x
		yvalues[index] = y
	}

	return
}

// Render renders the series.
func (prs *PolynomialRegressionSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
	style := prs.Style.InheritFrom(defaults)
	Draw.LineSeries(r, canvasBox, xrange, yrange, style, prs)
}
<commit_msg>tweaks<commit_after>package chart

import (
	"fmt"
	"math"

	"github.com/wcharczuk/go-chart/matrix"
)

// PolynomialRegressionSeries implements a polynomial regression over a given
// inner series.
type PolynomialRegressionSeries struct {
	Name  string
	Style Style
	YAxis YAxisType

	Limit       int
	Offset      int
	Degree      int
	InnerSeries ValueProvider

	coeffs []float64
}

// GetName returns the name of the time series.
func (prs PolynomialRegressionSeries) GetName() string {
	return prs.Name
}

// GetStyle returns the line style.
func (prs PolynomialRegressionSeries) GetStyle() Style {
	return prs.Style
}

// GetYAxis returns which YAxis the series draws on.
func (prs PolynomialRegressionSeries) GetYAxis() YAxisType {
	return prs.YAxis
}

// Len returns the number of elements in the series.
func (prs PolynomialRegressionSeries) Len() int {
	return Math.MinInt(prs.GetLimit(), prs.InnerSeries.Len()-prs.GetOffset())
}

// GetLimit returns the window size.
func (prs PolynomialRegressionSeries) GetLimit() int {
	if prs.Limit == 0 {
		return prs.InnerSeries.Len()
	}
	return prs.Limit
}

// GetEndIndex returns the effective limit end.
func (prs PolynomialRegressionSeries) GetEndIndex() int {
	windowEnd := prs.GetOffset() + prs.GetLimit()
	innerSeriesLastIndex := prs.InnerSeries.Len() - 1
	return Math.MinInt(windowEnd, innerSeriesLastIndex)
}

// GetOffset returns the data offset.
func (prs PolynomialRegressionSeries) GetOffset() int {
	if prs.Offset == 0 {
		return 0
	}
	return prs.Offset
}

// Validate validates the series.
func (prs *PolynomialRegressionSeries) Validate() error {
	if prs.InnerSeries == nil {
		return fmt.Errorf("linear regression series requires InnerSeries to be set")
	}

	endIndex := prs.GetEndIndex()
	if endIndex >= prs.InnerSeries.Len() {
		return fmt.Errorf("invalid window; inner series has length %d but end index is %d", prs.InnerSeries.Len(), endIndex)
	}

	return nil
}

// GetValue returns the series value for a given index.
func (prs *PolynomialRegressionSeries) GetValue(index int) (x, y float64) {
	if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 {
		return
	}

	if prs.coeffs == nil {
		coeffs, err := prs.computeCoefficients()
		if err != nil {
			panic(err)
		}
		prs.coeffs = coeffs
	}

	offset := prs.GetOffset()
	effectiveIndex := Math.MinInt(index+offset, prs.InnerSeries.Len())
	x, y = prs.InnerSeries.GetValue(effectiveIndex)
	y = prs.apply(x)
	return
}

// GetLastValue computes the last poly regression value.
func (prs *PolynomialRegressionSeries) GetLastValue() (x, y float64) {
	if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 {
		return
	}
	if prs.coeffs == nil {
		coeffs, err := prs.computeCoefficients()
		if err != nil {
			panic(err)
		}
		prs.coeffs = coeffs
	}
	endIndex := prs.GetEndIndex()
	x, y = prs.InnerSeries.GetValue(endIndex)
	y = prs.apply(x)
	return
}

func (prs *PolynomialRegressionSeries) apply(v float64) (out float64) {
	for index, coeff := range prs.coeffs {
		out = out + (coeff * math.Pow(v, float64(index)))
	}
	return
}

func (prs *PolynomialRegressionSeries) computeCoefficients() ([]float64, error) {
	xvalues, yvalues := prs.values()
	return matrix.Poly(xvalues, yvalues, prs.Degree)
}

func (prs *PolynomialRegressionSeries) values() (xvalues, yvalues []float64) {
	startIndex := prs.GetOffset()
	endIndex := prs.GetEndIndex()

	xvalues = make([]float64, endIndex-startIndex)
	yvalues = make([]float64, endIndex-startIndex)

	for index := startIndex; index < endIndex; index++ {
		x, y := prs.InnerSeries.GetValue(index)
		xvalues[index-startIndex] = x
		yvalues[index-startIndex] = y
	}

	return
}

// Render renders the series.
func (prs *PolynomialRegressionSeries) Render(r Renderer, canvasBox Box, xrange, yrange Range, defaults Style) {
	style := prs.Style.InheritFrom(defaults)
	Draw.LineSeries(r, canvasBox, xrange, yrange, style, prs)
}
<|endoftext|>


<commit_before>package diff

import (
	"fmt"
	"reflect"
	"strings"
	"testing"
)

func TestDiff(t *testing.T) {
	tests := []struct {
		desc   string
		A, B   []string
		chunks []Chunk
	}{
		{
			desc: "constitution",
			A: []string{
				"We the People of the United States, in Order to form a more perfect Union,",
				"establish Justice, insure domestic Tranquility, provide for the common defence,",
				"and secure the Blessings of Liberty to ourselves",
				"and our Posterity, do ordain and establish this Constitution for the United",
				"States of America.",
			},
			B: []string{
				"We the People of the United States, in Order to form a more perfect Union,",
				"establish Justice, insure domestic Tranquility, provide for the common defence,",
				"promote the general Welfare, and secure the Blessings of Liberty to ourselves",
				"and our Posterity, do ordain and establish this Constitution for the United",
				"States of America.",
			},
			chunks: []Chunk{
				0: {
					Equal: []string{
						"We the People of the United States, in Order to form a more perfect Union,",
						"establish Justice, insure domestic Tranquility, provide for the common defence,",
					},
				},
				1: {
					Deleted: []string{
						"and secure the Blessings of Liberty to ourselves",
					},
				},
				2: {
					Added: []string{
						"promote the general Welfare, and secure the Blessings of Liberty to ourselves",
					},
					Equal: []string{
						"and our Posterity, do ordain and establish this Constitution for the United",
						"States of America.",
					},
				},
			},
		},
	}

	for _, test := range tests {
		got := DiffChunks(test.A, test.B)
		if got, want := len(got), len(test.chunks); got != want {
			t.Errorf("%s: edit distance = %v, want %v", test.desc, got-1, want-1)
			continue
		}
		for i := range got {
			got, want := got[i], test.chunks[i]
			if got, want := got.Added, want.Added; !reflect.DeepEqual(got, want) {
				t.Errorf("%s[%d]: Added = %v, want %v", test.desc, i, got, want)
			}
			if got, want := got.Deleted, want.Deleted; !reflect.DeepEqual(got, want) {
				t.Errorf("%s[%d]: Deleted = %v, want %v", test.desc, i, got, want)
			}
			if got, want := got.Equal, want.Equal; !reflect.DeepEqual(got, want) {
				t.Errorf("%s[%d]: Equal = %v, want %v", test.desc, i, got, want)
			}
		}
	}
}

func ExampleDiff() {
	constitution := strings.TrimSpace(`
We the People of the United States, in Order to form a more perfect Union,
establish Justice, insure domestic Tranquility, provide for the common defence,
promote the general Welfare, and secure the Blessings of Liberty to ourselves
and our Posterity, do ordain and establish this Constitution for the United
States of America.
`)

	got := strings.TrimSpace(`
We the People of the United States, in Order to form a more perfect Union,
establish Justice, insure domestic Tranquility, provide for the common defence,
and secure the Blessings of Liberty to ourselves
and our Posterity, do ordain and establish this Constitution for the United
States of America.
`)

	fmt.Println(Diff(got, constitution))

	// Output:
	//  We the People of the United States, in Order to form a more perfect Union,
	//  establish Justice, insure domestic Tranquility, provide for the common defence,
	// -and secure the Blessings of Liberty to ourselves
	// +promote the general Welfare, and secure the Blessings of Liberty to ourselves
	//  and our Posterity, do ordain and establish this Constitution for the United
	//  States of America.
}
<commit_msg>Work around godoc space trimming<commit_after>package diff

import (
	"fmt"
	"reflect"
	"strings"
	"testing"
)

func TestDiff(t *testing.T) {
	tests := []struct {
		desc   string
		A, B   []string
		chunks []Chunk
	}{
		{
			desc: "constitution",
			A: []string{
				"We the People of the United States, in Order to form a more perfect Union,",
				"establish Justice, insure domestic Tranquility, provide for the common defence,",
				"and secure the Blessings of Liberty to ourselves",
				"and our Posterity, do ordain and establish this Constitution for the United",
				"States of America.",
			},
			B: []string{
				"We the People of the United States, in Order to form a more perfect Union,",
				"establish Justice, insure domestic Tranquility, provide for the common defence,",
				"promote the general Welfare, and secure the Blessings of Liberty to ourselves",
				"and our Posterity, do ordain and establish this Constitution for the United",
				"States of America.",
			},
			chunks: []Chunk{
				0: {
					Equal: []string{
						"We the People of the United States, in Order to form a more perfect Union,",
						"establish Justice, insure domestic Tranquility, provide for the common defence,",
					},
				},
				1: {
					Deleted: []string{
						"and secure the Blessings of Liberty to ourselves",
					},
				},
				2: {
					Added: []string{
						"promote the general Welfare, and secure the Blessings of Liberty to ourselves",
					},
					Equal: []string{
						"and our Posterity, do ordain and establish this Constitution for the United",
						"States of America.",
					},
				},
			},
		},
	}

	for _, test := range tests {
		got := DiffChunks(test.A, test.B)
		if got, want := len(got), len(test.chunks); got != want {
			t.Errorf("%s: edit distance = %v, want %v", test.desc, got-1, want-1)
			continue
		}
		for i := range got {
			got, want := got[i], test.chunks[i]
			if got, want := got.Added, want.Added; !reflect.DeepEqual(got, want) {
				t.Errorf("%s[%d]: Added = %v, want %v", test.desc, i, got, want)
			}
			if got, want := got.Deleted, want.Deleted; !reflect.DeepEqual(got, want) {
				t.Errorf("%s[%d]: Deleted = %v, want %v", test.desc, i, got, want)
			}
			if got, want := got.Equal, want.Equal; !reflect.DeepEqual(got, want) {
				t.Errorf("%s[%d]: Equal = %v, want %v", test.desc, i, got, want)
			}
		}
	}
}

func ExampleDiff() {
	constitution := strings.TrimSpace(`
We the People of the United States, in Order to form a more perfect Union,
establish Justice, insure domestic Tranquility, provide for the common defence,
promote the general Welfare, and secure the Blessings of Liberty to ourselves
and our Posterity, do ordain and establish this Constitution for the United
States of America.
`)

	got := strings.TrimSpace(`
:wq
We the People of the United States, in Order to form a more perfect Union,
establish Justice, insure domestic Tranquility, provide for the common defence,
and secure the Blessings of Liberty to ourselves
and our Posterity, do ordain and establish this Constitution for the United
States of America.
`)

	fmt.Println(Diff(got, constitution))

	// Output:
	// -:wq
	//  We the People of the United States, in Order to form a more perfect Union,
	//  establish Justice, insure domestic Tranquility, provide for the common defence,
	// -and secure the Blessings of Liberty to ourselves
	// +promote the general Welfare, and secure the Blessings of Liberty to ourselves
	//  and our Posterity, do ordain and establish this Constitution for the United
	//  States of America.
}
<|endoftext|>


<commit_before>package node

import (
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/docker/docker/api/client"
	"github.com/docker/docker/api/client/inspect"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/pkg/ioutils"
	"github.com/docker/engine-api/types/swarm"
	"github.com/docker/go-units"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

type inspectOptions struct {
	nodeIds []string
	format  string
	pretty  bool
}

func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
	var opts inspectOptions

	cmd := &cobra.Command{
		Use:   "inspect [OPTIONS] self|NODE [NODE...]",
		Short: "Display detailed information on one or more nodes",
		Args:  cli.RequiresMinArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			opts.nodeIds = args
			return runInspect(dockerCli, opts)
		},
	}

	flags := cmd.Flags()
	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
	flags.BoolVar(&opts.pretty, "pretty", false, "Print the information in a human friendly format.")
	return cmd
}

func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
	client := dockerCli.Client()
	ctx := context.Background()
	getRef := func(ref string) (interface{}, []byte, error) {
		nodeRef, err := Reference(client, ctx, ref)
		if err != nil {
			return nil, nil, err
		}
		node, _, err := client.NodeInspectWithRaw(ctx, nodeRef)
		return node, nil, err
	}

	if !opts.pretty {
		return inspect.Inspect(dockerCli.Out(), opts.nodeIds, opts.format, getRef)
	}
	return printHumanFriendly(dockerCli.Out(), opts.nodeIds, getRef)
}

func printHumanFriendly(out io.Writer, refs []string, getRef inspect.GetRefFunc) error {
	for idx, ref := range refs {
		obj, _, err := getRef(ref)
		if err != nil {
			return err
		}
		printNode(out, obj.(swarm.Node))

		// TODO: better way to do this?
		// print extra space between objects, but not after the last one
		if idx+1 != len(refs) {
			fmt.Fprintf(out, "\n\n")
		}
	}
	return nil
}

// TODO: use a template
func printNode(out io.Writer, node swarm.Node) {
	fmt.Fprintf(out, "ID:\t\t\t%s\n", node.ID)
	ioutils.FprintfIfNotEmpty(out, "Name:\t\t\t%s\n", node.Spec.Name)
	if node.Spec.Labels != nil {
		fmt.Fprintln(out, "Labels:")
		for k, v := range node.Spec.Labels {
			fmt.Fprintf(out, " - %s = %s\n", k, v)
		}
	}

	ioutils.FprintfIfNotEmpty(out, "Hostname:\t\t%s\n", node.Description.Hostname)
	fmt.Fprintln(out, "Status:")
	fmt.Fprintf(out, " State:\t\t\t%s\n", client.PrettyPrint(node.Status.State))
	ioutils.FprintfIfNotEmpty(out, " Message:\t\t%s\n", client.PrettyPrint(node.Status.Message))
	fmt.Fprintf(out, " Availability:\t\t%s\n", client.PrettyPrint(node.Spec.Availability))

	if node.ManagerStatus != nil {
		fmt.Fprintln(out, "Manager Status:")
		fmt.Fprintf(out, " Address:\t\t%s\n", node.ManagerStatus.Addr)
		fmt.Fprintf(out, " Raft Status:\t\t%s\n", client.PrettyPrint(node.ManagerStatus.Reachability))
		leader := "No"
		if node.ManagerStatus.Leader {
			leader = "Yes"
		}
		fmt.Fprintf(out, " Leader:\t\t%s\n", leader)
	}

	fmt.Fprintln(out, "Platform:")
	fmt.Fprintf(out, " Operating System:\t%s\n", node.Description.Platform.OS)
	fmt.Fprintf(out, " Architecture:\t\t%s\n", node.Description.Platform.Architecture)

	fmt.Fprintln(out, "Resources:")
	fmt.Fprintf(out, " CPUs:\t\t\t%d\n", node.Description.Resources.NanoCPUs/1e9)
	fmt.Fprintf(out, " Memory:\t\t%s\n", units.BytesSize(float64(node.Description.Resources.MemoryBytes)))

	var pluginTypes []string
	pluginNamesByType := map[string][]string{}
	for _, p := range node.Description.Engine.Plugins {
		// append to pluginTypes only if not done previously
		if _, ok := pluginNamesByType[p.Type]; !ok {
			pluginTypes = append(pluginTypes, p.Type)
		}
		pluginNamesByType[p.Type] = append(pluginNamesByType[p.Type], p.Name)
	}

	if len(pluginTypes) > 0 {
		fmt.Fprintln(out, "Plugins:")
		sort.Strings(pluginTypes) // ensure stable output
		for _, pluginType := range pluginTypes {
			fmt.Fprintf(out, "  %s:\t\t%s\n", pluginType, strings.Join(pluginNamesByType[pluginType], ", "))
		}
	}
	fmt.Fprintf(out, "Engine Version:\t\t%s\n", node.Description.Engine.EngineVersion)

	if len(node.Description.Engine.Labels) != 0 {
		fmt.Fprintln(out, "Engine Labels:")
		for k, v := range node.Description.Engine.Labels {
			fmt.Fprintf(out, " - %s = %s", k, v)
		}
	}

}
<commit_msg>Adding Joined at to node inspect<commit_after>package node

import (
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/docker/docker/api/client"
	"github.com/docker/docker/api/client/inspect"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/pkg/ioutils"
	"github.com/docker/engine-api/types/swarm"
	"github.com/docker/go-units"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
)

type inspectOptions struct {
	nodeIds []string
	format  string
	pretty  bool
}

func newInspectCommand(dockerCli *client.DockerCli) *cobra.Command {
	var opts inspectOptions

	cmd := &cobra.Command{
		Use:   "inspect [OPTIONS] self|NODE [NODE...]",
		Short: "Display detailed information on one or more nodes",
		Args:  cli.RequiresMinArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			opts.nodeIds = args
			return runInspect(dockerCli, opts)
		},
	}

	flags := cmd.Flags()
	flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given go template")
	flags.BoolVar(&opts.pretty, "pretty", false, "Print the information in a human friendly format.")
	return cmd
}

func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error {
	client := dockerCli.Client()
	ctx := context.Background()
	getRef := func(ref string) (interface{}, []byte, error) {
		nodeRef, err := Reference(client, ctx, ref)
		if err != nil {
			return nil, nil, err
		}
		node, _, err := client.NodeInspectWithRaw(ctx, nodeRef)
		return node, nil, err
	}

	if !opts.pretty {
		return inspect.Inspect(dockerCli.Out(), opts.nodeIds, opts.format, getRef)
	}
	return printHumanFriendly(dockerCli.Out(), opts.nodeIds, getRef)
}

func printHumanFriendly(out io.Writer, refs []string, getRef inspect.GetRefFunc) error {
	for idx, ref := range refs {
		obj, _, err := getRef(ref)
		if err != nil {
			return err
		}
		printNode(out, obj.(swarm.Node))

		// TODO: better way to do this?
		// print extra space between objects, but not after the last one
		if idx+1 != len(refs) {
			fmt.Fprintf(out, "\n\n")
		}
	}
	return nil
}

// TODO: use a template
func printNode(out io.Writer, node swarm.Node) {
	fmt.Fprintf(out, "ID:\t\t\t%s\n", node.ID)
	ioutils.FprintfIfNotEmpty(out, "Name:\t\t\t%s\n", node.Spec.Name)
	if node.Spec.Labels != nil {
		fmt.Fprintln(out, "Labels:")
		for k, v := range node.Spec.Labels {
			fmt.Fprintf(out, " - %s = %s\n", k, v)
		}
	}

	ioutils.FprintfIfNotEmpty(out, "Hostname:\t\t%s\n", node.Description.Hostname)
	fmt.Fprintf(out, "Joined at:\t\t%s\n", client.PrettyPrint(node.CreatedAt))
	fmt.Fprintln(out, "Status:")
	fmt.Fprintf(out, " State:\t\t\t%s\n", client.PrettyPrint(node.Status.State))
	ioutils.FprintfIfNotEmpty(out, " Message:\t\t%s\n", client.PrettyPrint(node.Status.Message))
	fmt.Fprintf(out, " Availability:\t\t%s\n", client.PrettyPrint(node.Spec.Availability))

	if node.ManagerStatus != nil {
		fmt.Fprintln(out, "Manager Status:")
		fmt.Fprintf(out, " Address:\t\t%s\n", node.ManagerStatus.Addr)
		fmt.Fprintf(out, " Raft Status:\t\t%s\n", client.PrettyPrint(node.ManagerStatus.Reachability))
		leader := "No"
		if node.ManagerStatus.Leader {
			leader = "Yes"
		}
		fmt.Fprintf(out, " Leader:\t\t%s\n", leader)
	}

	fmt.Fprintln(out, "Platform:")
	fmt.Fprintf(out, " Operating System:\t%s\n", node.Description.Platform.OS)
	fmt.Fprintf(out, " Architecture:\t\t%s\n", node.Description.Platform.Architecture)

	fmt.Fprintln(out, "Resources:")
	fmt.Fprintf(out, " CPUs:\t\t\t%d\n", node.Description.Resources.NanoCPUs/1e9)
	fmt.Fprintf(out, " Memory:\t\t%s\n", units.BytesSize(float64(node.Description.Resources.MemoryBytes)))

	var pluginTypes []string
	pluginNamesByType := map[string][]string{}
	for _, p := range node.Description.Engine.Plugins {
		// append to pluginTypes only if not done previously
		if _, ok := pluginNamesByType[p.Type]; !ok {
			pluginTypes = append(pluginTypes, p.Type)
		}
		pluginNamesByType[p.Type] = append(pluginNamesByType[p.Type], p.Name)
	}

	if len(pluginTypes) > 0 {
		fmt.Fprintln(out, "Plugins:")
		sort.Strings(pluginTypes) // ensure stable output
		for _, pluginType := range pluginTypes {
			fmt.Fprintf(out, "  %s:\t\t%s\n", pluginType, strings.Join(pluginNamesByType[pluginType], ", "))
		}
	}
	fmt.Fprintf(out, "Engine Version:\t\t%s\n", node.Description.Engine.EngineVersion)

	if len(node.Description.Engine.Labels) != 0 {
		fmt.Fprintln(out, "Engine Labels:")
		for k, v := range node.Description.Engine.Labels {
			fmt.Fprintf(out, " - %s = %s", k, v)
		}
	}

}
<|endoftext|>


<commit_before>package app_test

import (
	"bytes"
	"net/http/httptest"
	"net/url"
	"testing"
	"time"

	"github.com/gorilla/mux"
	"github.com/ugorji/go/codec"
	"k8s.io/kubernetes/pkg/api"

	"github.com/weaveworks/common/test"
	"github.com/weaveworks/scope/app"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/render/detailed"
	"github.com/weaveworks/scope/render/expected"
	"github.com/weaveworks/scope/report"
	"github.com/weaveworks/scope/test/fixture"
	"github.com/weaveworks/scope/test/reflect"
	"github.com/weaveworks/scope/test/utils"
)

const (
	systemGroupID                   = "system"
	customAPITopologyOptionFilterID = "containerLabelFilter0"
)

func TestAPITopology(t *testing.T) {
	ts := topologyServer()
	defer ts.Close()

	body := getRawJSON(t, ts, "/api/topology")

	var topologies []app.APITopologyDesc
	decoder := codec.NewDecoderBytes(body, &codec.JsonHandle{})
	if err := decoder.Decode(&topologies); err != nil {
		t.Fatalf("JSON parse error: %s", err)
	}
	equals(t, 5, len(topologies))

	for _, topology := range topologies {
		is200(t, ts, topology.URL)

		for _, subTopology := range topology.SubTopologies {
			is200(t, ts, subTopology.URL)
		}

		// TODO: add ECS nodes in report fixture
		if topology.Name == "Tasks" {
			continue
		}

		if have := topology.Stats.EdgeCount; have <= 0 {
			t.Errorf("EdgeCount isn't positive for %s: %d", topology.Name, have)
		}

		if have := topology.Stats.NodeCount; have <= 0 {
			t.Errorf("NodeCount isn't positive for %s: %d", topology.Name, have)
		}

		if have := topology.Stats.NonpseudoNodeCount; have <= 0 {
			t.Errorf("NonpseudoNodeCount isn't positive for %s: %d", topology.Name, have)
		}
	}
}

func TestContainerLabelFilter(t *testing.T) {
	topologySummaries, err := getTestContainerLabelFilterTopologySummary(t, false)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	// only the filtered container with fixture.TestLabelKey1 should be present
	equals(t, 1, len(topologySummaries))
	for key := range topologySummaries {
		equals(t, report.MakeContainerNodeID(fixture.ClientContainerID), key)
	}
}

func TestContainerLabelFilterExclude(t *testing.T) {
	topologySummaries, err := getTestContainerLabelFilterTopologySummary(t, true)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	// all containers but the excluded container should be present
	for key := range topologySummaries {
		id := report.MakeContainerNodeID(fixture.ServerContainerNodeID)
		if id == key {
			t.Errorf("Didn't expect to find %q in report", id)
		}
	}
}

func TestRendererForTopologyWithFiltering(t *testing.T) {
	ts := topologyServer()
	defer ts.Close()

	topologyRegistry := app.MakeRegistry()
	option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", render.IsApplication, false)
	topologyRegistry.AddContainerFilters(option)

	urlvalues := url.Values{}
	urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
	renderer, decorator, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	input := fixture.Report.Copy()
	input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{
		docker.LabelPrefix + "works.weave.role": "system",
	})
	have := utils.Prune(renderer.Render(input, decorator))
	want := utils.Prune(expected.RenderedContainers.Copy())
	delete(want, fixture.ClientContainerNodeID)
	delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID))
	delete(want, render.OutgoingInternetID)
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}

func TestRendererForTopologyNoFiltering(t *testing.T) {
	ts := topologyServer()
	defer ts.Close()

	topologyRegistry := app.MakeRegistry()
	option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", nil, false)
	topologyRegistry.AddContainerFilters(option)

	urlvalues := url.Values{}
	urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
	renderer, decorator, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	input := fixture.Report.Copy()
	input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{
		docker.LabelPrefix + "works.weave.role": "system",
	})
	have := utils.Prune(renderer.Render(input, decorator))
	want := utils.Prune(expected.RenderedContainers.Copy())
	delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID))
	delete(want, render.OutgoingInternetID)
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}

func getTestContainerLabelFilterTopologySummary(t *testing.T, exclude bool) (detailed.NodeSummaries, error) {
	ts := topologyServer()
	defer ts.Close()

	var (
		topologyRegistry = app.MakeRegistry()
		filter           render.FilterFunc
	)
	if exclude == true {
		filter = render.DoesNotHaveLabel(fixture.TestLabelKey2, fixture.ApplicationLabelValue2)
	} else {
		filter = render.HasLabel(fixture.TestLabelKey1, fixture.ApplicationLabelValue1)
	}
	option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", filter, false)
	topologyRegistry.AddContainerFilters(option)

	urlvalues := url.Values{}
	urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
	renderer, decorator, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
	if err != nil {
		return nil, err
	}

	return detailed.Summaries(fixture.Report, renderer.Render(fixture.Report, decorator)), nil
}

func TestAPITopologyAddsKubernetes(t *testing.T) {
	router := mux.NewRouter()
	c := app.NewCollector(1 * time.Minute)
	app.RegisterReportPostHandler(c, router)
	app.RegisterTopologyRoutes(router, c)
	ts := httptest.NewServer(router)
	defer ts.Close()

	body := getRawJSON(t, ts, "/api/topology")

	var topologies []app.APITopologyDesc
	decoder := codec.NewDecoderBytes(body, &codec.JsonHandle{})
	if err := decoder.Decode(&topologies); err != nil {
		t.Fatalf("JSON parse error: %s", err)
	}
	equals(t, 5, len(topologies))

	// Enable the kubernetes topologies
	rpt := report.MakeReport()
	rpt.Pod = report.MakeTopology()
	rpt.Pod.Nodes[fixture.ClientPodNodeID] = kubernetes.NewPod(&api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name:      "pong-a",
			Namespace: "ping",
			Labels:    map[string]string{"ponger": "true"},
		},
		Status: api.PodStatus{
			HostIP: "1.2.3.4",
			ContainerStatuses: []api.ContainerStatus{
				{ContainerID: "container1"},
				{ContainerID: "container2"},
			},
		},
		Spec: api.PodSpec{
			SecurityContext: &api.PodSecurityContext{},
		},
	}).GetNode("")
	buf := &bytes.Buffer{}
	encoder := codec.NewEncoder(buf, &codec.MsgpackHandle{})
	if err := encoder.Encode(rpt); err != nil {
		t.Fatalf("GOB encoding error: %s", err)
	}
	checkRequest(t, ts, "POST", "/api/report", buf.Bytes())

	body = getRawJSON(t, ts, "/api/topology")
	decoder = codec.NewDecoderBytes(body, &codec.JsonHandle{})
	if err := decoder.Decode(&topologies); err != nil {
		t.Fatalf("JSON parse error: %s", err)
	}
	equals(t, 5, len(topologies))

	found := false
	for _, topology := range topologies {
		if topology.Name == "Pods" {
			found = true
			break
		}
	}
	if !found {
		t.Error("Could not find pods topology")
	}
}
<commit_msg>api_topologies: Fix tests<commit_after>package app_test

import (
	"bytes"
	"net/http/httptest"
	"net/url"
	"testing"
	"time"

	"github.com/gorilla/mux"
	"github.com/ugorji/go/codec"
	"k8s.io/kubernetes/pkg/api"

	"github.com/weaveworks/common/test"
	"github.com/weaveworks/scope/app"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/render/detailed"
	"github.com/weaveworks/scope/render/expected"
	"github.com/weaveworks/scope/report"
	"github.com/weaveworks/scope/test/fixture"
	"github.com/weaveworks/scope/test/reflect"
	"github.com/weaveworks/scope/test/utils"
)

const (
	systemGroupID                   = "system"
	customAPITopologyOptionFilterID = "containerLabelFilter0"
)

func TestAPITopology(t *testing.T) {
	ts := topologyServer()
	defer ts.Close()

	body := getRawJSON(t, ts, "/api/topology")

	var topologies []app.APITopologyDesc
	decoder := codec.NewDecoderBytes(body, &codec.JsonHandle{})
	if err := decoder.Decode(&topologies); err != nil {
		t.Fatalf("JSON parse error: %s", err)
	}
	equals(t, 5, len(topologies))

	for _, topology := range topologies {
		is200(t, ts, topology.URL)

		for _, subTopology := range topology.SubTopologies {
			is200(t, ts, subTopology.URL)
		}

		// TODO: add ECS nodes in report fixture
		if topology.Name == "Tasks" {
			continue
		}

		if have := topology.Stats.EdgeCount; have <= 0 {
			t.Errorf("EdgeCount isn't positive for %s: %d", topology.Name, have)
		}

		if have := topology.Stats.NodeCount; have <= 0 {
			t.Errorf("NodeCount isn't positive for %s: %d", topology.Name, have)
		}

		if have := topology.Stats.NonpseudoNodeCount; have <= 0 {
			t.Errorf("NonpseudoNodeCount isn't positive for %s: %d", topology.Name, have)
		}
	}
}

func TestContainerLabelFilter(t *testing.T) {
	topologySummaries, err := getTestContainerLabelFilterTopologySummary(t, false)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	// only the filtered container with fixture.TestLabelKey1 should be present
	equals(t, 1, len(topologySummaries))
	for key := range topologySummaries {
		equals(t, report.MakeContainerNodeID(fixture.ClientContainerID), key)
	}
}

func TestContainerLabelFilterExclude(t *testing.T) {
	topologySummaries, err := getTestContainerLabelFilterTopologySummary(t, true)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	// all containers but the excluded container should be present
	for key := range topologySummaries {
		id := report.MakeContainerNodeID(fixture.ServerContainerNodeID)
		if id == key {
			t.Errorf("Didn't expect to find %q in report", id)
		}
	}
}

func TestRendererForTopologyWithFiltering(t *testing.T) {
	ts := topologyServer()
	defer ts.Close()

	topologyRegistry := app.MakeRegistry()
	option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", render.IsApplication, false)
	topologyRegistry.AddContainerFilters(option)

	urlvalues := url.Values{}
	urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
	urlvalues.Set("stopped", "running")
	urlvalues.Set("pseudo", "hide")
	renderer, decorator, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	input := fixture.Report.Copy()
	input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{
		docker.LabelPrefix + "works.weave.role": "system",
	})
	have := utils.Prune(renderer.Render(input, decorator))
	want := utils.Prune(expected.RenderedContainers.Copy())
	delete(want, fixture.ClientContainerNodeID)
	delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID))
	delete(want, render.OutgoingInternetID)
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}

func TestRendererForTopologyNoFiltering(t *testing.T) {
	ts := topologyServer()
	defer ts.Close()

	topologyRegistry := app.MakeRegistry()
	option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", nil, false)
	topologyRegistry.AddContainerFilters(option)

	urlvalues := url.Values{}
	urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
	urlvalues.Set("stopped", "running")
	urlvalues.Set("pseudo", "hide")
	renderer, decorator, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
	if err != nil {
		t.Fatalf("Topology Registry Report error: %s", err)
	}

	input := fixture.Report.Copy()
	input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{
		docker.LabelPrefix + "works.weave.role": "system",
	})
	have := utils.Prune(renderer.Render(input, decorator))
	want := utils.Prune(expected.RenderedContainers.Copy())
	delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID))
	delete(want, render.OutgoingInternetID)
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}

func getTestContainerLabelFilterTopologySummary(t *testing.T, exclude bool) (detailed.NodeSummaries, error) {
	ts := topologyServer()
	defer ts.Close()

	var (
		topologyRegistry = app.MakeRegistry()
		filter           render.FilterFunc
	)
	if exclude == true {
		filter = render.DoesNotHaveLabel(fixture.TestLabelKey2, fixture.ApplicationLabelValue2)
	} else {
		filter = render.HasLabel(fixture.TestLabelKey1, fixture.ApplicationLabelValue1)
	}
	option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", filter, false)
	topologyRegistry.AddContainerFilters(option)

	urlvalues := url.Values{}
	urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
	urlvalues.Set("stopped", "running")
	urlvalues.Set("pseudo", "hide")
	renderer, decorator, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
	if err != nil {
		return nil, err
	}

	return detailed.Summaries(fixture.Report, renderer.Render(fixture.Report, decorator)), nil
}

func TestAPITopologyAddsKubernetes(t *testing.T) {
	router := mux.NewRouter()
	c := app.NewCollector(1 * time.Minute)
	app.RegisterReportPostHandler(c, router)
	app.RegisterTopologyRoutes(router, c)
	ts := httptest.NewServer(router)
	defer ts.Close()

	body := getRawJSON(t, ts, "/api/topology")

	var topologies []app.APITopologyDesc
	decoder := codec.NewDecoderBytes(body, &codec.JsonHandle{})
	if err := decoder.Decode(&topologies); err != nil {
		t.Fatalf("JSON parse error: %s", err)
	}
	equals(t, 5, len(topologies))

	// Enable the kubernetes topologies
	rpt := report.MakeReport()
	rpt.Pod = report.MakeTopology()
	rpt.Pod.Nodes[fixture.ClientPodNodeID] = kubernetes.NewPod(&api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name:      "pong-a",
			Namespace: "ping",
			Labels:    map[string]string{"ponger": "true"},
		},
		Status: api.PodStatus{
			HostIP: "1.2.3.4",
			ContainerStatuses: []api.ContainerStatus{
				{ContainerID: "container1"},
				{ContainerID: "container2"},
			},
		},
		Spec: api.PodSpec{
			SecurityContext: &api.PodSecurityContext{},
		},
	}).GetNode("")
	buf := &bytes.Buffer{}
	encoder := codec.NewEncoder(buf, &codec.MsgpackHandle{})
	if err := encoder.Encode(rpt); err != nil {
		t.Fatalf("GOB encoding error: %s", err)
	}
	checkRequest(t, ts, "POST", "/api/report", buf.Bytes())

	body = getRawJSON(t, ts, "/api/topology")
	decoder = codec.NewDecoderBytes(body, &codec.JsonHandle{})
	if err := decoder.Decode(&topologies); err != nil {
		t.Fatalf("JSON parse error: %s", err)
	}
	equals(t, 5, len(topologies))

	found := false
	for _, topology := range topologies {
		if topology.Name == "Pods" {
			found = true
			break
		}
	}
	if !found {
		t.Error("Could not find pods topology")
	}
}
<|endoftext|>


<commit_before>package schema

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"sync"

	"github.com/mitchellh/mapstructure"
)

// MapFieldWriter writes data into a single map[string]string structure.
type MapFieldWriter struct {
	Schema map[string]*Schema

	lock   sync.Mutex
	result map[string]string
}

// Map returns the underlying map that is being written to.
func (w *MapFieldWriter) Map() map[string]string {
	w.lock.Lock()
	defer w.lock.Unlock()
	if w.result == nil {
		w.result = make(map[string]string)
	}

	return w.result
}

func (w *MapFieldWriter) WriteField(addr []string, value interface{}) error {
	w.lock.Lock()
	defer w.lock.Unlock()
	if w.result == nil {
		w.result = make(map[string]string)
	}

	schemaList := addrToSchema(addr, w.Schema)
	if len(schemaList) == 0 {
		return fmt.Errorf("Invalid address to set: %#v", addr)
	}

	// If we're setting anything other than a list root or set root,
	// then disallow it.
	for _, schema := range schemaList[:len(schemaList)-1] {
		if schema.Type == TypeList {
			return fmt.Errorf(
				"%s: can only set full list",
				strings.Join(addr, "."))
		}

		if schema.Type == TypeMap {
			return fmt.Errorf(
				"%s: can only set full map",
				strings.Join(addr, "."))
		}

		if schema.Type == TypeSet {
			return fmt.Errorf(
				"%s: can only set full set",
				strings.Join(addr, "."))
		}
	}

	return w.set(addr, value)
}

func (w *MapFieldWriter) set(addr []string, value interface{}) error {
	schemaList := addrToSchema(addr, w.Schema)
	if len(schemaList) == 0 {
		return fmt.Errorf("Invalid address to set: %#v", addr)
	}

	schema := schemaList[len(schemaList)-1]
	switch schema.Type {
	case TypeBool:
		fallthrough
	case TypeInt:
		fallthrough
	case TypeString:
		return w.setPrimitive(addr, value, schema)
	case TypeList:
		return w.setList(addr, value, schema)
	case TypeMap:
		return w.setMap(addr, value, schema)
	case TypeSet:
		return w.setSet(addr, value, schema)
	case typeObject:
		return w.setObject(addr, value, schema)
	default:
		panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
	}
}

func (w *MapFieldWriter) setList(
	addr []string,
	v interface{},
	schema *Schema) error {
	k := strings.Join(addr, ".")
	setElement := func(idx string, value interface{}) error {
		addrCopy := make([]string, len(addr), len(addr)+1)
		copy(addrCopy, addr)
		return w.set(append(addrCopy, idx), value)
	}

	var vs []interface{}
	if err := mapstructure.Decode(v, &vs); err != nil {
		return fmt.Errorf("%s: %s", k, err)
	}

	// Set the entire list.
	var err error
	for i, elem := range vs {
		is := strconv.FormatInt(int64(i), 10)
		err = setElement(is, elem)
		if err != nil {
			break
		}
	}
	if err != nil {
		for i, _ := range vs {
			is := strconv.FormatInt(int64(i), 10)
			setElement(is, nil)
		}

		return err
	}

	w.result[k+".#"] = strconv.FormatInt(int64(len(vs)), 10)
	return nil
}

func (w *MapFieldWriter) setMap(
	addr []string,
	value interface{},
	schema *Schema) error {
	k := strings.Join(addr, ".")
	v := reflect.ValueOf(value)
	vs := make(map[string]interface{})

	if value != nil {
		if v.Kind() != reflect.Map {
			return fmt.Errorf("%s: must be a map", k)
		}
		if v.Type().Key().Kind() != reflect.String {
			return fmt.Errorf("%s: keys must strings", k)
		}
		for _, mk := range v.MapKeys() {
			mv := v.MapIndex(mk)
			vs[mk.String()] = mv.Interface()
		}
	}

	if len(vs) == 0 {
		// The empty string here means the map is removed.
		w.result[k] = ""
		return nil
	}

	// Remove the pure key since we're setting the full map value
	delete(w.result, k)

	// Set each subkey
	addrCopy := make([]string, len(addr), len(addr)+1)
	copy(addrCopy, addr)
	for subKey, v := range vs {
		if err := w.set(append(addrCopy, subKey), v); err != nil {
			return err
		}
	}

	// Set the count
	w.result[k+".#"] = strconv.Itoa(len(vs))

	return nil
}

func (w *MapFieldWriter) setObject(
	addr []string,
	value interface{},
	schema *Schema) error {
	// Set the entire object. First decode into a proper structure
	var v map[string]interface{}
	if err := mapstructure.Decode(value, &v); err != nil {
		return fmt.Errorf("%s: %s", strings.Join(addr, "."), err)
	}

	// Make space for additional elements in the address
	addrCopy := make([]string, len(addr), len(addr)+1)
	copy(addrCopy, addr)

	// Set each element in turn
	var err error
	for k1, v1 := range v {
		if err = w.set(append(addrCopy, k1), v1); err != nil {
			break
		}
	}
	if err != nil {
		for k1, _ := range v {
			w.set(append(addrCopy, k1), nil)
		}
	}

	return err
}

func (w *MapFieldWriter) setPrimitive(
	addr []string,
	v interface{},
	schema *Schema) error {
	k := strings.Join(addr, ".")

	if v == nil {
		delete(w.result, k)
		return nil
	}

	var set string
	switch schema.Type {
	case TypeBool:
		var b bool
		if err := mapstructure.Decode(v, &b); err != nil {
			return fmt.Errorf("%s: %s", k, err)
		}

		set = strconv.FormatBool(b)
	case TypeString:
		if err := mapstructure.Decode(v, &set); err != nil {
			return fmt.Errorf("%s: %s", k, err)
		}
	case TypeInt:
		var n int
		if err := mapstructure.Decode(v, &n); err != nil {
			return fmt.Errorf("%s: %s", k, err)
		}

		set = strconv.FormatInt(int64(n), 10)
	default:
		return fmt.Errorf("Unknown type: %#v", schema.Type)
	}

	w.result[k] = set
	return nil
}

func (w *MapFieldWriter) setSet(
	addr []string,
	value interface{},
	schema *Schema) error {
	addrCopy := make([]string, len(addr), len(addr)+1)
	copy(addrCopy, addr)

	// If it is a slice, then we have to turn it into a *Set so that
	// we get the proper order back based on the hash code.
	if v := reflect.ValueOf(value); v.Kind() == reflect.Slice {
		// Build a temp *ResourceData to use for the conversion
		tempSchema := *schema
		tempSchema.Type = TypeList
		tempSchemaMap := map[string]*Schema{addr[0]: &tempSchema}
		tempW := &MapFieldWriter{Schema: tempSchemaMap}

		// Set the entire list, this lets us get sane values out of it
		if err := tempW.WriteField(addr, value); err != nil {
			return err
		}

		// Build the set by going over the list items in order and
		// hashing them into the set. The reason we go over the list and
		// not the `value` directly is because this forces all types
		// to become []interface{} (generic) instead of []string, which
		// most hash functions are expecting.
		s := &Set{F: schema.Set}
		tempR := &MapFieldReader{
			Map:    BasicMapReader(tempW.Map()),
			Schema: tempSchemaMap,
		}
		for i := 0; i < v.Len(); i++ {
			is := strconv.FormatInt(int64(i), 10)
			result, err := tempR.ReadField(append(addrCopy, is))
			if err != nil {
				return err
			}
			if !result.Exists {
				panic("set item just set doesn't exist")
			}

			s.Add(result.Value)
		}

		value = s
	}

	k := strings.Join(addr, ".")

	if value != nil {
		for code, elem := range value.(*Set).m {
			codeStr := strconv.FormatInt(int64(code), 10)
			if err := w.set(append(addrCopy, codeStr), elem); err != nil {
				return err
			}
		}
		w.result[k+".#"] = strconv.Itoa(value.(*Set).Len())
	}
	return nil
}
<commit_msg>Fixes #813: Ensuring set count (.#) is written to the state<commit_after>package schema

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"sync"

	"github.com/mitchellh/mapstructure"
)

// MapFieldWriter writes data into a single map[string]string structure.
type MapFieldWriter struct {
	Schema map[string]*Schema

	lock   sync.Mutex
	result map[string]string
}

// Map returns the underlying map that is being written to.
func (w *MapFieldWriter) Map() map[string]string {
	w.lock.Lock()
	defer w.lock.Unlock()
	if w.result == nil {
		w.result = make(map[string]string)
	}

	return w.result
}

func (w *MapFieldWriter) WriteField(addr []string, value interface{}) error {
	w.lock.Lock()
	defer w.lock.Unlock()
	if w.result == nil {
		w.result = make(map[string]string)
	}

	schemaList := addrToSchema(addr, w.Schema)
	if len(schemaList) == 0 {
		return fmt.Errorf("Invalid address to set: %#v", addr)
	}

	// If we're setting anything other than a list root or set root,
	// then disallow it.
	for _, schema := range schemaList[:len(schemaList)-1] {
		if schema.Type == TypeList {
			return fmt.Errorf(
				"%s: can only set full list",
				strings.Join(addr, "."))
		}

		if schema.Type == TypeMap {
			return fmt.Errorf(
				"%s: can only set full map",
				strings.Join(addr, "."))
		}

		if schema.Type == TypeSet {
			return fmt.Errorf(
				"%s: can only set full set",
				strings.Join(addr, "."))
		}
	}

	return w.set(addr, value)
}

func (w *MapFieldWriter) set(addr []string, value interface{}) error {
	schemaList := addrToSchema(addr, w.Schema)
	if len(schemaList) == 0 {
		return fmt.Errorf("Invalid address to set: %#v", addr)
	}

	schema := schemaList[len(schemaList)-1]
	switch schema.Type {
	case TypeBool:
		fallthrough
	case TypeInt:
		fallthrough
	case TypeString:
		return w.setPrimitive(addr, value, schema)
	case TypeList:
		return w.setList(addr, value, schema)
	case TypeMap:
		return w.setMap(addr, value, schema)
	case TypeSet:
		return w.setSet(addr, value, schema)
	case typeObject:
		return w.setObject(addr, value, schema)
	default:
		panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
	}
}

func (w *MapFieldWriter) setList(
	addr []string,
	v interface{},
	schema *Schema) error {
	k := strings.Join(addr, ".")
	setElement := func(idx string, value interface{}) error {
		addrCopy := make([]string, len(addr), len(addr)+1)
		copy(addrCopy, addr)
		return w.set(append(addrCopy, idx), value)
	}

	var vs []interface{}
	if err := mapstructure.Decode(v, &vs); err != nil {
		return fmt.Errorf("%s: %s", k, err)
	}

	// Set the entire list.
	var err error
	for i, elem := range vs {
		is := strconv.FormatInt(int64(i), 10)
		err = setElement(is, elem)
		if err != nil {
			break
		}
	}
	if err != nil {
		for i, _ := range vs {
			is := strconv.FormatInt(int64(i), 10)
			setElement(is, nil)
		}

		return err
	}

	w.result[k+".#"] = strconv.FormatInt(int64(len(vs)), 10)
	return nil
}

func (w *MapFieldWriter) setMap(
	addr []string,
	value interface{},
	schema *Schema) error {
	k := strings.Join(addr, ".")
	v := reflect.ValueOf(value)
	vs := make(map[string]interface{})

	if value != nil {
		if v.Kind() != reflect.Map {
			return fmt.Errorf("%s: must be a map", k)
		}
		if v.Type().Key().Kind() != reflect.String {
			return fmt.Errorf("%s: keys must strings", k)
		}
		for _, mk := range v.MapKeys() {
			mv := v.MapIndex(mk)
			vs[mk.String()] = mv.Interface()
		}
	}

	if len(vs) == 0 {
		// The empty string here means the map is removed.
		w.result[k] = ""
		return nil
	}

	// Remove the pure key since we're setting the full map value
	delete(w.result, k)

	// Set each subkey
	addrCopy := make([]string, len(addr), len(addr)+1)
	copy(addrCopy, addr)
	for subKey, v := range vs {
		if err := w.set(append(addrCopy, subKey), v); err != nil {
			return err
		}
	}

	// Set the count
	w.result[k+".#"] = strconv.Itoa(len(vs))

	return nil
}

func (w *MapFieldWriter) setObject(
	addr []string,
	value interface{},
	schema *Schema) error {
	// Set the entire object. First decode into a proper structure
	var v map[string]interface{}
	if err := mapstructure.Decode(value, &v); err != nil {
		return fmt.Errorf("%s: %s", strings.Join(addr, "."), err)
	}

	// Make space for additional elements in the address
	addrCopy := make([]string, len(addr), len(addr)+1)
	copy(addrCopy, addr)

	// Set each element in turn
	var err error
	for k1, v1 := range v {
		if err = w.set(append(addrCopy, k1), v1); err != nil {
			break
		}
	}
	if err != nil {
		for k1, _ := range v {
			w.set(append(addrCopy, k1), nil)
		}
	}

	return err
}

func (w *MapFieldWriter) setPrimitive(
	addr []string,
	v interface{},
	schema *Schema) error {
	k := strings.Join(addr, ".")

	if v == nil {
		delete(w.result, k)
		return nil
	}

	var set string
	switch schema.Type {
	case TypeBool:
		var b bool
		if err := mapstructure.Decode(v, &b); err != nil {
			return fmt.Errorf("%s: %s", k, err)
		}

		set = strconv.FormatBool(b)
	case TypeString:
		if err := mapstructure.Decode(v, &set); err != nil {
			return fmt.Errorf("%s: %s", k, err)
		}
	case TypeInt:
		var n int
		if err := mapstructure.Decode(v, &n); err != nil {
			return fmt.Errorf("%s: %s", k, err)
		}

		set = strconv.FormatInt(int64(n), 10)
	default:
		return fmt.Errorf("Unknown type: %#v", schema.Type)
	}

	w.result[k] = set
	return nil
}

func (w *MapFieldWriter) setSet(
	addr []string,
	value interface{},
	schema *Schema) error {
	addrCopy := make([]string, len(addr), len(addr)+1)
	copy(addrCopy, addr)

	// If it is a slice, then we have to turn it into a *Set so that
	// we get the proper order back based on the hash code.
	if v := reflect.ValueOf(value); v.Kind() == reflect.Slice {
		// Build a temp *ResourceData to use for the conversion
		tempSchema := *schema
		tempSchema.Type = TypeList
		tempSchemaMap := map[string]*Schema{addr[0]: &tempSchema}
		tempW := &MapFieldWriter{Schema: tempSchemaMap}

		// Set the entire list, this lets us get sane values out of it
		if err := tempW.WriteField(addr, value); err != nil {
			return err
		}

		// Build the set by going over the list items in order and
		// hashing them into the set. The reason we go over the list and
		// not the `value` directly is because this forces all types
		// to become []interface{} (generic) instead of []string, which
		// most hash functions are expecting.
		s := &Set{F: schema.Set}
		tempR := &MapFieldReader{
			Map:    BasicMapReader(tempW.Map()),
			Schema: tempSchemaMap,
		}
		for i := 0; i < v.Len(); i++ {
			is := strconv.FormatInt(int64(i), 10)
			result, err := tempR.ReadField(append(addrCopy, is))
			if err != nil {
				return err
			}
			if !result.Exists {
				panic("set item just set doesn't exist")
			}

			s.Add(result.Value)
		}

		value = s
	}

	k := strings.Join(addr, ".")

	if value == nil {
		w.result[k+".#"] = "0"
		return nil
	}

	for code, elem := range value.(*Set).m {
		codeStr := strconv.FormatInt(int64(code), 10)
		if err := w.set(append(addrCopy, codeStr), elem); err != nil {
			return err
		}
	}

	w.result[k+".#"] = strconv.Itoa(value.(*Set).Len())
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/BurntSushi/toml"
)

//VERSION of the program
var version = "undefined-autogenerated"

//Config data struct to read the config file
type Config struct {
	NMAPRange    string
	NMAPPorts    string //comma separated
	HTTPPort     int
	ScanInterval int //seconds
}

//ReadConfig reads the config file
func readConfig(configfile string) Config {
	var config Config
	if _, err := toml.DecodeFile(configfile, &config); err != nil {
		log.Fatal(err)
	}
	return config
}

func callNMAP(conf Config) {
	log.Println("Starting nmap caller")
	var counter = 1
	var tempScanFileName = "temp_scan.xml"
	var scanResultsFileName = "scan.xml"

	cmd := exec.Command("nmap", "-p", conf.NMAPPorts, "-oX", tempScanFileName, conf.NMAPRange)
	for {
		log.Println("Init NMAP scan no:", counter)
		var out bytes.Buffer
		cmd.Stdout = &out
		err := cmd.Run()
		if err != nil {
			log.Println(err)
		}
		log.Println("Scan no.", counter, "complete")
		counter = counter + 1

		n, err := copyScanResult(tempScanFileName, scanResultsFileName)
		if err != nil {
			log.Printf("copying scan data failed: %v\n", err)
		}
		log.Printf("Scan results saved %v bytes\n", n)
		<-time.After(time.Duration(conf.ScanInterval) * time.Second)
	}
}

func copyScanResult(tempScanFileName, scanResultsFileName string) (int64, error) {
	//copy to the scan.xml
	r, err := os.Open(tempScanFileName)
	if err != nil {
		return -1, err
	}
	defer r.Close()

	w, err := os.Create(scanResultsFileName)
	if err != nil {
		return -1, err
	}
	defer w.Close()

	// do the actual work
	n, err := io.Copy(w, r)
	if err != nil {
		return -1, err
	}
	return n, nil
}

func pageHandler(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path[1:]
	log.Println("URL path: " + path)

	//in case we have no path refer/redirect to index.html
	if len(path) == 0 {
		path = "index.html"
	}

	f, err := os.Open(path)
	if err == nil {
		Reader := bufio.NewReader(f)

		var contentType string

		if strings.HasSuffix(path, "css") {
			contentType = "text/css"
		} else if strings.HasSuffix(path, ".html") {
			contentType = "text/html"
		} else if strings.HasSuffix(path, ".js") {
			contentType = "application/javascript"
		} else if strings.HasSuffix(path, ".png") {
			contentType = "image/png"
		} else if strings.HasSuffix(path, ".svg") {
			contentType = "image/svg+xml"
		} else {
			contentType = "text/plain"
		}

		w.Header().Add("Content Type", contentType)
		Reader.WriteTo(w)
	} else {
		w.WriteHeader(404)
		fmt.Fprintln(w, "404 - "+http.StatusText(404))
	}
}

func main() {
	log.Println("Starting lan-monitor-server ver: " + version)

	//process the config
	//1st the config file is read and set parameters applied
	//2nd the command line parameters are interpreted,
	//if they are set they will overrule the config file
	//3rd if none of the above is applied the program reverts to the hardcoded defaults

	//defaults
	var config Config
	defaultConfigFileLocation := "/etc/lan-monitor.conf"
	config.HTTPPort = 8080
	config.NMAPRange = "192.168.0.1/24"
	config.NMAPPorts = "22,80"
	config.ScanInterval = 120 //seconds

	displayVersion := flag.Bool("version", false, "Prints the version number")
	cmdlineHTTPPort := flag.Int("port", config.HTTPPort, "HTTP port for the webserver")
	cmdlineNMAPScanRange := flag.String("range", config.NMAPRange, "The range NMAP should scan e.g. 192.168.1.1/24 it has to be nmap compatible")
	cmdlineScanInterval := flag.Int("scan-rate", config.ScanInterval, "The interval of the scans in seconds")
	configFileLocation := flag.String("config-file", defaultConfigFileLocation, "Location of the config file")
	cmdlinePorts := flag.String("scan-ports", config.NMAPPorts, "The ports that will be scanned")
	flag.Parse()

	//try to read the configfile
	_, err := os.Stat(*configFileLocation)
	if err == nil {
		config = readConfig(*configFileLocation)
	} else {
		log.Println("Config file is missing - looked at:", *configFileLocation)
		log.Println("Reverting to commandline/defaults")
	}

	//if no range is defined in the config file
	if config.NMAPRange == "" {
		config.NMAPRange = *cmdlineNMAPScanRange
	}

	//if no port is defined in the config file
	if config.HTTPPort == 0 {
		config.HTTPPort = *cmdlineHTTPPort
	}

	//if no scan interval is defined in the config file
	if config.ScanInterval == 0 {
		config.ScanInterval = *cmdlineScanInterval
	}

	//if no ports to be scanned are defined
	if config.NMAPPorts == "" {
		config.NMAPPorts = *cmdlinePorts
	}

	log.Println("Config - range:", config.NMAPRange, "webserver port:", config.HTTPPort, "interval:", config.ScanInterval, "sec", "scan-ports", config.NMAPPorts)

	if *displayVersion == true {
		fmt.Println("Version: " + version)
		return
	}

	//changing working dir
	log.Println("Changing working dir to: ")
	err = os.Chdir("../www")
	if err != nil {
		log.Fatalln("Unable to switch working dir")
	}

	workingDir, _ := os.Getwd()
	log.Println("Dir:" + workingDir)

	//init the scanning routine
	go callNMAP(config)

	//starting the webserver
	http.HandleFunc("/", pageHandler)
	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(config.HTTPPort), nil))
}
<commit_msg>changed to in-built go file server<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"time"

	"github.com/BurntSushi/toml"
)

//VERSION of the program
var version = "undefined-autogenerated"

//Config data struct to read the config file
type Config struct {
	NMAPRange    string
	NMAPPorts    string //comma separated
	HTTPPort     int
	ScanInterval int //seconds
}

//ReadConfig reads the config file
func readConfig(configfile string) Config {
	var config Config
	if _, err := toml.DecodeFile(configfile, &config); err != nil {
		log.Fatal(err)
	}
	return config
}

func callNMAP(conf Config) {
	log.Println("Starting nmap caller")
	var counter = 1
	var tempScanFileName = "temp_scan.xml"
	var scanResultsFileName = "scan.xml"

	cmd := exec.Command("nmap", "-p", conf.NMAPPorts, "-oX", tempScanFileName, conf.NMAPRange)
	for {
		log.Println("Init NMAP scan no:", counter)
		var out bytes.Buffer
		cmd.Stdout = &out
		err := cmd.Run()
		if err != nil {
			log.Println(err)
		}
		log.Println("Scan no.", counter, "complete")
		counter = counter + 1

		n, err := copyScanResult(tempScanFileName, scanResultsFileName)
		if err != nil {
			log.Printf("copying scan data failed: %v\n", err)
		}
		log.Printf("Scan results saved %v bytes\n", n)
		<-time.After(time.Duration(conf.ScanInterval) * time.Second)
	}
}

func copyScanResult(tempScanFileName, scanResultsFileName string) (int64, error) {
	//copy to the scan.xml
	r, err := os.Open(tempScanFileName)
	if err != nil {
		return -1, err
	}
	defer r.Close()

	w, err := os.Create(scanResultsFileName)
	if err != nil {
		return -1, err
	}
	defer w.Close()

	// do the actual work
	n, err := io.Copy(w, r)
	if err != nil {
		return -1, err
	}
	return n, nil
}

func main() {
	log.Println("Starting lan-monitor-server ver: " + version)

	//process the config
	//1st the config file is read and set parameters applied
	//2nd the command line parameters are interpreted,
	//if they are set they will overrule the config file
	//3rd if none of the above is applied the program reverts to the hardcoded defaults

	//defaults
	var config Config
	defaultConfigFileLocation := "/etc/lan-monitor.conf"
	config.HTTPPort = 8080
	config.NMAPRange = "192.168.0.1/24"
	config.NMAPPorts = "22,80"
	config.ScanInterval = 120 //seconds

	displayVersion := flag.Bool("version", false, "Prints the version number")
	cmdlineHTTPPort := flag.Int("port", config.HTTPPort, "HTTP port for the webserver")
	cmdlineNMAPScanRange := flag.String("range", config.NMAPRange, "The range NMAP should scan e.g. 192.168.1.1/24 it has to be nmap compatible")
	cmdlineScanInterval := flag.Int("scan-rate", config.ScanInterval, "The interval of the scans in seconds")
	configFileLocation := flag.String("config-file", defaultConfigFileLocation, "Location of the config file")
	cmdlinePorts := flag.String("scan-ports", config.NMAPPorts, "The ports that will be scanned")
	flag.Parse()

	//try to read the configfile
	_, err := os.Stat(*configFileLocation)
	if err == nil {
		config = readConfig(*configFileLocation)
	} else {
		log.Println("Config file is missing - looked at:", *configFileLocation)
		log.Println("Reverting to commandline/defaults")
	}

	//if no range is defined in the config file
	if config.NMAPRange == "" {
		config.NMAPRange = *cmdlineNMAPScanRange
	}

	//if no port is defined in the config file
	if config.HTTPPort == 0 {
		config.HTTPPort = *cmdlineHTTPPort
	}

	//if no scan interval is defined in the config file
	if config.ScanInterval == 0 {
		config.ScanInterval = *cmdlineScanInterval
	}

	//if no ports to be scanned are defined
	if config.NMAPPorts == "" {
		config.NMAPPorts = *cmdlinePorts
	}

	log.Println("Config - range:", config.NMAPRange, "webserver port:", config.HTTPPort, "interval:", config.ScanInterval, "sec", "scan-ports", config.NMAPPorts)

	if *displayVersion == true {
		fmt.Println("Version: " + version)
		return
	}

	//changing working dir
	log.Println("Changing working dir to: ")
	err = os.Chdir("../www")
	if err != nil {
		log.Fatalln("Unable to switch working dir")
	}

	workingDir, _ := os.Getwd()
	log.Println("Dir:" + workingDir)

	//init the scanning routine
	go callNMAP(config)

	//starting and configuring the webserver
	fs := http.FileServer(http.Dir(workingDir))
	http.Handle("/", fs)
	listenAddress := ":" + strconv.Itoa(config.HTTPPort)
	log.Fatal(http.ListenAndServe(listenAddress, nil))
}
<|endoftext|>


<commit_before>package mount

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

const (
	/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
	   (1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)

	   (1) mount ID:  unique identifier of the mount (may be reused after umount)
	   (2) parent ID:  ID of parent (or of self for the top of the mount tree)
	   (3) major:minor:  value of st_dev for files on filesystem
	   (4) root:  root of the mount within the filesystem
	   (5) mount point:  mount point relative to the process's root
	   (6) mount options:  per mount options
	   (7) optional fields:  zero or more fields of the form "tag[:value]"
	   (8) separator:  marks the end of the optional fields
	   (9) filesystem type:  name of filesystem of the form "type[.subtype]"
	   (10) mount source:  filesystem specific information or "none"
	   (11) super options:  per super block options*/
	mountinfoFormat = "%d %d %d:%d %s %s %s "
)

// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts
func parseMountTable() ([]*MountInfo, error) {
	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return parseInfoFile(f)
}

func parseInfoFile(r io.Reader) ([]*MountInfo, error) {
	var (
		s   = bufio.NewScanner(r)
		out = []*MountInfo{}
	)

	for s.Scan() {
		if err := s.Err(); err != nil {
			return nil, err
		}

		var (
			p    = &MountInfo{}
			text = s.Text()
		)

		if _, err := fmt.Sscanf(text, mountinfoFormat,
			&p.Id, &p.Parent, &p.Major, &p.Minor,
			&p.Root, &p.Mountpoint, &p.Opts); err != nil {
			return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
		}
		// Safe as mountinfo encodes mountpoints with spaces as \040.
		index := strings.Index(text, " - ")
		postSeparatorFields := strings.Fields(text[index+3:])
		if len(postSeparatorFields) < 3 {
			return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
		}

		p.Fstype = postSeparatorFields[0]
		p.Source = postSeparatorFields[1]
		p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
		out = append(out, p)
	}
	return out, nil
}
<commit_msg>pkg/mount: mountinfo from specified pid<commit_after>// +build linux

package mount

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

const (
	/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
	   (1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)

	   (1) mount ID:  unique identifier of the mount (may be reused after umount)
	   (2) parent ID:  ID of parent (or of self for the top of the mount tree)
	   (3) major:minor:  value of st_dev for files on filesystem
	   (4) root:  root of the mount within the filesystem
	   (5) mount point:  mount point relative to the process's root
	   (6) mount options:  per mount options
	   (7) optional fields:  zero or more fields of the form "tag[:value]"
	   (8) separator:  marks the end of the optional fields
	   (9) filesystem type:  name of filesystem of the form "type[.subtype]"
	   (10) mount source:  filesystem specific information or "none"
	   (11) super options:  per super block options*/
	mountinfoFormat = "%d %d %d:%d %s %s %s "
)

// Parse /proc/self/mountinfo because comparing Dev and ino does not work from bind mounts
func parseMountTable() ([]*MountInfo, error) {
	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return parseInfoFile(f)
}

func parseInfoFile(r io.Reader) ([]*MountInfo, error) {
	var (
		s   = bufio.NewScanner(r)
		out = []*MountInfo{}
	)

	for s.Scan() {
		if err := s.Err(); err != nil {
			return nil, err
		}

		var (
			p    = &MountInfo{}
			text = s.Text()
		)

		if _, err := fmt.Sscanf(text, mountinfoFormat,
			&p.Id, &p.Parent, &p.Major, &p.Minor,
			&p.Root, &p.Mountpoint, &p.Opts); err != nil {
			return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
		}
		// Safe as mountinfo encodes mountpoints with spaces as \040.
		index := strings.Index(text, " - ")
		postSeparatorFields := strings.Fields(text[index+3:])
		if len(postSeparatorFields) < 3 {
			return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
		}

		p.Fstype = postSeparatorFields[0]
		p.Source = postSeparatorFields[1]
		p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
		out = append(out, p)
	}
	return out, nil
}

// PidMountInfo collects the mounts for a specific Pid
func PidMountInfo(pid int) ([]*MountInfo, error) {
	f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return parseInfoFile(f)
}
<|endoftext|>