<commit_before>package bridge

import (
	"errors"
	"log"
	"net"
	"net/url"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"sync"

	dockerapi "github.com/fsouza/go-dockerclient"
)

var serviceIDPattern = regexp.MustCompile(`^(.+?):([a-zA-Z0-9][a-zA-Z0-9_.-]+):[0-9]+(?::udp)?$`)

type Bridge struct {
	sync.Mutex
	registry       RegistryAdapter
	docker         *dockerapi.Client
	services       map[string][]*Service
	deadContainers map[string]*DeadContainer
	config         Config
}

func New(docker *dockerapi.Client, adapterUri string, config Config) (*Bridge, error) {
	uri, err := url.Parse(adapterUri)
	if err != nil {
		return nil, errors.New("bad adapter uri: " + adapterUri)
	}
	factory, found := AdapterFactories.Lookup(uri.Scheme)
	if !found {
		return nil, errors.New("unrecognized adapter: " + adapterUri)
	}

	log.Println("Using", uri.Scheme, "adapter:", uri)
	return &Bridge{
		docker:         docker,
		config:         config,
		registry:       factory.New(uri),
		services:       make(map[string][]*Service),
		deadContainers: make(map[string]*DeadContainer),
	}, nil
}

func (b *Bridge) Ping() error {
	return b.registry.Ping()
}

func (b *Bridge) Add(containerId string) {
	b.add(containerId, false)
}

func (b *Bridge) Remove(containerId string) {
	b.remove(containerId, true)
}

func (b *Bridge) RemoveOnExit(containerId string) {
	b.remove(containerId, b.shouldRemove(containerId))
}

func (b *Bridge) Refresh() {
	for containerId, services := range b.getServicesCopy() {
		for _, service := range services {
			err := b.registry.Refresh(service)
			if err != nil {
				log.Println("refresh failed:", service.ID, err)
				continue
			}
			log.Println("refreshed:", containerId[:12], service.ID)
		}
	}
}

func (b *Bridge) PruneDeadContainers() {
	b.Lock()
	defer b.Unlock()
	for containerId, deadContainer := range b.deadContainers {
		deadContainer.TTL -= b.config.RefreshInterval
		if deadContainer.TTL <= 0 {
			delete(b.deadContainers, containerId)
		}
	}
}

// Get a deep copy of the current services in a thread-safe way
func (b *Bridge) getServicesCopy() map[string][]*Service {
	b.Lock()
	defer b.Unlock()
	svcsCopy := make(map[string][]*Service)

	for id, svc := range b.services {
		var svcPointers []*Service
		for _, s := range svc {
			t := *s
			z := &t
			svcPointers = append(svcPointers, z)
		}
		svcsCopy[id] = svcPointers
	}
	return svcsCopy
}

func (b *Bridge) Sync(quiet bool) {

	// Take this to avoid having to use a mutex
	servicesSnapshot := b.getServicesCopy()

	containers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{})
	if err != nil && quiet {
		log.Println("error listing containers, skipping sync")
		return
	} else if err != nil && !quiet {
		log.Fatal(err)
	}

	log.Printf("Syncing services on %d containers", len(containers))

	// NOTE: This assumes reregistering will do the right thing, i.e. nothing..
	for _, listing := range containers {
		services := servicesSnapshot[listing.ID]
		if services == nil {
			go b.add(listing.ID, quiet)
		} else {
			for _, service := range services {
				err := b.registry.Register(service)
				if err != nil {
					log.Println("sync register failed:", service, err)
				}
			}
		}
	}

	// Clean up services that were registered previously, but aren't
	// acknowledged within registrator
	if b.config.Cleanup {
		// Remove services if its corresponding container is not running
		log.Println("Listing non-exited containers")
		filters := map[string][]string{"status": {"created", "restarting", "running", "paused"}}
		nonExitedContainers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{Filters: filters})
		if err != nil {
			log.Println("error listing nonExitedContainers, skipping sync", err)
			return
		}
		for listingId, _ := range servicesSnapshot {
			found := false
			for _, container := range nonExitedContainers {
				if listingId == container.ID {
					found = true
					break
				}
			}
			// This is a container that does not exist
			if !found {
				log.Printf("stale: Removing service %s because it does not exist", listingId)
				go b.RemoveOnExit(listingId)
			}
		}

		log.Println("Cleaning up dangling services")
		extServices, err := b.registry.Services()
		if err != nil {
			log.Println("cleanup failed:", err)
			return
		}

	Outer:
		for _, extService := range extServices {
			matches := serviceIDPattern.FindStringSubmatch(extService.ID)
			if len(matches) != 3 {
				// There's no way this was registered by us, so leave it
				continue
			}
			serviceHostname := matches[1]
			if serviceHostname != Hostname {
				// ignore because registered on a different host
				continue
			}
			serviceContainerName := matches[2]
			for _, listing := range servicesSnapshot {
				for _, service := range listing {
					if service.Name == extService.Name && serviceContainerName == service.Origin.container.Name[1:] {
						continue Outer
					}
				}
			}
			log.Println("dangling:", extService.ID)
			err := b.registry.Deregister(extService)
			if err != nil {
				log.Println("deregister failed:", extService.ID, err)
				continue
			}
			log.Println(extService.ID, "removed")
		}
	}
}

func (b *Bridge) deleteDeadContainer(containerId string) {
	b.Lock()
	defer b.Unlock()

	if d := b.deadContainers[containerId]; d != nil {
		b.services[containerId] = d.Services
		delete(b.deadContainers, containerId)
	}
}

func (b *Bridge) appendService(containerId string, service *Service) {
	b.Lock()
	defer b.Unlock()
	if b.services[containerId] != nil {
		log.Println("container, ", containerId[:12], ", already exists, will not append.")
		return
	}
	b.services[containerId] = append(b.services[containerId], service)
	log.Println("added:", containerId[:12], service.ID)
}

func (b *Bridge) add(containerId string, quiet bool) {
	b.deleteDeadContainer(containerId)

	b.Lock()
	defer b.Unlock()

	if b.services[containerId] != nil {
		log.Println("container, ", containerId[:12], ", already exists, ignoring")
		// Alternatively, remove and readd or resubmit.
		return
	}
	b.Unlock()

	container, err := b.docker.InspectContainer(containerId)
	if err != nil {
		log.Println("unable to inspect container:", containerId[:12], err)
		return
	}

	ports := make(map[string]ServicePort)

	// Extract configured host port mappings, relevant when using --net=host
	for port, _ := range container.Config.ExposedPorts {
		published := []dockerapi.PortBinding{{"0.0.0.0", port.Port()}}
		ports[string(port)] = servicePort(container, port, published)
	}

	// Extract runtime port mappings, relevant when using --net=bridge
	for port, published := range container.NetworkSettings.Ports {
		ports[string(port)] = servicePort(container, port, published)
	}

	if len(ports) == 0 && !quiet {
		log.Println("ignored:", container.ID[:12], "no published ports")
		return
	}

	servicePorts := make(map[string]ServicePort)
	for key, port := range ports {
		if b.config.Internal != true && port.HostPort == "" {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "port", port.ExposedPort, "not published on host")
			}
			continue
		}
		servicePorts[key] = port
	}

	isGroup := len(servicePorts) > 1
	for _, port := range servicePorts {
		service := b.newService(port, isGroup)
		if service == nil {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "service on port", port.ExposedPort)
			}
			continue
		}
		err := b.registry.Register(service)
		if err != nil {
			log.Println("register failed:", service, err)
			continue
		}
		b.appendService(container.ID, service)
	}
}

func (b *Bridge) newService(port ServicePort, isgroup bool) *Service {
	container := port.container
	defaultName := strings.Split(path.Base(container.Config.Image), ":")[0]

	// not sure about this logic. kind of want to remove it.
	hostname := Hostname
	if hostname == "" {
		hostname = port.HostIP
	}
	if port.HostIP == "0.0.0.0" {
		ip, err := net.ResolveIPAddr("ip", hostname)
		if err == nil {
			port.HostIP = ip.String()
		}
	}

	if b.config.HostIp != "" {
		port.HostIP = b.config.HostIp
	}

	metadata, metadataFromPort := serviceMetaData(container.Config, port.ExposedPort)

	ignore := mapDefault(metadata, "ignore", "")
	if ignore != "" {
		return nil
	}

	if b.config.RequireLabel {
		if strings.ToLower(mapDefault(metadata, "register", "false")) == "false" {
			log.Printf("Did not find label SERVICE_REGISTER on %s - ignoring.", container.Name)
			return nil
		}
	}

	service := new(Service)
	service.Origin = port
	service.ID = hostname + ":" + container.Name[1:] + ":" + port.ExposedPort
	service.Name = mapDefault(metadata, "name", defaultName)
	if isgroup && !metadataFromPort["name"] {
		service.Name += "-" + port.ExposedPort
	}
	var p int

	if b.config.Internal == true {
		service.IP = port.ExposedIP
		p, _ = strconv.Atoi(port.ExposedPort)
	} else {
		service.IP = port.HostIP
		p, _ = strconv.Atoi(port.HostPort)
	}
	service.Port = p

	if b.config.UseIpFromLabel != "" {
		containerIp := container.Config.Labels[b.config.UseIpFromLabel]
		if containerIp != "" {
			slashIndex := strings.LastIndex(containerIp, "/")
			if slashIndex > -1 {
				service.IP = containerIp[:slashIndex]
			} else {
				service.IP = containerIp
			}
			log.Println("using container IP " + service.IP + " from label '" +
				b.config.UseIpFromLabel + "'")
		} else {
			log.Println("Label '" + b.config.UseIpFromLabel +
				"' not found in container configuration")
		}
	}

	// NetworkMode can point to another container (kuberenetes pods)
	networkMode := container.HostConfig.NetworkMode
	if networkMode != "" {
		if strings.HasPrefix(networkMode, "container:") {
			networkContainerId := strings.Split(networkMode, ":")[1]
			log.Println(service.Name + ": detected container NetworkMode, linked to: " + networkContainerId[:12])
			networkContainer, err := b.docker.InspectContainer(networkContainerId)
			if err != nil {
				log.Println("unable to inspect network container:", networkContainerId[:12], err)
			} else {
				service.IP = networkContainer.NetworkSettings.IPAddress
				log.Println(service.Name + ": using network container IP " + service.IP)
			}
		}
	}

	if port.PortType == "udp" {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags, "udp")
		service.ID = service.ID + ":udp"
	} else {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags)
	}

	// Look for ECS labels and add them to metadata if present
	for k, v := range container.Config.Labels {
		if strings.Contains(k, "com.amazonaws.ecs") {
			metadata[k] = v
		}
	}

	id := mapDefault(metadata, "id", "")
	if id != "" {
		service.ID = id
	}

	delete(metadata, "id")
	delete(metadata, "tags")
	delete(metadata, "name")
	service.Attrs = metadata
	service.TTL = b.config.RefreshTtl

	return service
}

func (b *Bridge) remove(containerId string, deregister bool) {
	log.Printf("container stop detected for: %v", containerId)
	b.Lock()
	defer b.Unlock()

	if deregister {
		deregisterAll := func(services []*Service) {
			for _, service := range services {
				err := b.registry.Deregister(service)
				if err != nil {
					log.Println("deregister failed:", service.ID, err)
					continue
				}
				log.Println("removed:", containerId[:12], service.ID)
			}
		}
		deregisterAll(b.services[containerId])
		if d := b.deadContainers[containerId]; d != nil {
			deregisterAll(d.Services)
			delete(b.deadContainers, containerId)
		}
	} else if b.config.RefreshTtl != 0 && b.services[containerId] != nil {
		// need to stop the refreshing, but can't delete it yet
		b.deadContainers[containerId] = &DeadContainer{b.config.RefreshTtl, b.services[containerId]}
	}
	delete(b.services, containerId)
}

// bit set on ExitCode if it represents an exit via a signal
var dockerSignaledBit = 128

func (b *Bridge) shouldRemove(containerId string) bool {
	if b.config.DeregisterCheck == "always" {
		return true
	}
	container, err := b.docker.InspectContainer(containerId)
	if _, ok := err.(*dockerapi.NoSuchContainer); ok {
		// the container has already been removed from Docker
		// e.g. probabably run with "--rm" to remove immediately
		// so its exit code is not accessible
		log.Printf("registrator: container %v was removed, could not fetch exit code", containerId[:12])
		return true
	}

	switch {
	case err != nil:
		log.Printf("registrator: error fetching status for container %v on \"die\" event: %v\n", containerId[:12], err)
		return false
	case container.State.Running:
		log.Printf("registrator: not removing container %v, still running", containerId[:12])
		return false
	case container.State.ExitCode == 0:
		return true
	case container.State.ExitCode&dockerSignaledBit == dockerSignaledBit:
		return true
	}
	return false
}

var Hostname string

func init() {
	// It's ok for Hostname to ultimately be an empty string
	// An empty string will fall back to trying to make a best guess
	Hostname, _ = os.Hostname()
}
<commit_msg>Fix unlock<commit_after>package bridge

import (
	"errors"
	"log"
	"net"
	"net/url"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"sync"

	dockerapi "github.com/fsouza/go-dockerclient"
)

var serviceIDPattern = regexp.MustCompile(`^(.+?):([a-zA-Z0-9][a-zA-Z0-9_.-]+):[0-9]+(?::udp)?$`)

type Bridge struct {
	sync.Mutex
	registry       RegistryAdapter
	docker         *dockerapi.Client
	services       map[string][]*Service
	deadContainers map[string]*DeadContainer
	config         Config
}

func New(docker *dockerapi.Client, adapterUri string, config Config) (*Bridge, error) {
	uri, err := url.Parse(adapterUri)
	if err != nil {
		return nil, errors.New("bad adapter uri: " + adapterUri)
	}
	factory, found := AdapterFactories.Lookup(uri.Scheme)
	if !found {
		return nil, errors.New("unrecognized adapter: " + adapterUri)
	}

	log.Println("Using", uri.Scheme, "adapter:", uri)
	return &Bridge{
		docker:         docker,
		config:         config,
		registry:       factory.New(uri),
		services:       make(map[string][]*Service),
		deadContainers: make(map[string]*DeadContainer),
	}, nil
}

func (b *Bridge) Ping() error {
	return b.registry.Ping()
}

func (b *Bridge) Add(containerId string) {
	b.add(containerId, false)
}

func (b *Bridge) Remove(containerId string) {
	b.remove(containerId, true)
}

func (b *Bridge) RemoveOnExit(containerId string) {
	b.remove(containerId, b.shouldRemove(containerId))
}

func (b *Bridge) Refresh() {
	for containerId, services := range b.getServicesCopy() {
		for _, service := range services {
			err := b.registry.Refresh(service)
			if err != nil {
				log.Println("refresh failed:", service.ID, err)
				continue
			}
			log.Println("refreshed:", containerId[:12], service.ID)
		}
	}
}

func (b *Bridge) PruneDeadContainers() {
	b.Lock()
	defer b.Unlock()
	for containerId, deadContainer := range b.deadContainers {
		deadContainer.TTL -= b.config.RefreshInterval
		if deadContainer.TTL <= 0 {
			delete(b.deadContainers, containerId)
		}
	}
}

// Get a deep copy of the current services in a thread-safe way
func (b *Bridge) getServicesCopy() map[string][]*Service {
	b.Lock()
	defer b.Unlock()
	svcsCopy := make(map[string][]*Service)

	for id, svc := range b.services {
		var svcPointers []*Service
		for _, s := range svc {
			t := *s
			z := &t
			svcPointers = append(svcPointers, z)
		}
		svcsCopy[id] = svcPointers
	}
	return svcsCopy
}

func (b *Bridge) Sync(quiet bool) {

	// Take this to avoid having to use a mutex
	servicesSnapshot := b.getServicesCopy()

	containers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{})
	if err != nil && quiet {
		log.Println("error listing containers, skipping sync")
		return
	} else if err != nil && !quiet {
		log.Fatal(err)
	}

	log.Printf("Syncing services on %d containers", len(containers))

	// NOTE: This assumes reregistering will do the right thing, i.e. nothing..
	for _, listing := range containers {
		services := servicesSnapshot[listing.ID]
		if services == nil {
			go b.add(listing.ID, quiet)
		} else {
			for _, service := range services {
				err := b.registry.Register(service)
				if err != nil {
					log.Println("sync register failed:", service, err)
				}
			}
		}
	}

	// Clean up services that were registered previously, but aren't
	// acknowledged within registrator
	if b.config.Cleanup {
		// Remove services if its corresponding container is not running
		log.Println("Listing non-exited containers")
		filters := map[string][]string{"status": {"created", "restarting", "running", "paused"}}
		nonExitedContainers, err := b.docker.ListContainers(dockerapi.ListContainersOptions{Filters: filters})
		if err != nil {
			log.Println("error listing nonExitedContainers, skipping sync", err)
			return
		}
		for listingId, _ := range servicesSnapshot {
			found := false
			for _, container := range nonExitedContainers {
				if listingId == container.ID {
					found = true
					break
				}
			}
			// This is a container that does not exist
			if !found {
				log.Printf("stale: Removing service %s because it does not exist", listingId)
				go b.RemoveOnExit(listingId)
			}
		}

		log.Println("Cleaning up dangling services")
		extServices, err := b.registry.Services()
		if err != nil {
			log.Println("cleanup failed:", err)
			return
		}

	Outer:
		for _, extService := range extServices {
			matches := serviceIDPattern.FindStringSubmatch(extService.ID)
			if len(matches) != 3 {
				// There's no way this was registered by us, so leave it
				continue
			}
			serviceHostname := matches[1]
			if serviceHostname != Hostname {
				// ignore because registered on a different host
				continue
			}
			serviceContainerName := matches[2]
			for _, listing := range servicesSnapshot {
				for _, service := range listing {
					if service.Name == extService.Name && serviceContainerName == service.Origin.container.Name[1:] {
						continue Outer
					}
				}
			}
			log.Println("dangling:", extService.ID)
			err := b.registry.Deregister(extService)
			if err != nil {
				log.Println("deregister failed:", extService.ID, err)
				continue
			}
			log.Println(extService.ID, "removed")
		}
	}
}

func (b *Bridge) deleteDeadContainer(containerId string) {
	b.Lock()
	defer b.Unlock()

	if d := b.deadContainers[containerId]; d != nil {
		b.services[containerId] = d.Services
		delete(b.deadContainers, containerId)
	}
}

func (b *Bridge) appendService(containerId string, service *Service) {
	b.Lock()
	defer b.Unlock()
	if b.services[containerId] != nil {
		log.Println("container, ", containerId[:12], ", already exists, will not append.")
		return
	}
	b.services[containerId] = append(b.services[containerId], service)
	log.Println("added:", containerId[:12], service.ID)
}

func (b *Bridge) add(containerId string, quiet bool) {
	b.deleteDeadContainer(containerId)

	b.Lock()
	if b.services[containerId] != nil {
		log.Println("container, ", containerId[:12], ", already exists, ignoring")
		// Alternatively, remove and readd or resubmit.
		return
	}
	b.Unlock()

	container, err := b.docker.InspectContainer(containerId)
	if err != nil {
		log.Println("unable to inspect container:", containerId[:12], err)
		return
	}

	ports := make(map[string]ServicePort)

	// Extract configured host port mappings, relevant when using --net=host
	for port, _ := range container.Config.ExposedPorts {
		published := []dockerapi.PortBinding{{"0.0.0.0", port.Port()}}
		ports[string(port)] = servicePort(container, port, published)
	}

	// Extract runtime port mappings, relevant when using --net=bridge
	for port, published := range container.NetworkSettings.Ports {
		ports[string(port)] = servicePort(container, port, published)
	}

	if len(ports) == 0 && !quiet {
		log.Println("ignored:", container.ID[:12], "no published ports")
		return
	}

	servicePorts := make(map[string]ServicePort)
	for key, port := range ports {
		if b.config.Internal != true && port.HostPort == "" {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "port", port.ExposedPort, "not published on host")
			}
			continue
		}
		servicePorts[key] = port
	}

	isGroup := len(servicePorts) > 1
	for _, port := range servicePorts {
		service := b.newService(port, isGroup)
		if service == nil {
			if !quiet {
				log.Println("ignored:", container.ID[:12], "service on port", port.ExposedPort)
			}
			continue
		}
		err := b.registry.Register(service)
		if err != nil {
			log.Println("register failed:", service, err)
			continue
		}
		b.appendService(container.ID, service)
	}
}

func (b *Bridge) newService(port ServicePort, isgroup bool) *Service {
	container := port.container
	defaultName := strings.Split(path.Base(container.Config.Image), ":")[0]

	// not sure about this logic. kind of want to remove it.
	hostname := Hostname
	if hostname == "" {
		hostname = port.HostIP
	}
	if port.HostIP == "0.0.0.0" {
		ip, err := net.ResolveIPAddr("ip", hostname)
		if err == nil {
			port.HostIP = ip.String()
		}
	}

	if b.config.HostIp != "" {
		port.HostIP = b.config.HostIp
	}

	metadata, metadataFromPort := serviceMetaData(container.Config, port.ExposedPort)

	ignore := mapDefault(metadata, "ignore", "")
	if ignore != "" {
		return nil
	}

	if b.config.RequireLabel {
		if strings.ToLower(mapDefault(metadata, "register", "false")) == "false" {
			log.Printf("Did not find label SERVICE_REGISTER on %s - ignoring.", container.Name)
			return nil
		}
	}

	service := new(Service)
	service.Origin = port
	service.ID = hostname + ":" + container.Name[1:] + ":" + port.ExposedPort
	service.Name = mapDefault(metadata, "name", defaultName)
	if isgroup && !metadataFromPort["name"] {
		service.Name += "-" + port.ExposedPort
	}
	var p int

	if b.config.Internal == true {
		service.IP = port.ExposedIP
		p, _ = strconv.Atoi(port.ExposedPort)
	} else {
		service.IP = port.HostIP
		p, _ = strconv.Atoi(port.HostPort)
	}
	service.Port = p

	if b.config.UseIpFromLabel != "" {
		containerIp := container.Config.Labels[b.config.UseIpFromLabel]
		if containerIp != "" {
			slashIndex := strings.LastIndex(containerIp, "/")
			if slashIndex > -1 {
				service.IP = containerIp[:slashIndex]
			} else {
				service.IP = containerIp
			}
			log.Println("using container IP " + service.IP + " from label '" +
				b.config.UseIpFromLabel + "'")
		} else {
			log.Println("Label '" + b.config.UseIpFromLabel +
				"' not found in container configuration")
		}
	}

	// NetworkMode can point to another container (kuberenetes pods)
	networkMode := container.HostConfig.NetworkMode
	if networkMode != "" {
		if strings.HasPrefix(networkMode, "container:") {
			networkContainerId := strings.Split(networkMode, ":")[1]
			log.Println(service.Name + ": detected container NetworkMode, linked to: " + networkContainerId[:12])
			networkContainer, err := b.docker.InspectContainer(networkContainerId)
			if err != nil {
				log.Println("unable to inspect network container:", networkContainerId[:12], err)
			} else {
				service.IP = networkContainer.NetworkSettings.IPAddress
				log.Println(service.Name + ": using network container IP " + service.IP)
			}
		}
	}

	if port.PortType == "udp" {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags, "udp")
		service.ID = service.ID + ":udp"
	} else {
		service.Tags = combineTags(
			mapDefault(metadata, "tags", ""), b.config.ForceTags)
	}

	// Look for ECS labels and add them to metadata if present
	for k, v := range container.Config.Labels {
		if strings.Contains(k, "com.amazonaws.ecs") {
			metadata[k] = v
		}
	}

	id := mapDefault(metadata, "id", "")
	if id != "" {
		service.ID = id
	}

	delete(metadata, "id")
	delete(metadata, "tags")
	delete(metadata, "name")
	service.Attrs = metadata
	service.TTL = b.config.RefreshTtl

	return service
}

func (b *Bridge) remove(containerId string, deregister bool) {
	log.Printf("container stop detected for: %v", containerId)
	b.Lock()
	defer b.Unlock()

	if deregister {
		deregisterAll := func(services []*Service) {
			for _, service := range services {
				err := b.registry.Deregister(service)
				if err != nil {
					log.Println("deregister failed:", service.ID, err)
					continue
				}
				log.Println("removed:", containerId[:12], service.ID)
			}
		}
		deregisterAll(b.services[containerId])
		if d := b.deadContainers[containerId]; d != nil {
			deregisterAll(d.Services)
			delete(b.deadContainers, containerId)
		}
	} else if b.config.RefreshTtl != 0 && b.services[containerId] != nil {
		// need to stop the refreshing, but can't delete it yet
		b.deadContainers[containerId] = &DeadContainer{b.config.RefreshTtl, b.services[containerId]}
	}
	delete(b.services, containerId)
}

// bit set on ExitCode if it represents an exit via a signal
var dockerSignaledBit = 128

func (b *Bridge) shouldRemove(containerId string) bool {
	if b.config.DeregisterCheck == "always" {
		return true
	}
	container, err := b.docker.InspectContainer(containerId)
	if _, ok := err.(*dockerapi.NoSuchContainer); ok {
		// the container has already been removed from Docker
		// e.g. probabably run with "--rm" to remove immediately
		// so its exit code is not accessible
		log.Printf("registrator: container %v was removed, could not fetch exit code", containerId[:12])
		return true
	}

	switch {
	case err != nil:
		log.Printf("registrator: error fetching status for container %v on \"die\" event: %v\n", containerId[:12], err)
		return false
	case container.State.Running:
		log.Printf("registrator: not removing container %v, still running", containerId[:12])
		return false
	case container.State.ExitCode == 0:
		return true
	case container.State.ExitCode&dockerSignaledBit == dockerSignaledBit:
		return true
	}
	return false
}

var Hostname string

func init() {
	// It's ok for Hostname to ultimately be an empty string
	// An empty string will fall back to trying to make a best guess
	Hostname, _ = os.Hostname()
}
<|endoftext|>


<commit_before>package bridge

import (
	//"fmt"
	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/bridge/irc"
	"github.com/42wim/matterbridge/bridge/mattermost"
	"github.com/42wim/matterbridge/bridge/xmpp"
	log "github.com/Sirupsen/logrus"
	"strings"
)

type Bridge struct {
	*config.Config
	Source      string
	Bridges     []Bridger
	Channels    []map[string]string
	ignoreNicks map[string][]string
}

type Bridger interface {
	Send(msg config.Message) error
	Name() string
	Connect() error
	//Command(cmd string) string
}

func NewBridge(cfg *config.Config) error {
	c := make(chan config.Message)
	b := &Bridge{}
	b.Config = cfg
	if cfg.IRC.Enable {
		b.Bridges = append(b.Bridges, birc.New(cfg, c))
	}
	if cfg.Mattermost.Enable {
		b.Bridges = append(b.Bridges, bmattermost.New(cfg, c))
	}
	if cfg.Xmpp.Enable {
		b.Bridges = append(b.Bridges, bxmpp.New(cfg, c))
	}
	if len(b.Bridges) < 2 {
		log.Fatalf("only %d sections enabled. Need at least 2 sections enabled (eg [IRC] and [mattermost]", len(b.Bridges))
	}
	for _, br := range b.Bridges {
		br.Connect()
	}
	b.mapChannels()
	b.mapIgnores()
	b.handleReceive(c)
	return nil
}

func (b *Bridge) handleReceive(c chan config.Message) {
	for {
		select {
		case msg := <-c:
			m := b.getChannel(msg.Origin, msg.Channel)
			if m == nil {
				continue
			}
			for _, br := range b.Bridges {
				if b.ignoreMessage(msg.Username, msg.Text, msg.Origin) {
					continue
				}
				// do not send to originated bridge
				if br.Name() != msg.Origin {
					msg.Channel = m[br.Name()]
					msgmod := b.modifyMessage(msg, br.Name())
					br.Send(msgmod)
				}
			}
		}
	}
}

func (b *Bridge) mapChannels() error {
	for _, val := range b.Config.Channel {
		m := make(map[string]string)
		m["irc"] = val.IRC
		m["mattermost"] = val.Mattermost
		m["xmpp"] = val.Xmpp
		b.Channels = append(b.Channels, m)
	}
	return nil
}

func (b *Bridge) mapIgnores() {
	m := make(map[string][]string)
	m["irc"] = strings.Fields(b.Config.IRC.IgnoreNicks)
	m["mattermost"] = strings.Fields(b.Config.Mattermost.IgnoreNicks)
	m["xmpp"] = strings.Fields(b.Config.Mattermost.IgnoreNicks)
	b.ignoreNicks = m
}

func (b *Bridge) getChannel(src, name string) map[string]string {
	for _, v := range b.Channels {
		if v[src] == name {
			return v
		}
	}
	return nil
}

func (b *Bridge) ignoreMessage(nick string, message string, protocol string) bool {
	// should we discard messages ?
	for _, entry := range b.ignoreNicks[protocol] {
		if nick == entry {
			return true
		}
	}
	return false
}

func setNickFormat(msg *config.Message, format string) {
	if format == "" {
		msg.Username = msg.Origin + "-" + msg.Username + ": "
		return
	}
	msg.Username = strings.Replace(format, "{NICK}", msg.Username, -1)
	msg.Username = strings.Replace(msg.Username, "{BRIDGE}", msg.Origin, -1)
}

func (b *Bridge) modifyMessage(msg config.Message, dest string) config.Message {
	switch dest {
	case "irc":
		setNickFormat(&msg, b.Config.IRC.RemoteNickFormat)
	case "xmpp":
		setNickFormat(&msg, b.Config.Xmpp.RemoteNickFormat)
	case "mattermost":
		setNickFormat(&msg, b.Config.Mattermost.RemoteNickFormat)
	}
	return msg
}
<commit_msg>Refactor handleReceive<commit_after>package bridge

import (
	//"fmt"
	"github.com/42wim/matterbridge/bridge/config"
	"github.com/42wim/matterbridge/bridge/irc"
	"github.com/42wim/matterbridge/bridge/mattermost"
	"github.com/42wim/matterbridge/bridge/xmpp"
	log "github.com/Sirupsen/logrus"
	"strings"
)

type Bridge struct {
	*config.Config
	Source      string
	Bridges     []Bridger
	Channels    []map[string]string
	ignoreNicks map[string][]string
}

type Bridger interface {
	Send(msg config.Message) error
	Name() string
	Connect() error
	//Command(cmd string) string
}

func NewBridge(cfg *config.Config) error {
	c := make(chan config.Message)
	b := &Bridge{}
	b.Config = cfg
	if cfg.IRC.Enable {
		b.Bridges = append(b.Bridges, birc.New(cfg, c))
	}
	if cfg.Mattermost.Enable {
		b.Bridges = append(b.Bridges, bmattermost.New(cfg, c))
	}
	if cfg.Xmpp.Enable {
		b.Bridges = append(b.Bridges, bxmpp.New(cfg, c))
	}
	if len(b.Bridges) < 2 {
		log.Fatalf("only %d sections enabled. Need at least 2 sections enabled (eg [IRC] and [mattermost]", len(b.Bridges))
	}
	for _, br := range b.Bridges {
		br.Connect()
	}
	b.mapChannels()
	b.mapIgnores()
	b.handleReceive(c)
	return nil
}

func (b *Bridge) handleReceive(c chan config.Message) {
	for {
		select {
		case msg := <-c:
			for _, br := range b.Bridges {
				b.handleMessage(msg, br)
			}
		}
	}
}

func (b *Bridge) mapChannels() error {
	for _, val := range b.Config.Channel {
		m := make(map[string]string)
		m["irc"] = val.IRC
		m["mattermost"] = val.Mattermost
		m["xmpp"] = val.Xmpp
		b.Channels = append(b.Channels, m)
	}
	return nil
}

func (b *Bridge) mapIgnores() {
	m := make(map[string][]string)
	m["irc"] = strings.Fields(b.Config.IRC.IgnoreNicks)
	m["mattermost"] = strings.Fields(b.Config.Mattermost.IgnoreNicks)
	m["xmpp"] = strings.Fields(b.Config.Mattermost.IgnoreNicks)
	b.ignoreNicks = m
}

func (b *Bridge) getDestChannel(msg *config.Message, dest string) string {
	for _, v := range b.Channels {
		if v[msg.Origin] == msg.Channel {
			return v[dest]
		}
	}
	return ""
}

func (b *Bridge) handleMessage(msg config.Message, dest Bridger) {
	if b.ignoreMessage(&msg) {
		return
	}
	if dest.Name() != msg.Origin {
		msg.Channel = b.getDestChannel(&msg, dest.Name())
		if msg.Channel == "" {
			return
		}
		b.modifyMessage(&msg, dest.Name())
		dest.Send(msg)
	}
}

func (b *Bridge) ignoreMessage(msg *config.Message) bool {
	// should we discard messages ?
	for _, entry := range b.ignoreNicks[msg.Origin] {
		if msg.Username == entry {
			return true
		}
	}
	return false
}

func setNickFormat(msg *config.Message, format string) {
	if format == "" {
		msg.Username = msg.Origin + "-" + msg.Username + ": "
		return
	}
	msg.Username = strings.Replace(format, "{NICK}", msg.Username, -1)
	msg.Username = strings.Replace(msg.Username, "{BRIDGE}", msg.Origin, -1)
}

func (b *Bridge) modifyMessage(msg *config.Message, dest string) {
	switch dest {
	case "irc":
		setNickFormat(msg, b.Config.IRC.RemoteNickFormat)
	case "xmpp":
		setNickFormat(msg, b.Config.Xmpp.RemoteNickFormat)
	case "mattermost":
		setNickFormat(msg, b.Config.Mattermost.RemoteNickFormat)
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The Go Cloud Development Kit 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
//
//     https://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 (
	"strings"
	"testing"
)

func Test(t *testing.T) {
	got, fails, err := run(strings.NewReader(testOutput))
	if err != nil {
		t.Fatal(err)
	}
	want := `Failures (reporting up to 10):
  gocloud.dev/internal/docstore/internal/fields/TestUnexportedAnonymousNonStruct
ran 6; passed 3; failed 1; skipped 2`
	if got != want {
		t.Errorf("\ngot  %s\nwant %s", got, want)
	}
	if !fails {
		t.Error("wanted fails true, got false")
	}
}

const testOutput = `{"Time":"2019-05-09T16:39:56.83133991-04:00","Action":"run","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags"}
{"Time":"2019-05-09T16:39:56.831489481-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags","Output":"=== RUN   TestFieldsNoTags\n"}
{"Time":"2019-05-09T16:39:56.831517464-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags","Output":"--- PASS: TestFieldsNoTags (0.00s)\n"}
{"Time":"2019-05-09T16:39:56.831535431-04:00","Action":"pass","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags","Elapsed":0}
{"Time":"2019-05-09T16:39:56.831551807-04:00","Action":"run","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags"}
{"Time":"2019-05-09T16:39:56.831561396-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags","Output":"=== RUN   TestAgainstJSONEncodingNoTags\n"}
{"Time":"2019-05-09T16:39:56.831573783-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags","Output":"--- PASS: TestAgainstJSONEncodingNoTags (0.00s)\n"}
{"Time":"2019-05-09T16:39:56.831584528-04:00","Action":"pass","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags","Elapsed":0}
{"Time":"2019-05-09T16:39:56.844376487-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/drivertest","Output":"?   \tgocloud.dev/internal/docstore/drivertest\t[no test files]\n"}
{"Time":"2019-05-09T16:39:56.844397339-04:00","Action":"skip","Package":"gocloud.dev/internal/docstore/drivertest","Elapsed":0}
{"Time":"2019-05-09T16:39:56.831666898-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsWithTags","Output":"--- PASS: TestFieldsWithTags (0.00s)\n"}
{"Time":"2019-05-09T16:39:56.831677054-04:00","Action":"pass","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsWithTags","Elapsed":0}
{"Time":"2019-05-09T16:39:56.831729957-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestUnexportedAnonymousNonStruct","Output":"=== RUN   TestUnexportedAnonymousNonStruct\n"}
{"Time":"2019-05-09T16:39:56.831759258-04:00","Action":"fail","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestUnexportedAnonymousNonStruct","Elapsed":0}
{"Time":"2019-05-09T16:39:56.873905964-04:00","Action":"skip","Package":"gocloud.dev/internal/docstore/memdocstore","Test":"TestConformance/TypeDrivenCodec","Elapsed":0}
`
<commit_msg>testing: generic path expectations in test-summary_test (#2177)<commit_after>// Copyright 2019 The Go Cloud Development Kit 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
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"path/filepath"
	"strings"
	"testing"
)

func Test(t *testing.T) {
	got, fails, err := run(strings.NewReader(testOutput))
	if err != nil {
		t.Fatal(err)
	}
	path := filepath.Join("gocloud.dev", "internal", "docstore", "internal", "fields", "TestUnexportedAnonymousNonStruct")
	want := fmt.Sprintf(`Failures (reporting up to 10):
  %s
ran 6; passed 3; failed 1; skipped 2`, path)
	if got != want {
		t.Errorf("\ngot  %s\nwant %s", got, want)
	}
	if !fails {
		t.Error("wanted fails true, got false")
	}
}

const testOutput = `{"Time":"2019-05-09T16:39:56.83133991-04:00","Action":"run","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags"}
{"Time":"2019-05-09T16:39:56.831489481-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags","Output":"=== RUN   TestFieldsNoTags\n"}
{"Time":"2019-05-09T16:39:56.831517464-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags","Output":"--- PASS: TestFieldsNoTags (0.00s)\n"}
{"Time":"2019-05-09T16:39:56.831535431-04:00","Action":"pass","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsNoTags","Elapsed":0}
{"Time":"2019-05-09T16:39:56.831551807-04:00","Action":"run","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags"}
{"Time":"2019-05-09T16:39:56.831561396-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags","Output":"=== RUN   TestAgainstJSONEncodingNoTags\n"}
{"Time":"2019-05-09T16:39:56.831573783-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags","Output":"--- PASS: TestAgainstJSONEncodingNoTags (0.00s)\n"}
{"Time":"2019-05-09T16:39:56.831584528-04:00","Action":"pass","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestAgainstJSONEncodingNoTags","Elapsed":0}
{"Time":"2019-05-09T16:39:56.844376487-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/drivertest","Output":"?   \tgocloud.dev/internal/docstore/drivertest\t[no test files]\n"}
{"Time":"2019-05-09T16:39:56.844397339-04:00","Action":"skip","Package":"gocloud.dev/internal/docstore/drivertest","Elapsed":0}
{"Time":"2019-05-09T16:39:56.831666898-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsWithTags","Output":"--- PASS: TestFieldsWithTags (0.00s)\n"}
{"Time":"2019-05-09T16:39:56.831677054-04:00","Action":"pass","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestFieldsWithTags","Elapsed":0}
{"Time":"2019-05-09T16:39:56.831729957-04:00","Action":"output","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestUnexportedAnonymousNonStruct","Output":"=== RUN   TestUnexportedAnonymousNonStruct\n"}
{"Time":"2019-05-09T16:39:56.831759258-04:00","Action":"fail","Package":"gocloud.dev/internal/docstore/internal/fields","Test":"TestUnexportedAnonymousNonStruct","Elapsed":0}
{"Time":"2019-05-09T16:39:56.873905964-04:00","Action":"skip","Package":"gocloud.dev/internal/docstore/memdocstore","Test":"TestConformance/TypeDrivenCodec","Elapsed":0}
`
<|endoftext|>


<commit_before>package expts

import (
	"encoding/json"
	"net/url"
	"path"
	"sync"

	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/cmd/shared"
)

////Cmd to export target servers
var Cmd = &cobra.Command{
	Use:   "export",
	Short: "Export target servers to a file",
	Long:  "Export target servers to a file",
	RunE: func(cmd *cobra.Command, args []string) (err error) {

		const exportFileName = "targetservers.json"
		err = exportTargetServers()
		if err != nil {
			return
		}
		return shared.WriteByteArrayToFile(exportFileName, false, nil)
	},
}

var conn int

func init() {

	Cmd.Flags().IntVarP(&conn, "conn", "c",
		4, "Number of connections")

}

//batch created a batch of targetservers to query
func batch(entities []string, entityType string, pwg *sync.WaitGroup, mu *sync.Mutex) {

	defer pwg.Done()
	//batch workgroup
	var bwg sync.WaitGroup

	bwg.Add(len(entities))

	for _, entity := range entities {
		u, _ := url.Parse(shared.BaseURL)
		u.Path = path.Join(u.Path, shared.RootArgs.Org, "environments", shared.RootArgs.Env, entityType, entity)
		go shared.GetAsyncEntity(u.String(), &bwg, mu)
	}
	bwg.Wait()
}

func exportTargetServers() error {

	//parent workgroup
	var pwg sync.WaitGroup
	var mu sync.Mutex
	const entityType = "targetservers"

	u, _ := url.Parse(shared.BaseURL)
	u.Path = path.Join(u.Path, shared.RootArgs.Org, "environments", shared.RootArgs.Env, entityType)
	//don't print to sysout
	respBody, err := shared.HttpClient(false, u.String())
	if err != nil {
		return err
	}

	var targetservers []string
	err = json.Unmarshal(respBody, &targetservers)
	if err != nil {
		return err
	}

	numEntities := len(targetservers)
	shared.Info.Printf("Found %d targetservers in the org\n", numEntities)
	shared.Info.Printf("Exporting targetservers with %d connections\n", conn)

	numOfLoops, remaining := numEntities/conn, numEntities%conn

	//ensure connections aren't greater than targetservers
	if conn > numEntities {
		conn = numEntities
	}

	start := 0

	for i, end := 0, 0; i < numOfLoops; i++ {
		pwg.Add(1)
		end = (i * conn) + conn
		shared.Info.Printf("Exporting batch %d of targetservers\n", (i + 1))
		go batch(targetservers[start:end], entityType, &pwg, &mu)
		start = end
		pwg.Wait()
	}

	if remaining > 0 {
		pwg.Add(1)
		shared.Info.Printf("Exporting remaining %d targetservers\n", remaining)
		go batch(targetservers[start:numEntities], entityType, &pwg, &mu)
		pwg.Wait()
	}

	return nil
}
<commit_msg>fix comment<commit_after>package expts

import (
	"encoding/json"
	"net/url"
	"path"
	"sync"

	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/cmd/shared"
)

//Cmd to export target servers
var Cmd = &cobra.Command{
	Use:   "export",
	Short: "Export target servers to a file",
	Long:  "Export target servers to a file",
	RunE: func(cmd *cobra.Command, args []string) (err error) {

		const exportFileName = "targetservers.json"
		err = exportTargetServers()
		if err != nil {
			return
		}
		return shared.WriteByteArrayToFile(exportFileName, false, nil)
	},
}

var conn int

func init() {

	Cmd.Flags().IntVarP(&conn, "conn", "c",
		4, "Number of connections")

}

//batch created a batch of targetservers to query
func batch(entities []string, entityType string, pwg *sync.WaitGroup, mu *sync.Mutex) {

	defer pwg.Done()
	//batch workgroup
	var bwg sync.WaitGroup

	bwg.Add(len(entities))

	for _, entity := range entities {
		u, _ := url.Parse(shared.BaseURL)
		u.Path = path.Join(u.Path, shared.RootArgs.Org, "environments", shared.RootArgs.Env, entityType, entity)
		go shared.GetAsyncEntity(u.String(), &bwg, mu)
	}
	bwg.Wait()
}

func exportTargetServers() error {

	//parent workgroup
	var pwg sync.WaitGroup
	var mu sync.Mutex
	const entityType = "targetservers"

	u, _ := url.Parse(shared.BaseURL)
	u.Path = path.Join(u.Path, shared.RootArgs.Org, "environments", shared.RootArgs.Env, entityType)
	//don't print to sysout
	respBody, err := shared.HttpClient(false, u.String())
	if err != nil {
		return err
	}

	var targetservers []string
	err = json.Unmarshal(respBody, &targetservers)
	if err != nil {
		return err
	}

	numEntities := len(targetservers)
	shared.Info.Printf("Found %d targetservers in the org\n", numEntities)
	shared.Info.Printf("Exporting targetservers with %d connections\n", conn)

	numOfLoops, remaining := numEntities/conn, numEntities%conn

	//ensure connections aren't greater than targetservers
	if conn > numEntities {
		conn = numEntities
	}

	start := 0

	for i, end := 0, 0; i < numOfLoops; i++ {
		pwg.Add(1)
		end = (i * conn) + conn
		shared.Info.Printf("Exporting batch %d of targetservers\n", (i + 1))
		go batch(targetservers[start:end], entityType, &pwg, &mu)
		start = end
		pwg.Wait()
	}

	if remaining > 0 {
		pwg.Add(1)
		shared.Info.Printf("Exporting remaining %d targetservers\n", remaining)
		go batch(targetservers[start:numEntities], entityType, &pwg, &mu)
		pwg.Wait()
	}

	return nil
}
<|endoftext|>


<commit_before>package servicebuilder

import (
	"log"
	"path/filepath"
	"strings"

	"github.com/essentier/gopencils"
	"github.com/essentier/nomockutil"
	"github.com/essentier/spickspan/config"
	"github.com/go-errors/errors"
)

func createServiceBuilder(serviceConfig config.Service, providerUrl string, token string) *serviceBuilder {
	nomockApi := gopencils.Api(providerUrl)
	return &serviceBuilder{nomockApi: nomockApi, token: token, serviceConfig: serviceConfig}
}

type serviceBuilder struct {
	nomockApi     *gopencils.Resource
	serviceConfig config.Service
	token         string
}

func (p *serviceBuilder) buildService() error {
	if !p.serviceConfig.IsSourceProject() {
		return errors.New("Could not build a service that is not a source project.")
	}

	err := gitPush(p.serviceConfig.ServiceName, p.serviceConfig.ProjectSrcRoot, p.nomockApi.Api.BaseUrl.String()+"/nomockbuilder", p.token)
	if err != nil {
		return err
	}

	log.Printf("going to build code")
	return p.buildServiceOnNomockBuilder(p.serviceConfig.ServiceName)
}

func (p *serviceBuilder) buildServiceOnNomockBuilder(serviceName string) error {
	log.Printf("building service %v on nomock builder", serviceName)
	var result interface{}
	builderResource := p.nomockApi.Res("nomockbuilder/build/"+serviceName, &result)
	builderResource.SetHeader("Authorization", "Bearer "+p.token)
	_, err := builderResource.Get()
	return err
}

func gitPush(serviceName string, projectDir string, builderUrl string, token string) error {
	log.Printf("gitpusher.Push project dir: %v", projectDir)
	gitDir := filepath.Join(projectDir, ".git")
	if !nomockutil.Exists(gitDir) {
		return errors.Errorf("Project %v is not initialized with git. Use 'git init' to initialize the project.", projectDir)
	}

	remoteUrl := getEssentierGitRemote(serviceName, builderUrl, token)
	git := &gitProject{projectDir: projectDir, err: nil}
	originalBranch := git.getCurrentBranch()
	git.stashAll()
	if git.err == nil {
		defer git.deferredPopStashed()
	}

	git.branch("nomock")
	if git.err == nil {
		defer git.deferredDeleteBranch("nomock")
	}

	git.checkout("nomock")
	if git.err == nil {
		defer git.deferredCheckout(originalBranch)
	}

	git.pull(remoteUrl, "nomock")
	git.applyStash()
	git.addAll()
	git.commit("'done by nomock'")
	git.push(remoteUrl, "nomock")
	return git.err
}

func getEssentierGitRemote(serviceName string, builderUrl string, token string) string {
	remoteUrl := ""
	if strings.HasPrefix(builderUrl, "git") {
		remoteUrl = builderUrl + ":" + serviceName
	} else if strings.HasPrefix(builderUrl, "https://") {
		if strings.HasSuffix(builderUrl, "/") {
			remoteUrl = "https://" + token + ":@" + builderUrl[8:] + serviceName
		} else {
			remoteUrl = "https://" + token + ":@" + builderUrl[8:] + "/" + serviceName
		}
	}
	return remoteUrl
}
<commit_msg>use essentier gopencils<commit_after>package servicebuilder

import (
	"log"
	"path/filepath"
	"strings"

	"github.com/essentier/gopencils"
	"github.com/essentier/nomockutil"
	"github.com/essentier/spickspan/config"
	"github.com/go-errors/errors"
)

func createServiceBuilder(serviceConfig config.Service, providerUrl string, token string) *serviceBuilder {
	nomockApi := gopencils.Api(providerUrl)
	return &serviceBuilder{nomockApi: nomockApi, token: token, serviceConfig: serviceConfig}
}

type serviceBuilder struct {
	nomockApi     *gopencils.Resource
	serviceConfig config.Service
	token         string
}

func (p *serviceBuilder) buildService() error {
	if !p.serviceConfig.IsSourceProject() {
		return errors.New("Could not build a service that is not a source project.")
	}

	err := gitPush(p.serviceConfig.ServiceName, p.serviceConfig.ProjectSrcRoot, p.nomockApi.Api.BaseUrl.String()+"/nomockbuilder", p.token)
	if err != nil {
		return err
	}

	log.Printf("going to build code")
	return p.buildServiceOnNomockBuilder(p.serviceConfig.ServiceName)
}

func (p *serviceBuilder) buildServiceOnNomockBuilder(serviceName string) error {
	log.Printf("building service %v on nomock builder", serviceName)
	var result interface{}
	builderResource := p.nomockApi.NewChildResource("nomockbuilder/build/"+serviceName, &result)
	builderResource.SetHeader("Authorization", "Bearer "+p.token)
	_, err := builderResource.Get()
	return err
}

func gitPush(serviceName string, projectDir string, builderUrl string, token string) error {
	log.Printf("gitpusher.Push project dir: %v", projectDir)
	gitDir := filepath.Join(projectDir, ".git")
	if !nomockutil.Exists(gitDir) {
		return errors.Errorf("Project %v is not initialized with git. Use 'git init' to initialize the project.", projectDir)
	}

	remoteUrl := getEssentierGitRemote(serviceName, builderUrl, token)
	git := &gitProject{projectDir: projectDir, err: nil}
	originalBranch := git.getCurrentBranch()
	git.stashAll()
	if git.err == nil {
		defer git.deferredPopStashed()
	}

	git.branch("nomock")
	if git.err == nil {
		defer git.deferredDeleteBranch("nomock")
	}

	git.checkout("nomock")
	if git.err == nil {
		defer git.deferredCheckout(originalBranch)
	}

	git.pull(remoteUrl, "nomock")
	git.applyStash()
	git.addAll()
	git.commit("'done by nomock'")
	git.push(remoteUrl, "nomock")
	return git.err
}

func getEssentierGitRemote(serviceName string, builderUrl string, token string) string {
	remoteUrl := ""
	if strings.HasPrefix(builderUrl, "git") {
		remoteUrl = builderUrl + ":" + serviceName
	} else if strings.HasPrefix(builderUrl, "https://") {
		if strings.HasSuffix(builderUrl, "/") {
			remoteUrl = "https://" + token + ":@" + builderUrl[8:] + serviceName
		} else {
			remoteUrl = "https://" + token + ":@" + builderUrl[8:] + "/" + serviceName
		}
	}
	return remoteUrl
}
<|endoftext|>


<commit_before>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package thumbnail

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/common/util/fsutil"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/services/imageconversion"
	"io"
	"path/filepath"
	"time"
)

var (
	SizeSmall = ThumbDimension{
		MaxWidth:  200,
		MaxHeight: 0,
	}

	SizeMedium = ThumbDimension{
		MaxWidth:  400,
		MaxHeight: 0,
	}

	SizeLarge = ThumbDimension{
		MaxWidth:  800,
		MaxHeight: 0,
	}
)

func NewConversionService(logger logger.Logger, repository dataaccess.Repository, targetFolder string, thumbnailIndex *Index) *ConversionService {

	// create a new conversion service
	conversionService := &ConversionService{
		logger:     logger,
		repository: repository,

		index:           thumbnailIndex,
		thumbnailFolder: targetFolder,
	}

	// start the conversion
	conversionService.startConversion()

	return conversionService
}

type ConversionService struct {
	logger     logger.Logger
	repository dataaccess.Repository

	index           *Index
	thumbnailFolder string
}

func (conversion *ConversionService) startConversion() {

	// distinctive update
	conversion.repository.OnUpdate(func(route route.Route) {
		item := conversion.repository.Item(route)
		if item == nil {
			return
		}

		for _, file := range item.Files() {

			// create the thumbnail
			conversion.createThumbnail(file, SizeSmall)
			conversion.createThumbnail(file, SizeMedium)
			conversion.createThumbnail(file, SizeLarge)
		}
	})

	// full run
	go func() {

		for _, item := range conversion.repository.Items() {

			for _, file := range item.Files() {

				// create the thumbnail
				conversion.createThumbnail(file, SizeSmall)
				conversion.createThumbnail(file, SizeMedium)
				conversion.createThumbnail(file, SizeLarge)

			}

			// wait before processing the next image
			time.Sleep(500 * time.Millisecond)
		}

	}()
}

func (conversion *ConversionService) createThumbnail(file *dataaccess.File, dimensions ThumbDimension) {

	// get the mime type
	mimeType, err := file.MimeType()
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	// check the mime type
	if !imageconversion.MimeTypeIsSupported(mimeType) {
		conversion.logger.Debug("The mime-type %q is currently not supported.", mimeType)
		return
	}

	// determine the file name
	fileExtension := imageconversion.GetFileExtensionFromMimeType(mimeType)
	filename := fmt.Sprintf("%s-%v-%v.%s", file.Id(), dimensions.MaxWidth, dimensions.MaxHeight, fileExtension)

	// assemble the full file route
	fullFileRoute, err := route.Combine(file.Parent(), file.Route())
	if err != nil {
		conversion.logger.Warn("Unable to combine routes %q and %q.", file.Parent(), file.Route())
		return
	}

	thumb := newThumb(fullFileRoute, filename, dimensions)

	// check the index
	if conversion.isInIndex(thumb) {
		conversion.logger.Debug("Thumb %q already available in the index", thumb.String())
		return
	}

	// determine the file path
	filePath := filepath.Join(conversion.thumbnailFolder, filename)

	// open the target file
	target, fileError := fsutil.OpenFile(filePath)
	if fileError != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", fileError.Error())
		return
	}

	defer target.Close()

	// convert the image
	conversionError := file.Data(func(content io.ReadSeeker) error {
		return imageconversion.Resize(content, mimeType, dimensions.MaxWidth, dimensions.MaxHeight, target)
	})

	// handle errors
	if conversionError != nil {
		conversion.logger.Warn("Unable to create thumbnail for file %q. Error: %s", file, conversionError.Error())
		return
	}

	// add to index
	conversion.addToIndex(thumb)
	conversion.logger.Debug("Adding Thumb %q to index", thumb.String())
}

func (conversion *ConversionService) isInIndex(thumb Thumb) bool {

	// check if there are thumb for the route
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		return false
	}

	// check if there is a thumb with that dimensions
	if _, thumbExists := thumbs[thumb.Dimensions.String()]; thumbExists {
		// check if the file exists
		return fsutil.FileExists(filepath.Join(conversion.thumbnailFolder, thumb.Path))

	}

	return false
}

func (conversion *ConversionService) addToIndex(thumb Thumb) {
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		thumbs = make(Thumbs)
	}

	thumbs[thumb.Dimensions.String()] = thumb
	conversion.index.SetThumbs(thumb.Route, thumbs)
}
<commit_msg>Conversion service code cleanup<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package thumbnail

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/common/util/fsutil"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/services/imageconversion"
	"io"
	"path/filepath"
	"time"
)

var (
	SizeSmall = ThumbDimension{
		MaxWidth:  200,
		MaxHeight: 0,
	}

	SizeMedium = ThumbDimension{
		MaxWidth:  400,
		MaxHeight: 0,
	}

	SizeLarge = ThumbDimension{
		MaxWidth:  800,
		MaxHeight: 0,
	}
)

func NewConversionService(logger logger.Logger, repository dataaccess.Repository, targetFolder string, thumbnailIndex *Index) *ConversionService {

	// create a new conversion service
	conversionService := &ConversionService{
		logger:     logger,
		repository: repository,

		index:           thumbnailIndex,
		thumbnailFolder: targetFolder,
	}

	// start the conversion
	conversionService.startConversion()

	return conversionService
}

type ConversionService struct {
	logger     logger.Logger
	repository dataaccess.Repository

	index           *Index
	thumbnailFolder string
}

// Start the conversion process.
func (conversion *ConversionService) startConversion() {

	// distinctive update
	conversion.repository.OnUpdate(func(route route.Route) {
		item := conversion.repository.Item(route)
		conversion.createThumbnailsForItem(item)
	})

	// full run
	go conversion.fullConversion()
}

// Process all items in the repository.
func (conversion *ConversionService) fullConversion() {
	for _, item := range conversion.repository.Items() {

		conversion.createThumbnailsForItem(item)

		// wait before processing the next image
		time.Sleep(500 * time.Millisecond)
	}
}

// Create thumbnail for all image files found in the supplied item.
func (conversion *ConversionService) createThumbnailsForItem(item *dataaccess.Item) {

	if item == nil {
		return
	}

	for _, file := range item.Files() {

		// create the thumbnail
		conversion.createThumbnail(file, SizeSmall)
		conversion.createThumbnail(file, SizeMedium)
		conversion.createThumbnail(file, SizeLarge)

	}

}

// Creates a thumbnail for the supplied file with the specified dimensions.
func (conversion *ConversionService) createThumbnail(file *dataaccess.File, dimensions ThumbDimension) {

	// get the mime type
	mimeType, err := file.MimeType()
	if err != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", err.Error())
		return
	}

	// check the mime type
	if !imageconversion.MimeTypeIsSupported(mimeType) {
		conversion.logger.Debug("The mime-type %q is currently not supported.", mimeType)
		return
	}

	// determine the file name
	fileExtension := imageconversion.GetFileExtensionFromMimeType(mimeType)
	filename := fmt.Sprintf("%s-%v-%v.%s", file.Id(), dimensions.MaxWidth, dimensions.MaxHeight, fileExtension)

	// assemble the full file route
	fullFileRoute, err := route.Combine(file.Parent(), file.Route())
	if err != nil {
		conversion.logger.Warn("Unable to combine routes %q and %q.", file.Parent(), file.Route())
		return
	}

	thumb := newThumb(fullFileRoute, filename, dimensions)

	// check the index
	if conversion.isInIndex(thumb) {
		conversion.logger.Debug("Thumb %q already available in the index", thumb.String())
		return
	}

	// determine the file path
	filePath := filepath.Join(conversion.thumbnailFolder, filename)

	// open the target file
	target, fileError := fsutil.OpenFile(filePath)
	if fileError != nil {
		conversion.logger.Warn("Unable to detect mime type for file. Error: %s", fileError.Error())
		return
	}

	defer target.Close()

	// convert the image
	conversionError := file.Data(func(content io.ReadSeeker) error {
		return imageconversion.Resize(content, mimeType, dimensions.MaxWidth, dimensions.MaxHeight, target)
	})

	// handle errors
	if conversionError != nil {
		conversion.logger.Warn("Unable to create thumbnail for file %q. Error: %s", file, conversionError.Error())
		return
	}

	// add to index
	conversion.addToIndex(thumb)
	conversion.logger.Debug("Adding Thumb %q to index", thumb.String())
}

func (conversion *ConversionService) isInIndex(thumb Thumb) bool {

	// check if there are thumb for the route
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		return false
	}

	// check if there is a thumb with that dimensions
	if _, thumbExists := thumbs[thumb.Dimensions.String()]; thumbExists {
		// check if the file exists
		return fsutil.FileExists(filepath.Join(conversion.thumbnailFolder, thumb.Path))

	}

	return false
}

func (conversion *ConversionService) addToIndex(thumb Thumb) {
	thumbs, entryExists := conversion.index.GetThumbs(thumb.Route)
	if !entryExists {
		thumbs = make(Thumbs)
	}

	thumbs[thumb.Dimensions.String()] = thumb
	conversion.index.SetThumbs(thumb.Route, thumbs)
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "io/ioutil"
import "os"

func main() {
	fmt.Println("Advent of code: Golang\nTask 8")

	PrintCurrentDir()

	file, err := ioutil.ReadFile("../input.txt")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	content := string(file)
	fmt.Println(content)
}

func PrintCurrentDir() {
	pwd, err := os.Getwd()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println("current dir: " + pwd)
}

<commit_msg>Close file at the end<commit_after>package main

import "fmt"
import "io/ioutil"
import "os"

func main() {
	fmt.Println("Advent of code: Golang\nTask 8")

	PrintCurrentDir()

	file, err := ioutil.ReadFile("../input.txt")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
        defer file.Close()

	content := string(file)
	fmt.Println(content)
}

func PrintCurrentDir() {
	pwd, err := os.Getwd()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println("current dir: " + pwd)
}

<|endoftext|>


<commit_before>package colonycore

import (
	"errors"
	"github.com/eaciit/dbox"
	_ "github.com/eaciit/dbox/dbc/jsons"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

var _conn dbox.IConnection
var _ctx *orm.DataContext
var _ctxErr error

func ctx() *orm.DataContext {
	var econn error
	if _ctx == nil {
		if _conn == nil {
			_conn, econn = getConnection()
			if econn != nil {
				_ctxErr = errors.New("Connection error: " + econn.Error())
				return nil
			}
		}
		_ctx = orm.New(_conn)
	}
	return _ctx
}

func Delete(o orm.IModel) error {
	e := ctx().Delete(o)
	if e != nil {
		return errors.New("Core.Delete: " + e.Error())
	}
	return e

}

func Save(o orm.IModel) error {
	e := ctx().Save(o)
	if e != nil {
		return errors.New("Core.Save: " + e.Error())
	}
	return e
}

func Get(o orm.IModel, id interface{}) error {
	e := ctx().GetById(o, id)
	if e != nil {
		return errors.New("Core.Get: " + e.Error())
	}
	return e
}

func Find(o orm.IModel, filter *dbox.Filter) (dbox.ICursor, error) {
	var filters []*dbox.Filter
	if filter != nil {
		filters = append(filters, filter)
	}
	c, e := ctx().Find(o, toolkit.M{}.Set("where", filters))
	if e != nil {
		return nil, errors.New("Core.Find: " + e.Error())
	}
	return c, nil
}

func Finds(o orm.IModel, filter *dbox.Filter, param toolkit.M) (dbox.ICursor, error) {
	var filters []*dbox.Filter
	if filter != nil {
		filters = append(filters, filter)
	}

	params := toolkit.M{}
	params.Set("where", filters)

	if qe := param.Get("order", nil); qe != nil {
		params.Set("order", qe.([]string))
	}
	if qe := param.Get("skip", nil); qe != nil {
		params.Set("skip", qe.(int))
	}
	if qe := param.Get("take", nil); qe != nil {
		params.Set("limit", qe.(int))
	}

	c, e := ctx().Find(o, params)
	if e != nil {
		return nil, errors.New("Core.Find: " + e.Error())
	}
	return c, nil
}
<commit_msg>finds function<commit_after>package colonycore

import (
	"errors"
	"github.com/eaciit/dbox"
	_ "github.com/eaciit/dbox/dbc/jsons"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
)

var _conn dbox.IConnection
var _ctx *orm.DataContext
var _ctxErr error

func ctx() *orm.DataContext {
	var econn error
	if _ctx == nil {
		if _conn == nil {
			_conn, econn = getConnection()
			if econn != nil {
				_ctxErr = errors.New("Connection error: " + econn.Error())
				return nil
			}
		}
		_ctx = orm.New(_conn)
	}
	return _ctx
}

func Delete(o orm.IModel) error {
	e := ctx().Delete(o)
	if e != nil {
		return errors.New("Core.Delete: " + e.Error())
	}
	return e

}

func Save(o orm.IModel) error {
	e := ctx().Save(o)
	if e != nil {
		return errors.New("Core.Save: " + e.Error())
	}
	return e
}

func Get(o orm.IModel, id interface{}) error {
	e := ctx().GetById(o, id)
	if e != nil {
		return errors.New("Core.Get: " + e.Error())
	}
	return e
}

func Find(o orm.IModel, filter *dbox.Filter) (dbox.ICursor, error) {
	var filters []*dbox.Filter
	if filter != nil {
		filters = append(filters, filter)
	}
	c, e := ctx().Find(o, toolkit.M{}.Set("where", filters))
	if e != nil {
		return nil, errors.New("Core.Find: " + e.Error())
	}
	return c, nil
}

func Finds(o orm.IModel, param toolkit.M) (dbox.ICursor, error) {
	var filters []*dbox.Filter

	params := toolkit.M{}
	params.Set("where", filters)

	if qe := param.Get("order", nil); qe != nil {
		params.Set("order", qe.([]string))
	}
	if qe := param.Get("skip", nil); qe != nil {
		params.Set("skip", qe.(int))
	}
	if qe := param.Get("take", nil); qe != nil {
		params.Set("limit", qe.(int))
	}
	if qe := param.Get("where", nil); qe != nil {
		filters = append(filters, qe.(*dbox.Filter))
		params.Set("where", filters)
	}

	c, e := ctx().Find(o, params)
	if e != nil {
		return nil, errors.New("Core.Find: " + e.Error())
	}
	return c, nil
}
<|endoftext|>


<commit_before>// Package valida implements JMBG, MBS, Municipal ID and OIB numbers validations.
package valida

import "strconv"

// digit returns one digit.
func digit(in string) int {
	d, err := strconv.Atoi(in)
	if d < 0 || err != nil {
		return 0
	}
	return d
}

// isValid validate input string.
func isValid(in string) bool {
	i, err := strconv.ParseInt(in, 10, 64)
	if i > 0 && err == nil {
		return true
	}
	return false
}

// JMBG validate JMBG number.
func JMBG(in string) bool {
	if len(in) != 13 || !isValid(in) {
		return false
	}
	// get first 12 chars
	digits := in[:12]
	coef := 7
	zzz := 0
	for _, r := range digits {
		// exit if char not digit
		d := digit(string(r))
		zzz += d * coef
		if coef == 2 {
			coef = 8
		}
		coef--
	}
	// get last digit
	last := digit(in[12:13])

	ost := zzz % 11
	raz := 11 - ost
	ok1 := ost == 0 && last == 0
	ok2 := ost > 1 && ost < 11 && last == raz
	if ok1 || ok2 {
		return true
	}
	return false
}

// MBS validate MBS number.
func MBS(in string) bool {
	if (len(in) != 8 && len(in) != 12) || !isValid(in) {
		return false
	}
	// get first 7 chars
	digits := in[:7]
	zzz := 0
	for i, r := range digits {
		coef := 8 - i
		// exit if char not digit
		d := digit(string(r))
		zzz += d * coef
	}
	// exit if control char not digit
	control := digit(in[7:8])
	ost := zzz % 11
	raz := 11 - ost
	ok1 := ost == 1 && control == 0
	ok2 := ost > 1 && ost < 11 && control == raz
	if ok1 || ok2 {
		return true
	}
	return false
}

// MID validate Municipal ID number.
func MID(in string) bool {
	if len(in) != 4 || !isValid(in) {
		return false
	}
	// get first 3 chars
	digits := in[:3]
	zzz := 0
	for i, r := range digits {
		coef := 4 - i
		d := digit(string(r))
		zzz += d * coef
	}
	last := digit(in[3:4])
	ost := zzz % 11
	raz := 11 - ost
	ok1 := ost == 1 && last == 0
	ok2 := ost > 1 && ost < 11 && last == raz
	if ok1 || ok2 {
		return true
	}
	return false
}

// OIB validate OIB number.
func OIB(in string) bool {
	if len(in) != 11 || !isValid(in) {
		return false
	}

	first10 := in[:len(in)-1]
	o := oibCalc(first10)

	last := digit(in[len(in)-1:])

	// calc control char
	ctrl := 11 - o
	if ctrl == 10 {
		ctrl = 0
	}
	return ctrl == last
}

func oibCalc(digits string) int {
	o := 10
	for _, r := range digits {
		// exit if char not digit
		d := digit(string(r))
		o += d
		o = o % 10
		if o == 0 {
			o = 10
		}
		o *= 2
		o = o % 11
	}
	return o
}
<commit_msg>add midCalc<commit_after>// Package valida implements JMBG, MBS, Municipal ID and OIB numbers validations.
package valida

import "strconv"

// digit returns one digit.
func digit(in string) int {
	d, err := strconv.Atoi(in)
	if d < 0 || err != nil {
		return 0
	}
	return d
}

// isValid validate input string.
func isValid(in string) bool {
	i, err := strconv.ParseInt(in, 10, 64)
	if i > 0 && err == nil {
		return true
	}
	return false
}

// JMBG validate JMBG number.
func JMBG(in string) bool {
	if len(in) != 13 || !isValid(in) {
		return false
	}
	// get first 12 chars
	digits := in[:12]
	coef := 7
	zzz := 0
	for _, r := range digits {
		// exit if char not digit
		d := digit(string(r))
		zzz += d * coef
		if coef == 2 {
			coef = 8
		}
		coef--
	}
	// get last digit
	last := digit(in[12:13])

	ost := zzz % 11
	raz := 11 - ost
	ok1 := ost == 0 && last == 0
	ok2 := ost > 1 && ost < 11 && last == raz
	if ok1 || ok2 {
		return true
	}
	return false
}

// MBS validate MBS number.
func MBS(in string) bool {
	if (len(in) != 8 && len(in) != 12) || !isValid(in) {
		return false
	}
	// get first 7 chars
	digits := in[:7]
	zzz := 0
	for i, r := range digits {
		coef := 8 - i
		// exit if char not digit
		d := digit(string(r))
		zzz += d * coef
	}
	// exit if control char not digit
	control := digit(in[7:8])
	ost := zzz % 11
	raz := 11 - ost
	ok1 := ost == 1 && control == 0
	ok2 := ost > 1 && ost < 11 && control == raz
	if ok1 || ok2 {
		return true
	}
	return false
}

// MID validate Municipal ID number.
func MID(in string) bool {
	if len(in) != 4 || !isValid(in) {
		return false
	}

	first3 := in[:3]
	zzz := midCalc(first3)
	ost := zzz % 11
	raz := 11 - ost

	last := digit(in[3:4])
	ok1 := ost == 1 && last == 0
	ok2 := ost > 1 && ost < 11 && last == raz
	if ok1 || ok2 {
		return true
	}
	return false
}

func midCalc(first3 string) int {
	zzz := 0
	for i, r := range first3 {
		coef := 4 - i
		d := digit(string(r))
		zzz += d * coef
	}
	return zzz
}

// OIB validate OIB number.
func OIB(in string) bool {
	if len(in) != 11 || !isValid(in) {
		return false
	}

	first10 := in[:len(in)-1]
	o := oibCalc(first10)

	last := digit(in[len(in)-1:])

	// calc control char
	ctrl := 11 - o
	if ctrl == 10 {
		ctrl = 0
	}
	return ctrl == last
}

func oibCalc(digits string) int {
	o := 10
	for _, r := range digits {
		// exit if char not digit
		d := digit(string(r))
		o += d
		o = o % 10
		if o == 0 {
			o = 10
		}
		o *= 2
		o = o % 11
	}
	return o
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/lambda"

	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsLambdaEventSourceMapping() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsLambdaEventSourceMappingCreate,
		Read:   resourceAwsLambdaEventSourceMappingRead,
		Update: resourceAwsLambdaEventSourceMappingUpdate,
		Delete: resourceAwsLambdaEventSourceMappingDelete,

		Schema: map[string]*schema.Schema{
			"event_source_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"function_name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"starting_position": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"batch_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  100,
			},
			"enabled": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
			"function_arn": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"last_modified": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"last_processing_result": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"state": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"state_transition_reason": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"uuid": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

// resourceAwsLambdaEventSourceMappingCreate maps to:
// CreateEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	functionName := d.Get("function_name").(string)
	eventSourceArn := d.Get("event_source_arn").(string)

	log.Printf("[DEBUG] Creating Lambda event source mapping: source %s to function %s", eventSourceArn, functionName)

	params := &lambda.CreateEventSourceMappingInput{
		EventSourceArn:   aws.String(eventSourceArn),
		FunctionName:     aws.String(functionName),
		StartingPosition: aws.String(d.Get("starting_position").(string)),
		BatchSize:        aws.Int64(int64(d.Get("batch_size").(int))),
		Enabled:          aws.Bool(d.Get("enabled").(bool)),
	}

	eventSourceMappingConfiguration, err := conn.CreateEventSourceMapping(params)
	if err != nil {
		return fmt.Errorf("Error creating Lambda event source mapping: %s", err)
	}

	d.Set("uuid", eventSourceMappingConfiguration.UUID)
	d.SetId(*eventSourceMappingConfiguration.UUID)

	return resourceAwsLambdaEventSourceMappingRead(d, meta)
}

// resourceAwsLambdaEventSourceMappingRead maps to:
// GetEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	log.Printf("[DEBUG] Fetching Lambda event source mapping: %s", d.Id())

	params := &lambda.GetEventSourceMappingInput{
		UUID: aws.String(d.Id()),
	}

	eventSourceMappingConfiguration, err := conn.GetEventSourceMapping(params)
	if err != nil {
		return err
	}

	d.Set("batch_size", eventSourceMappingConfiguration.BatchSize)
	d.Set("event_source_arn", eventSourceMappingConfiguration.EventSourceArn)
	d.Set("function_arn", eventSourceMappingConfiguration.FunctionArn)
	d.Set("last_modified", eventSourceMappingConfiguration.LastModified)
	d.Set("last_processing_result", eventSourceMappingConfiguration.LastProcessingResult)
	d.Set("state", eventSourceMappingConfiguration.State)
	d.Set("state_transition_reason", eventSourceMappingConfiguration.StateTransitionReason)
	d.Set("uuid", eventSourceMappingConfiguration.UUID)

	return nil
}

// resourceAwsLambdaEventSourceMappingDelete maps to:
// DeleteEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	log.Printf("[INFO] Deleting Lambda event source mapping: %s", d.Id())

	params := &lambda.DeleteEventSourceMappingInput{
		UUID: aws.String(d.Id()),
	}

	_, err := conn.DeleteEventSourceMapping(params)
	if err != nil {
		return fmt.Errorf("Error deleting Lambda event source mapping: %s", err)
	}

	d.SetId("")

	return nil
}

// resourceAwsLambdaEventSourceMappingUpdate maps to:
// UpdateEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	log.Printf("[DEBUG] Updating Lambda event source mapping: %s", d.Id())

	params := &lambda.UpdateEventSourceMappingInput{
		UUID:         aws.String(d.Id()),
		BatchSize:    aws.Int64(int64(d.Get("batch_size").(int))),
		FunctionName: aws.String(d.Get("function_name").(string)),
		Enabled:      aws.Bool(d.Get("enabled").(bool)),
	}

	_, err := conn.UpdateEventSourceMapping(params)
	if err != nil {
		return fmt.Errorf("Error updating Lambda event source mapping: %s", err)
	}

	return resourceAwsLambdaEventSourceMappingRead(d, meta)
}
<commit_msg>Retry InvalidParameterValueException errors due to newly created resources<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/lambda"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsLambdaEventSourceMapping() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsLambdaEventSourceMappingCreate,
		Read:   resourceAwsLambdaEventSourceMappingRead,
		Update: resourceAwsLambdaEventSourceMappingUpdate,
		Delete: resourceAwsLambdaEventSourceMappingDelete,

		Schema: map[string]*schema.Schema{
			"event_source_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"function_name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"starting_position": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"batch_size": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Default:  100,
			},
			"enabled": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
			"function_arn": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"last_modified": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"last_processing_result": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"state": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"state_transition_reason": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"uuid": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

// resourceAwsLambdaEventSourceMappingCreate maps to:
// CreateEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	functionName := d.Get("function_name").(string)
	eventSourceArn := d.Get("event_source_arn").(string)

	log.Printf("[DEBUG] Creating Lambda event source mapping: source %s to function %s", eventSourceArn, functionName)

	params := &lambda.CreateEventSourceMappingInput{
		EventSourceArn:   aws.String(eventSourceArn),
		FunctionName:     aws.String(functionName),
		StartingPosition: aws.String(d.Get("starting_position").(string)),
		BatchSize:        aws.Int64(int64(d.Get("batch_size").(int))),
		Enabled:          aws.Bool(d.Get("enabled").(bool)),
	}

	err := resource.Retry(1*time.Minute, func() error {
		eventSourceMappingConfiguration, err := conn.CreateEventSourceMapping(params)
		if err != nil {
			if awserr, ok := err.(awserr.Error); ok {
				if awserr.Code() == "InvalidParameterValueException" {
					// Retryable
					return awserr
				}
			}
			// Not retryable
			return resource.RetryError{Err: err}
		}
		// No error
		d.Set("uuid", eventSourceMappingConfiguration.UUID)
		d.SetId(*eventSourceMappingConfiguration.UUID)
		return nil
	})

	if err != nil {
		return fmt.Errorf("Error creating Lambda event source mapping: %s", err)
	}

	return resourceAwsLambdaEventSourceMappingRead(d, meta)
}

// resourceAwsLambdaEventSourceMappingRead maps to:
// GetEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	log.Printf("[DEBUG] Fetching Lambda event source mapping: %s", d.Id())

	params := &lambda.GetEventSourceMappingInput{
		UUID: aws.String(d.Id()),
	}

	eventSourceMappingConfiguration, err := conn.GetEventSourceMapping(params)
	if err != nil {
		return err
	}

	d.Set("batch_size", eventSourceMappingConfiguration.BatchSize)
	d.Set("event_source_arn", eventSourceMappingConfiguration.EventSourceArn)
	d.Set("function_arn", eventSourceMappingConfiguration.FunctionArn)
	d.Set("last_modified", eventSourceMappingConfiguration.LastModified)
	d.Set("last_processing_result", eventSourceMappingConfiguration.LastProcessingResult)
	d.Set("state", eventSourceMappingConfiguration.State)
	d.Set("state_transition_reason", eventSourceMappingConfiguration.StateTransitionReason)
	d.Set("uuid", eventSourceMappingConfiguration.UUID)

	return nil
}

// resourceAwsLambdaEventSourceMappingDelete maps to:
// DeleteEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	log.Printf("[INFO] Deleting Lambda event source mapping: %s", d.Id())

	params := &lambda.DeleteEventSourceMappingInput{
		UUID: aws.String(d.Id()),
	}

	_, err := conn.DeleteEventSourceMapping(params)
	if err != nil {
		return fmt.Errorf("Error deleting Lambda event source mapping: %s", err)
	}

	d.SetId("")

	return nil
}

// resourceAwsLambdaEventSourceMappingUpdate maps to:
// UpdateEventSourceMapping in the API / SDK
func resourceAwsLambdaEventSourceMappingUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).lambdaconn

	log.Printf("[DEBUG] Updating Lambda event source mapping: %s", d.Id())

	params := &lambda.UpdateEventSourceMappingInput{
		UUID:         aws.String(d.Id()),
		BatchSize:    aws.Int64(int64(d.Get("batch_size").(int))),
		FunctionName: aws.String(d.Get("function_name").(string)),
		Enabled:      aws.Bool(d.Get("enabled").(bool)),
	}

	_, err := conn.UpdateEventSourceMapping(params)
	if err != nil {
		return fmt.Errorf("Error updating Lambda event source mapping: %s", err)
	}

	return resourceAwsLambdaEventSourceMappingRead(d, meta)
}
<|endoftext|>


<commit_before>package etcdcontrol

import (
	"net"

	log "github.com/Sirupsen/logrus"
	"golang.org/x/net/context"

	"github.com/weaveworks/flux/common/daemon"
	"github.com/weaveworks/flux/common/data"
	"github.com/weaveworks/flux/common/store"

	"github.com/weaveworks/flux/balancer/model"
)

type Listener struct {
	store     store.Store
	updates   chan<- model.ServiceUpdate
	errorSink daemon.ErrorSink
	context   context.Context
	cancel    context.CancelFunc
}

func NewListener(store store.Store, updates chan<- model.ServiceUpdate) daemon.StartFunc {
	return func(es daemon.ErrorSink) daemon.Component {
		ctx, cancel := context.WithCancel(context.Background())
		listener := &Listener{
			store:     store,
			updates:   updates,
			errorSink: es,
			context:   ctx,
			cancel:    cancel,
		}
		go listener.run()
		return listener
	}
}

func (l *Listener) run() {
	changes := make(chan data.ServiceChange)
	l.store.WatchServices(nil, changes, l.errorSink,
		store.QueryServiceOptions{WithInstances: true})

	if err := l.doInitialQuery(); err != nil {
		l.errorSink.Post(err)
		return
	}

	for {
		change := <-changes
		var ms *model.Service
		if !change.ServiceDeleted {
			svc, err := l.store.GetService(change.Name, store.QueryServiceOptions{WithInstances: true})
			if err != nil {
				l.errorSink.Post(err)
				return
			}

			if ms = translateService(svc); ms == nil {
				continue
			}
		}

		l.updates <- model.ServiceUpdate{
			Updates: map[string]*model.Service{change.Name: ms},
		}
	}
}

func (l *Listener) doInitialQuery() error {
	// Send initial state of each service
	svcs, err := l.store.GetAllServices(store.QueryServiceOptions{WithInstances: true})
	if err != nil {
		return err
	}

	updates := make(map[string]*model.Service)
	for _, svc := range svcs {
		if ms := translateService(svc); ms != nil {
			updates[svc.Name] = ms
		}
	}

	l.updates <- model.ServiceUpdate{
		Updates: updates,
		Reset:   true,
	}
	return nil
}

func translateService(svc *store.ServiceInfo) *model.Service {
	var ip net.IP
	if svc.Address != "" {
		ip = net.ParseIP(svc.Address)
		if ip == nil {
			log.Errorf("Bad address \"%s\" for service %s",
				svc.Address, svc.Name)
			return nil
		}
	}

	insts := []model.Instance{}
	for _, instance := range svc.Instances {
		if instance.State != data.LIVE {
			continue // try next instance
		}

		ip := net.ParseIP(instance.Address)
		if ip == nil {
			log.Errorf("Bad address \"%s\" for instance %s/%s",
				instance.Address, svc.Name, instance.Name)
			continue
		}

		insts = append(insts, model.Instance{
			Name:  instance.Name,
			Group: instance.ContainerRule,
			IP:    ip,
			Port:  instance.Port,
		})
	}

	return &model.Service{
		Name:      svc.Name,
		Protocol:  svc.Protocol,
		IP:        ip,
		Port:      svc.Port,
		Instances: insts,
	}
}

func (l *Listener) Stop() {
	l.cancel()
}
<commit_msg>Stopping the balancer etcd listener didn't actually work<commit_after>package etcdcontrol

import (
	"net"

	log "github.com/Sirupsen/logrus"
	"golang.org/x/net/context"

	"github.com/weaveworks/flux/common/daemon"
	"github.com/weaveworks/flux/common/data"
	"github.com/weaveworks/flux/common/store"

	"github.com/weaveworks/flux/balancer/model"
)

type Listener struct {
	store     store.Store
	updates   chan<- model.ServiceUpdate
	errorSink daemon.ErrorSink
	context   context.Context
	cancel    context.CancelFunc
}

func NewListener(store store.Store, updates chan<- model.ServiceUpdate) daemon.StartFunc {
	return func(es daemon.ErrorSink) daemon.Component {
		ctx, cancel := context.WithCancel(context.Background())
		listener := &Listener{
			store:     store,
			updates:   updates,
			errorSink: es,
			context:   ctx,
			cancel:    cancel,
		}
		go listener.run()
		return listener
	}
}

func (l *Listener) run() {
	changes := make(chan data.ServiceChange)
	l.store.WatchServices(l.context, changes, l.errorSink,
		store.QueryServiceOptions{WithInstances: true})

	if err := l.doInitialQuery(); err != nil {
		l.errorSink.Post(err)
		return
	}

	for {
		change := <-changes
		var ms *model.Service
		if !change.ServiceDeleted {
			svc, err := l.store.GetService(change.Name, store.QueryServiceOptions{WithInstances: true})
			if err != nil {
				l.errorSink.Post(err)
				return
			}

			if ms = translateService(svc); ms == nil {
				continue
			}
		}

		l.updates <- model.ServiceUpdate{
			Updates: map[string]*model.Service{change.Name: ms},
		}
	}
}

func (l *Listener) doInitialQuery() error {
	// Send initial state of each service
	svcs, err := l.store.GetAllServices(store.QueryServiceOptions{WithInstances: true})
	if err != nil {
		return err
	}

	updates := make(map[string]*model.Service)
	for _, svc := range svcs {
		if ms := translateService(svc); ms != nil {
			updates[svc.Name] = ms
		}
	}

	l.updates <- model.ServiceUpdate{
		Updates: updates,
		Reset:   true,
	}
	return nil
}

func translateService(svc *store.ServiceInfo) *model.Service {
	var ip net.IP
	if svc.Address != "" {
		ip = net.ParseIP(svc.Address)
		if ip == nil {
			log.Errorf("Bad address \"%s\" for service %s",
				svc.Address, svc.Name)
			return nil
		}
	}

	insts := []model.Instance{}
	for _, instance := range svc.Instances {
		if instance.State != data.LIVE {
			continue // try next instance
		}

		ip := net.ParseIP(instance.Address)
		if ip == nil {
			log.Errorf("Bad address \"%s\" for instance %s/%s",
				instance.Address, svc.Name, instance.Name)
			continue
		}

		insts = append(insts, model.Instance{
			Name:  instance.Name,
			Group: instance.ContainerRule,
			IP:    ip,
			Port:  instance.Port,
		})
	}

	return &model.Service{
		Name:      svc.Name,
		Protocol:  svc.Protocol,
		IP:        ip,
		Port:      svc.Port,
		Instances: insts,
	}
}

func (l *Listener) Stop() {
	l.cancel()
}
<|endoftext|>


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

package cmd

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

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/byteorder"
	"github.com/cilium/cilium/pkg/command"
	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/u8proto"

	"github.com/spf13/cobra"
)

var printIDs bool

// bpfPolicyListCmd represents the bpf_policy_list command
var bpfPolicyListCmd = &cobra.Command{
	Use:    "get",
	Short:  "List contents of a policy BPF map",
	PreRun: requireEndpointID,
	Run: func(cmd *cobra.Command, args []string) {
		common.RequireRootPrivilege("cilium bpf policy get")
		listMap(cmd, args)
	},
}

func init() {
	bpfPolicyCmd.AddCommand(bpfPolicyListCmd)
	bpfPolicyListCmd.Flags().BoolVarP(&printIDs, "numeric", "n", false, "Do not resolve IDs")
	command.AddJSONOutput(bpfPolicyListCmd)
}

func listMap(cmd *cobra.Command, args []string) {
	lbl := args[0]

	if lbl != "" {
		if id := identity.GetReservedID(lbl); id != identity.IdentityUnknown {
			lbl = "reserved_" + strconv.FormatUint(uint64(id), 10)
		}
	} else {
		Fatalf("Need ID or label\n")
	}

	file := bpf.MapPath(policymap.MapName + lbl)
	fd, err := bpf.ObjGet(file)
	if err != nil {
		Fatalf("%s\n", err)
	}
	defer bpf.ObjClose(fd)

	m := policymap.PolicyMap{Fd: fd}
	statsMap, err := m.DumpToSlice()
	if err != nil {
		Fatalf("Error while opening bpf Map: %s\n", err)
	}

	if command.OutputJSON() {
		if err := command.PrintOutput(statsMap); err != nil {
			os.Exit(1)
		}
	} else {
		w := tabwriter.NewWriter(os.Stdout, 5, 0, 3, ' ', 0)
		formatMap(w, statsMap)
		w.Flush()
		if len(statsMap) == 0 {
			fmt.Printf("Policy stats empty. Perhaps the policy enforcement is disabled?\n")
		}
	}
}

func formatMap(w io.Writer, statsMap []policymap.PolicyEntryDump) {
	const (
		trafficDirectionTitle = "DIRECTION"
		labelsIDTitle         = "IDENTITY"
		labelsDesTitle        = "LABELS (source:key[=value])"
		portTitle             = "PORT/PROTO"
		bytesTitle            = "BYTES"
		packetsTitle          = "PACKETS"
	)

	labelsID := map[identity.NumericIdentity]*identity.Identity{}
	for _, stat := range statsMap {
		if !printIDs {
			id := identity.NumericIdentity(stat.Key.Identity)
			if lbls, err := client.IdentityGet(id.StringID()); err != nil {
				fmt.Fprintf(os.Stderr, "Was impossible to retrieve label ID %d: %s\n",
					id, err)
			} else {
				labelsID[id] = identity.NewIdentityFromModel(lbls)
			}
		}

	}

	if printIDs {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n", trafficDirectionTitle, labelsIDTitle, portTitle, bytesTitle, packetsTitle)
	} else {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n", trafficDirectionTitle, labelsDesTitle, portTitle, bytesTitle, packetsTitle)
	}
	for _, stat := range statsMap {
		id := identity.NumericIdentity(stat.Key.Identity)
		trafficDirection := policymap.TrafficDirection(stat.Key.TrafficDirection)
		trafficDirectionString := trafficDirection.String()
		port := models.PortProtocolANY
		if stat.Key.DestPort != 0 {
			dport := byteorder.NetworkToHost(stat.Key.DestPort).(uint16)
			proto := u8proto.U8proto(stat.Key.Nexthdr)
			port = fmt.Sprintf("%d/%s", dport, proto.String())
		}
		if printIDs {
			fmt.Fprintf(w, "%s\t%d\t%s\t%d\t%d\t\n", trafficDirectionString, id, port, stat.Bytes, stat.Packets)
		} else if lbls := labelsID[id]; lbls != nil {
			first := true
			for _, lbl := range lbls.Labels {
				if first {
					fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%d\t\n", trafficDirectionString, lbl, port, stat.Bytes, stat.Packets)
					first = false
				} else {
					fmt.Fprintf(w, "\t%s\t\t\t\t\t\n", lbl)
				}
			}
		} else {
			fmt.Fprintf(w, "%s\t%d\t%s\t%d\t%d\t\n", trafficDirectionString, id, port, stat.Bytes, stat.Packets)
		}
	}
}
<commit_msg>cli: Fix cilium bpf policy get<commit_after>// Copyright 2017-2018 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

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

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/byteorder"
	"github.com/cilium/cilium/pkg/command"
	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/u8proto"

	"github.com/spf13/cobra"
)

var printIDs bool

// bpfPolicyListCmd represents the bpf_policy_list command
var bpfPolicyListCmd = &cobra.Command{
	Use:    "get",
	Short:  "List contents of a policy BPF map",
	PreRun: requireEndpointID,
	Run: func(cmd *cobra.Command, args []string) {
		common.RequireRootPrivilege("cilium bpf policy get")
		listMap(cmd, args)
	},
}

func init() {
	bpfPolicyCmd.AddCommand(bpfPolicyListCmd)
	bpfPolicyListCmd.Flags().BoolVarP(&printIDs, "numeric", "n", false, "Do not resolve IDs")
	command.AddJSONOutput(bpfPolicyListCmd)
}

func listMap(cmd *cobra.Command, args []string) {
	lbl := args[0]

	if lbl != "" {
		if id := identity.GetReservedID(lbl); id != identity.IdentityUnknown {
			lbl = "reserved_" + strconv.FormatUint(uint64(id), 10)
		}
	} else {
		Fatalf("Need ID or label\n")
	}

	file := bpf.MapPath(policymap.MapName + lbl)
	fd, err := bpf.ObjGet(file)
	if err != nil {
		Fatalf("%s\n", err)
	}
	defer bpf.ObjClose(fd)

	m := policymap.PolicyMap{Fd: fd}
	statsMap, err := m.DumpToSlice()
	if err != nil {
		Fatalf("Error while opening bpf Map: %s\n", err)
	}

	if command.OutputJSON() {
		if err := command.PrintOutput(statsMap); err != nil {
			os.Exit(1)
		}
	} else {
		w := tabwriter.NewWriter(os.Stdout, 5, 0, 3, ' ', 0)
		formatMap(w, statsMap)
		w.Flush()
		if len(statsMap) == 0 {
			fmt.Printf("Policy stats empty. Perhaps the policy enforcement is disabled?\n")
		}
	}
}

func formatMap(w io.Writer, statsMap []policymap.PolicyEntryDump) {
	const (
		trafficDirectionTitle = "DIRECTION"
		labelsIDTitle         = "IDENTITY"
		labelsDesTitle        = "LABELS (source:key[=value])"
		portTitle             = "PORT/PROTO"
		bytesTitle            = "BYTES"
		packetsTitle          = "PACKETS"
	)

	labelsID := map[identity.NumericIdentity]*identity.Identity{}
	for _, stat := range statsMap {
		if !printIDs {
			id := identity.NumericIdentity(stat.Key.Identity)
			if lbls, err := client.IdentityGet(id.StringID()); err != nil {
				fmt.Fprintf(os.Stderr, "Was impossible to retrieve label ID %d: %s\n",
					id, err)
			} else {
				labelsID[id] = identity.NewIdentityFromModel(lbls)
			}
		}

	}

	if printIDs {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n", trafficDirectionTitle, labelsIDTitle, portTitle, bytesTitle, packetsTitle)
	} else {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n", trafficDirectionTitle, labelsDesTitle, portTitle, bytesTitle, packetsTitle)
	}
	for _, stat := range statsMap {
		id := identity.NumericIdentity(stat.Key.Identity)
		trafficDirection := policymap.TrafficDirection(stat.Key.TrafficDirection)
		trafficDirectionString := trafficDirection.String()
		port := models.PortProtocolANY
		if stat.Key.DestPort != 0 {
			dport := byteorder.NetworkToHost(stat.Key.DestPort).(uint16)
			proto := u8proto.U8proto(stat.Key.Nexthdr)
			port = fmt.Sprintf("%d/%s", dport, proto.String())
		}
		if printIDs {
			fmt.Fprintf(w, "%s\t%d\t%s\t%d\t%d\t\n", trafficDirectionString, id, port, stat.Bytes, stat.Packets)
		} else if lbls := labelsID[id]; lbls != nil && len(lbls.Labels) > 0 {
			first := true
			for _, lbl := range lbls.Labels {
				if first {
					fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%d\t\n", trafficDirectionString, lbl, port, stat.Bytes, stat.Packets)
					first = false
				} else {
					fmt.Fprintf(w, "\t%s\t\t\t\t\t\n", lbl)
				}
			}
		} else {
			fmt.Fprintf(w, "%s\t%d\t%s\t%d\t%d\t\n", trafficDirectionString, id, port, stat.Bytes, stat.Packets)
		}
	}
}
<|endoftext|>