<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fuzzer

import (
	"fmt"

	fuzz "github.com/google/gofuzz"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/kubernetes/pkg/apis/extensions"
)

// Funcs returns the fuzzer functions for the extensions api group.
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
	return []interface{}{
		func(j *extensions.DeploymentSpec, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			rhl := int32(c.Rand.Int31())
			pds := int32(c.Rand.Int31())
			j.RevisionHistoryLimit = &rhl
			j.ProgressDeadlineSeconds = &pds
		},
		func(j *extensions.DeploymentStrategy, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			// Ensure that strategyType is one of valid values.
			strategyTypes := []extensions.DeploymentStrategyType{extensions.RecreateDeploymentStrategyType, extensions.RollingUpdateDeploymentStrategyType}
			j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
			if j.Type != extensions.RollingUpdateDeploymentStrategyType {
				j.RollingUpdate = nil
			} else {
				rollingUpdate := extensions.RollingUpdateDeployment{}
				if c.RandBool() {
					rollingUpdate.MaxUnavailable = intstr.FromInt(int(c.Rand.Int31()))
					rollingUpdate.MaxSurge = intstr.FromInt(int(c.Rand.Int31()))
				} else {
					rollingUpdate.MaxSurge = intstr.FromString(fmt.Sprintf("%d%%", c.Rand.Int31()))
				}
				j.RollingUpdate = &rollingUpdate
			}
		},
		func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) {
			c.FuzzNoCustom(psp) // fuzz self without calling this function again

			runAsUserRules := []extensions.RunAsUserStrategy{
				extensions.RunAsUserStrategyMustRunAsNonRoot,
				extensions.RunAsUserStrategyMustRunAs,
				extensions.RunAsUserStrategyRunAsAny,
			}
			psp.RunAsUser.Rule = runAsUserRules[c.Rand.Intn(len(runAsUserRules))]

			seLinuxRules := []extensions.SELinuxStrategy{
				extensions.SELinuxStrategyMustRunAs,
				extensions.SELinuxStrategyRunAsAny,
			}
			psp.SELinux.Rule = seLinuxRules[c.Rand.Intn(len(seLinuxRules))]

			supplementalGroupsRules := []extensions.SupplementalGroupsStrategyType{
				extensions.SupplementalGroupsStrategyRunAsAny,
				extensions.SupplementalGroupsStrategyMustRunAs,
			}
			psp.SupplementalGroups.Rule = supplementalGroupsRules[c.Rand.Intn(len(supplementalGroupsRules))]

			fsGroupRules := []extensions.FSGroupStrategyType{
				extensions.FSGroupStrategyMustRunAs,
				extensions.FSGroupStrategyRunAsAny,
			}
			psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))]
		},
		func(s *extensions.Scale, c fuzz.Continue) {
			c.FuzzNoCustom(s) // fuzz self without calling this function again
			// TODO: Implement a fuzzer to generate valid keys, values and operators for
			// selector requirements.
			if s.Status.Selector != nil {
				s.Status.Selector = &metav1.LabelSelector{
					MatchLabels: map[string]string{
						"testlabelkey": "testlabelval",
					},
					MatchExpressions: []metav1.LabelSelectorRequirement{
						{
							Key:      "testkey",
							Operator: metav1.LabelSelectorOpIn,
							Values:   []string{"val1", "val2", "val3"},
						},
					},
				}
			}
		},
		func(j *extensions.DaemonSetSpec, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			rhl := int32(c.Rand.Int31())
			j.RevisionHistoryLimit = &rhl
		},
		func(j *extensions.DaemonSetUpdateStrategy, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			// Ensure that strategyType is one of valid values.
			strategyTypes := []extensions.DaemonSetUpdateStrategyType{extensions.RollingUpdateDaemonSetStrategyType, extensions.OnDeleteDaemonSetStrategyType}
			j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
			if j.Type != extensions.RollingUpdateDaemonSetStrategyType {
				j.RollingUpdate = nil
			} else {
				rollingUpdate := extensions.RollingUpdateDaemonSet{}
				if c.RandBool() {
					if c.RandBool() {
						rollingUpdate.MaxUnavailable = intstr.FromInt(1 + int(c.Rand.Int31()))
					} else {
						rollingUpdate.MaxUnavailable = intstr.FromString(fmt.Sprintf("%d%%", 1+c.Rand.Int31()))
					}
				}
				j.RollingUpdate = &rollingUpdate
			}
		},
	}
}
<commit_msg>Update extensions fuzzer to use selector fuzzer<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fuzzer

import (
	"fmt"

	fuzz "github.com/google/gofuzz"

	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/kubernetes/pkg/apis/extensions"
)

// Funcs returns the fuzzer functions for the extensions api group.
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
	return []interface{}{
		func(j *extensions.DeploymentSpec, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			rhl := int32(c.Rand.Int31())
			pds := int32(c.Rand.Int31())
			j.RevisionHistoryLimit = &rhl
			j.ProgressDeadlineSeconds = &pds
		},
		func(j *extensions.DeploymentStrategy, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			// Ensure that strategyType is one of valid values.
			strategyTypes := []extensions.DeploymentStrategyType{extensions.RecreateDeploymentStrategyType, extensions.RollingUpdateDeploymentStrategyType}
			j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
			if j.Type != extensions.RollingUpdateDeploymentStrategyType {
				j.RollingUpdate = nil
			} else {
				rollingUpdate := extensions.RollingUpdateDeployment{}
				if c.RandBool() {
					rollingUpdate.MaxUnavailable = intstr.FromInt(int(c.Rand.Int31()))
					rollingUpdate.MaxSurge = intstr.FromInt(int(c.Rand.Int31()))
				} else {
					rollingUpdate.MaxSurge = intstr.FromString(fmt.Sprintf("%d%%", c.Rand.Int31()))
				}
				j.RollingUpdate = &rollingUpdate
			}
		},
		func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) {
			c.FuzzNoCustom(psp) // fuzz self without calling this function again

			runAsUserRules := []extensions.RunAsUserStrategy{
				extensions.RunAsUserStrategyMustRunAsNonRoot,
				extensions.RunAsUserStrategyMustRunAs,
				extensions.RunAsUserStrategyRunAsAny,
			}
			psp.RunAsUser.Rule = runAsUserRules[c.Rand.Intn(len(runAsUserRules))]

			seLinuxRules := []extensions.SELinuxStrategy{
				extensions.SELinuxStrategyMustRunAs,
				extensions.SELinuxStrategyRunAsAny,
			}
			psp.SELinux.Rule = seLinuxRules[c.Rand.Intn(len(seLinuxRules))]

			supplementalGroupsRules := []extensions.SupplementalGroupsStrategyType{
				extensions.SupplementalGroupsStrategyRunAsAny,
				extensions.SupplementalGroupsStrategyMustRunAs,
			}
			psp.SupplementalGroups.Rule = supplementalGroupsRules[c.Rand.Intn(len(supplementalGroupsRules))]

			fsGroupRules := []extensions.FSGroupStrategyType{
				extensions.FSGroupStrategyMustRunAs,
				extensions.FSGroupStrategyRunAsAny,
			}
			psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))]
		},
		func(j *extensions.DaemonSetSpec, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			rhl := int32(c.Rand.Int31())
			j.RevisionHistoryLimit = &rhl
		},
		func(j *extensions.DaemonSetUpdateStrategy, c fuzz.Continue) {
			c.FuzzNoCustom(j) // fuzz self without calling this function again
			// Ensure that strategyType is one of valid values.
			strategyTypes := []extensions.DaemonSetUpdateStrategyType{extensions.RollingUpdateDaemonSetStrategyType, extensions.OnDeleteDaemonSetStrategyType}
			j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))]
			if j.Type != extensions.RollingUpdateDaemonSetStrategyType {
				j.RollingUpdate = nil
			} else {
				rollingUpdate := extensions.RollingUpdateDaemonSet{}
				if c.RandBool() {
					if c.RandBool() {
						rollingUpdate.MaxUnavailable = intstr.FromInt(1 + int(c.Rand.Int31()))
					} else {
						rollingUpdate.MaxUnavailable = intstr.FromString(fmt.Sprintf("%d%%", 1+c.Rand.Int31()))
					}
				}
				j.RollingUpdate = &rollingUpdate
			}
		},
	}
}
<|endoftext|>


<commit_before>//go:build linux
// +build linux

/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kubelet

import (
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/klog/v2"
	utiliptables "k8s.io/kubernetes/pkg/util/iptables"
	utilexec "k8s.io/utils/exec"
	utilnet "k8s.io/utils/net"
)

const (
	// KubeIPTablesHintChain is the chain whose existence in either iptables-legacy
	// or iptables-nft indicates which version of iptables the system is using
	KubeIPTablesHintChain utiliptables.Chain = "KUBE-IPTABLES-HINT"

	// KubeMarkMasqChain is the mark-for-masquerade chain
	// TODO: clean up this logic in kube-proxy
	KubeMarkMasqChain utiliptables.Chain = "KUBE-MARK-MASQ"

	// KubeMarkDropChain is the mark-for-drop chain
	KubeMarkDropChain utiliptables.Chain = "KUBE-MARK-DROP"

	// KubePostroutingChain is kubernetes postrouting rules
	KubePostroutingChain utiliptables.Chain = "KUBE-POSTROUTING"

	// KubeFirewallChain is kubernetes firewall rules
	KubeFirewallChain utiliptables.Chain = "KUBE-FIREWALL"
)

func (kl *Kubelet) initNetworkUtil() {
	exec := utilexec.New()
	// TODO: @khenidak review when there is no IPv6 iptables exec  what should happen here (note: no error returned from this func)
	ipv6Primary := kl.nodeIPs != nil && utilnet.IsIPv6(kl.nodeIPs[0])

	var iptClients []utiliptables.Interface
	var protocols []utiliptables.Protocol

	// assume 4,6
	protocols = append(protocols, utiliptables.ProtocolIPv4)
	iptClients = append(iptClients, utiliptables.New(exec, utiliptables.ProtocolIPv4))

	protocols = append(protocols, utiliptables.ProtocolIPv6)
	iptClients = append(iptClients, utiliptables.New(exec, utiliptables.ProtocolIPv6))

	// and if they are not
	if ipv6Primary {
		protocols[0], protocols[1] = protocols[1], protocols[0]
		iptClients[0], iptClients[1] = iptClients[1], iptClients[0]
	}

	for i := range iptClients {
		iptClient := iptClients[i]
		if kl.syncNetworkUtil(iptClient) {
			klog.InfoS("Initialized protocol iptables rules.", "protocol", protocols[i])
			go iptClient.Monitor(
				utiliptables.Chain("KUBE-KUBELET-CANARY"),
				[]utiliptables.Table{utiliptables.TableMangle, utiliptables.TableNAT, utiliptables.TableFilter},
				func() { kl.syncNetworkUtil(iptClient) },
				1*time.Minute, wait.NeverStop,
			)
		} else {
			klog.InfoS("Failed to initialize protocol iptables rules; some functionality may be missing.", "protocol", protocols[i])
		}
	}
}

// syncNetworkUtil ensures the network utility are present on host.
// Network util includes:
//  1. In nat table, KUBE-MARK-DROP rule to mark connections for dropping
//     Marked connection will be drop on INPUT/OUTPUT Chain in filter table
//  2. In nat table, KUBE-MARK-MASQ rule to mark connections for SNAT
//     Marked connection will get SNAT on POSTROUTING Chain in nat table
func (kl *Kubelet) syncNetworkUtil(iptClient utiliptables.Interface) bool {
	// Setup KUBE-MARK-DROP rules
	dropMark := getIPTablesMark(kl.iptablesDropBit)
	if _, err := iptClient.EnsureChain(utiliptables.TableNAT, KubeMarkDropChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat chain exists KUBE-MARK-DROP chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubeMarkDropChain, "-j", "MARK", "--or-mark", dropMark); err != nil {
		klog.ErrorS(err, "Failed to ensure marking rule for KUBE-MARK-DROP chain")
		return false
	}
	if _, err := iptClient.EnsureChain(utiliptables.TableFilter, KubeFirewallChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that filter table exists KUBE-FIREWALL chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableFilter, KubeFirewallChain,
		"-m", "comment", "--comment", "kubernetes firewall for dropping marked packets",
		"-m", "mark", "--mark", fmt.Sprintf("%s/%s", dropMark, dropMark),
		"-j", "DROP"); err != nil {
		klog.ErrorS(err, "Failed to ensure rule to drop packet marked by the KUBE-MARK-DROP in KUBE-FIREWALL chain")
		return false
	}

	// drop all non-local packets to localhost if they're not part of an existing
	// forwarded connection. See #90259
	if !iptClient.IsIPv6() { // ipv6 doesn't have this issue
		if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableFilter, KubeFirewallChain,
			"-m", "comment", "--comment", "block incoming localnet connections",
			"--dst", "127.0.0.0/8",
			"!", "--src", "127.0.0.0/8",
			"-m", "conntrack",
			"!", "--ctstate", "RELATED,ESTABLISHED,DNAT",
			"-j", "DROP"); err != nil {
			klog.ErrorS(err, "Failed to ensure rule to drop invalid localhost packets in filter table KUBE-FIREWALL chain")
			return false
		}
	}

	if _, err := iptClient.EnsureRule(utiliptables.Prepend, utiliptables.TableFilter, utiliptables.ChainOutput, "-j", string(KubeFirewallChain)); err != nil {
		klog.ErrorS(err, "Failed to ensure that filter table  from OUTPUT chain jumps to KUBE-FIREWALL chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Prepend, utiliptables.TableFilter, utiliptables.ChainInput, "-j", string(KubeFirewallChain)); err != nil {
		klog.ErrorS(err, "Failed to ensure that filter table INPUT chain jumps to KUBE-FIREWALL chain")
		return false
	}

	// Setup KUBE-MARK-MASQ rules
	masqueradeMark := getIPTablesMark(kl.iptablesMasqueradeBit)
	if _, err := iptClient.EnsureChain(utiliptables.TableNAT, KubeMarkMasqChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat table exists KUBE-MARK-MASQ chain")
		return false
	}
	if _, err := iptClient.EnsureChain(utiliptables.TableNAT, KubePostroutingChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat table exists kube POSTROUTING chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubeMarkMasqChain, "-j", "MARK", "--or-mark", masqueradeMark); err != nil {
		klog.ErrorS(err, "Failed to ensure marking rule for KUBE-MARK-MASQ chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Prepend, utiliptables.TableNAT, utiliptables.ChainPostrouting,
		"-m", "comment", "--comment", "kubernetes postrouting rules", "-j", string(KubePostroutingChain)); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat table from POSTROUTING chain jumps to KUBE-POSTROUTING chain")
		return false
	}

	// Set up KUBE-POSTROUTING to unmark and masquerade marked packets
	// NB: THIS MUST MATCH the corresponding code in the iptables and ipvs
	// modes of kube-proxy
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubePostroutingChain,
		"-m", "mark", "!", "--mark", fmt.Sprintf("%s/%s", masqueradeMark, masqueradeMark),
		"-j", "RETURN"); err != nil {
		klog.ErrorS(err, "Failed to ensure filtering rule for KUBE-POSTROUTING chain")
		return false
	}
	// Clear the mark to avoid re-masquerading if the packet re-traverses the network stack.
	// We know the mark bit is currently set so we can use --xor-mark to clear it (without needing
	// to Sprintf another bitmask).
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubePostroutingChain,
		"-j", "MARK", "--xor-mark", masqueradeMark); err != nil {
		klog.ErrorS(err, "Failed to ensure unmarking rule for KUBE-POSTROUTING chain")
		return false
	}
	masqRule := []string{
		"-m", "comment", "--comment", "kubernetes service traffic requiring SNAT",
		"-j", "MASQUERADE",
	}
	if iptClient.HasRandomFully() {
		masqRule = append(masqRule, "--random-fully")
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubePostroutingChain, masqRule...); err != nil {
		klog.ErrorS(err, "Failed to ensure SNAT rule for packets marked by KUBE-MARK-MASQ chain in nat table KUBE-POSTROUTING chain")
		return false
	}

	// Create hint chain so other components can see whether we are using iptables-legacy
	// or iptables-nft.
	if _, err := iptClient.EnsureChain(utiliptables.TableMangle, KubeIPTablesHintChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that iptables hint chain exists")
		return false
	}

	return true
}

// getIPTablesMark returns the fwmark given the bit
func getIPTablesMark(bit int) string {
	value := 1 << uint(bit)
	return fmt.Sprintf("%#08x", value)
}
<commit_msg>Clean up kubelet iptables setup a bit<commit_after>//go:build linux
// +build linux

/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kubelet

import (
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/klog/v2"
	utiliptables "k8s.io/kubernetes/pkg/util/iptables"
	utilexec "k8s.io/utils/exec"
)

const (
	// KubeIPTablesHintChain is the chain whose existence in either iptables-legacy
	// or iptables-nft indicates which version of iptables the system is using
	KubeIPTablesHintChain utiliptables.Chain = "KUBE-IPTABLES-HINT"

	// KubeMarkMasqChain is the mark-for-masquerade chain
	// TODO: clean up this logic in kube-proxy
	KubeMarkMasqChain utiliptables.Chain = "KUBE-MARK-MASQ"

	// KubeMarkDropChain is the mark-for-drop chain
	KubeMarkDropChain utiliptables.Chain = "KUBE-MARK-DROP"

	// KubePostroutingChain is kubernetes postrouting rules
	KubePostroutingChain utiliptables.Chain = "KUBE-POSTROUTING"

	// KubeFirewallChain is kubernetes firewall rules
	KubeFirewallChain utiliptables.Chain = "KUBE-FIREWALL"
)

func (kl *Kubelet) initNetworkUtil() {
	exec := utilexec.New()
	iptClients := []utiliptables.Interface{
		utiliptables.New(exec, utiliptables.ProtocolIPv4),
		utiliptables.New(exec, utiliptables.ProtocolIPv6),
	}

	for i := range iptClients {
		iptClient := iptClients[i]
		if kl.syncNetworkUtil(iptClient) {
			klog.InfoS("Initialized protocol iptables rules.", "protocol", iptClient.Protocol())
			go iptClient.Monitor(
				utiliptables.Chain("KUBE-KUBELET-CANARY"),
				[]utiliptables.Table{utiliptables.TableMangle, utiliptables.TableNAT, utiliptables.TableFilter},
				func() { kl.syncNetworkUtil(iptClient) },
				1*time.Minute, wait.NeverStop,
			)
		} else {
			klog.InfoS("Failed to initialize protocol iptables rules; some functionality may be missing.", "protocol", iptClient.Protocol())
		}
	}
}

// syncNetworkUtil ensures the network utility are present on host.
// Network util includes:
//  1. In nat table, KUBE-MARK-DROP rule to mark connections for dropping
//     Marked connection will be drop on INPUT/OUTPUT Chain in filter table
//  2. In nat table, KUBE-MARK-MASQ rule to mark connections for SNAT
//     Marked connection will get SNAT on POSTROUTING Chain in nat table
func (kl *Kubelet) syncNetworkUtil(iptClient utiliptables.Interface) bool {
	// Setup KUBE-MARK-DROP rules
	dropMark := getIPTablesMark(kl.iptablesDropBit)
	if _, err := iptClient.EnsureChain(utiliptables.TableNAT, KubeMarkDropChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat chain exists KUBE-MARK-DROP chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubeMarkDropChain, "-j", "MARK", "--or-mark", dropMark); err != nil {
		klog.ErrorS(err, "Failed to ensure marking rule for KUBE-MARK-DROP chain")
		return false
	}
	if _, err := iptClient.EnsureChain(utiliptables.TableFilter, KubeFirewallChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that filter table exists KUBE-FIREWALL chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableFilter, KubeFirewallChain,
		"-m", "comment", "--comment", "kubernetes firewall for dropping marked packets",
		"-m", "mark", "--mark", fmt.Sprintf("%s/%s", dropMark, dropMark),
		"-j", "DROP"); err != nil {
		klog.ErrorS(err, "Failed to ensure rule to drop packet marked by the KUBE-MARK-DROP in KUBE-FIREWALL chain")
		return false
	}

	// drop all non-local packets to localhost if they're not part of an existing
	// forwarded connection. See #90259
	if !iptClient.IsIPv6() { // ipv6 doesn't have this issue
		if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableFilter, KubeFirewallChain,
			"-m", "comment", "--comment", "block incoming localnet connections",
			"--dst", "127.0.0.0/8",
			"!", "--src", "127.0.0.0/8",
			"-m", "conntrack",
			"!", "--ctstate", "RELATED,ESTABLISHED,DNAT",
			"-j", "DROP"); err != nil {
			klog.ErrorS(err, "Failed to ensure rule to drop invalid localhost packets in filter table KUBE-FIREWALL chain")
			return false
		}
	}

	if _, err := iptClient.EnsureRule(utiliptables.Prepend, utiliptables.TableFilter, utiliptables.ChainOutput, "-j", string(KubeFirewallChain)); err != nil {
		klog.ErrorS(err, "Failed to ensure that filter table  from OUTPUT chain jumps to KUBE-FIREWALL chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Prepend, utiliptables.TableFilter, utiliptables.ChainInput, "-j", string(KubeFirewallChain)); err != nil {
		klog.ErrorS(err, "Failed to ensure that filter table INPUT chain jumps to KUBE-FIREWALL chain")
		return false
	}

	// Setup KUBE-MARK-MASQ rules
	masqueradeMark := getIPTablesMark(kl.iptablesMasqueradeBit)
	if _, err := iptClient.EnsureChain(utiliptables.TableNAT, KubeMarkMasqChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat table exists KUBE-MARK-MASQ chain")
		return false
	}
	if _, err := iptClient.EnsureChain(utiliptables.TableNAT, KubePostroutingChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat table exists kube POSTROUTING chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubeMarkMasqChain, "-j", "MARK", "--or-mark", masqueradeMark); err != nil {
		klog.ErrorS(err, "Failed to ensure marking rule for KUBE-MARK-MASQ chain")
		return false
	}
	if _, err := iptClient.EnsureRule(utiliptables.Prepend, utiliptables.TableNAT, utiliptables.ChainPostrouting,
		"-m", "comment", "--comment", "kubernetes postrouting rules", "-j", string(KubePostroutingChain)); err != nil {
		klog.ErrorS(err, "Failed to ensure that nat table from POSTROUTING chain jumps to KUBE-POSTROUTING chain")
		return false
	}

	// Set up KUBE-POSTROUTING to unmark and masquerade marked packets
	// NB: THIS MUST MATCH the corresponding code in the iptables and ipvs
	// modes of kube-proxy
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubePostroutingChain,
		"-m", "mark", "!", "--mark", fmt.Sprintf("%s/%s", masqueradeMark, masqueradeMark),
		"-j", "RETURN"); err != nil {
		klog.ErrorS(err, "Failed to ensure filtering rule for KUBE-POSTROUTING chain")
		return false
	}
	// Clear the mark to avoid re-masquerading if the packet re-traverses the network stack.
	// We know the mark bit is currently set so we can use --xor-mark to clear it (without needing
	// to Sprintf another bitmask).
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubePostroutingChain,
		"-j", "MARK", "--xor-mark", masqueradeMark); err != nil {
		klog.ErrorS(err, "Failed to ensure unmarking rule for KUBE-POSTROUTING chain")
		return false
	}
	masqRule := []string{
		"-m", "comment", "--comment", "kubernetes service traffic requiring SNAT",
		"-j", "MASQUERADE",
	}
	if iptClient.HasRandomFully() {
		masqRule = append(masqRule, "--random-fully")
	}
	if _, err := iptClient.EnsureRule(utiliptables.Append, utiliptables.TableNAT, KubePostroutingChain, masqRule...); err != nil {
		klog.ErrorS(err, "Failed to ensure SNAT rule for packets marked by KUBE-MARK-MASQ chain in nat table KUBE-POSTROUTING chain")
		return false
	}

	// Create hint chain so other components can see whether we are using iptables-legacy
	// or iptables-nft.
	if _, err := iptClient.EnsureChain(utiliptables.TableMangle, KubeIPTablesHintChain); err != nil {
		klog.ErrorS(err, "Failed to ensure that iptables hint chain exists")
		return false
	}

	return true
}

// getIPTablesMark returns the fwmark given the bit
func getIPTablesMark(bit int) string {
	value := 1 << uint(bit)
	return fmt.Sprintf("%#08x", value)
}
<|endoftext|>


<commit_before>package paypal

import (
	"fmt"
	"time"
)

// https://developer.paypal.com/docs/api/#vault

type (
	VaultRequest struct {
		CreditCard
		MerchantID     string `json:"merchant_id,omitempty"`
		ExternalCardID string `json:"external_card_id,omitempty"`
	}

	VaultResponse struct {
		VaultRequest
		CreateTime *time.Time `json: "create_time"`
		UpdateTime *time.Time `json: "update_time"`
		State      string     `json: "state"`
		ValidUntil string     `json: "valid_until"`
		Links      []Links    `json:"links"`
	}
)

// StoreInVault will store credit card details with PayPal.
func (c *Client) StoreInVault(cc VaultRequest) (*VaultResponse, error) {

	req, err := NewRequest("POST", fmt.Sprintf("%s/vault/credit-cards", c.APIBase), cc)

	if err != nil {
		return nil, err
	}
	v := &VaultResponse{}

	err = c.SendWithAuth(req, v)
	if err != nil {
		return nil, err
	}
	return v, nil
}
<commit_msg>Added: Vault Struct Comments<commit_after>package paypal

import (
	"fmt"
	"time"
)

// https://developer.paypal.com/docs/api/#vault

type (
	// VaultRequest maps to vault_request object
	VaultRequest struct {
		CreditCard
		MerchantID     string `json:"merchant_id,omitempty"`
		ExternalCardID string `json:"external_card_id,omitempty"`
	}

	// VaultResponse maps to vault_response object
	VaultResponse struct {
		VaultRequest
		CreateTime *time.Time `json: "create_time"`
		UpdateTime *time.Time `json: "update_time"`
		State      string     `json: "state"`
		ValidUntil string     `json: "valid_until"`
		Links      []Links    `json:"links"`
	}
)

// StoreInVault will store credit card details with PayPal.
func (c *Client) StoreInVault(cc VaultRequest) (*VaultResponse, error) {

	req, err := NewRequest("POST", fmt.Sprintf("%s/vault/credit-cards", c.APIBase), cc)

	if err != nil {
		return nil, err
	}
	v := &VaultResponse{}

	err = c.SendWithAuth(req, v)
	if err != nil {
		return nil, err
	}
	return v, nil
}
<|endoftext|>


<commit_before>// +build linux

package mem

import (
	"context"
	"strconv"
	"strings"

	"github.com/shirou/gopsutil/internal/common"
	"golang.org/x/sys/unix"
)

func VirtualMemory() (*VirtualMemoryStat, error) {
	return VirtualMemoryWithContext(context.Background())
}

func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
	filename := common.HostProc("meminfo")
	lines, _ := common.ReadLines(filename)
	// flag if MemAvailable is in /proc/meminfo (kernel 3.14+)
	memavail := false

	ret := &VirtualMemoryStat{}
	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) != 2 {
			continue
		}
		key := strings.TrimSpace(fields[0])
		value := strings.TrimSpace(fields[1])
		value = strings.Replace(value, " kB", "", -1)

		t, err := strconv.ParseUint(value, 10, 64)
		if err != nil {
			return ret, err
		}
		switch key {
		case "MemTotal":
			ret.Total = t * 1024
		case "MemFree":
			ret.Free = t * 1024
		case "MemAvailable":
			memavail = true
			ret.Available = t * 1024
		case "Buffers":
			ret.Buffers = t * 1024
		case "Cached":
			ret.Cached = t * 1024
		case "Active":
			ret.Active = t * 1024
		case "Inactive":
			ret.Inactive = t * 1024
		case "Writeback":
			ret.Writeback = t * 1024
		case "WritebackTmp":
			ret.WritebackTmp = t * 1024
		case "Dirty":
			ret.Dirty = t * 1024
		case "Shmem":
			ret.Shared = t * 1024
		case "Slab":
			ret.Slab = t * 1024
		case "SReclaimable":
			ret.SReclaimable = t * 1024
		case "PageTables":
			ret.PageTables = t * 1024
		case "SwapCached":
			ret.SwapCached = t * 1024
		case "CommitLimit":
			ret.CommitLimit = t * 1024
		case "Committed_AS":
			ret.CommittedAS = t * 1024
		case "HighTotal":
			ret.HighTotal = t * 1024
		case "HighFree":
			ret.HighFree = t * 1024
		case "LowTotal":
			ret.LowTotal = t * 1024
		case "LowFree":
			ret.LowFree = t * 1024
		case "SwapTotal":
			ret.SwapTotal = t * 1024
		case "SwapFree":
			ret.SwapFree = t * 1024
		case "Mapped":
			ret.Mapped = t * 1024
		case "VmallocTotal":
			ret.VMallocTotal = t * 1024
		case "VmallocUsed":
			ret.VMallocUsed = t * 1024
		case "VmallocChunk":
			ret.VMallocChunk = t * 1024
		case "HugePages_Total":
			ret.HugePagesTotal = t
		case "HugePages_Free":
			ret.HugePagesFree = t
		case "Hugepagesize":
			ret.HugePageSize = t * 1024
		}
	}

	ret.Cached += ret.SReclaimable

	if !memavail {
		ret.Available = ret.Free + ret.Buffers + ret.Cached
	}
	ret.Used = ret.Total - ret.Free - ret.Buffers - ret.Cached
	ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0

	return ret, nil
}

func SwapMemory() (*SwapMemoryStat, error) {
	return SwapMemoryWithContext(context.Background())
}

func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
	sysinfo := &unix.Sysinfo_t{}

	if err := unix.Sysinfo(sysinfo); err != nil {
		return nil, err
	}
	ret := &SwapMemoryStat{
		Total: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit),
		Free:  uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit),
	}
	ret.Used = ret.Total - ret.Free
	//check Infinity
	if ret.Total != 0 {
		ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0
	} else {
		ret.UsedPercent = 0
	}
	filename := common.HostProc("vmstat")
	lines, _ := common.ReadLines(filename)
	for _, l := range lines {
		fields := strings.Fields(l)
		if len(fields) < 2 {
			continue
		}
		switch fields[0] {
		case "pswpin":
			value, err := strconv.ParseUint(fields[1], 10, 64)
			if err != nil {
				continue
			}
			ret.Sin = value * 4 * 1024
		case "pswpout":
			value, err := strconv.ParseUint(fields[1], 10, 64)
			if err != nil {
				continue
			}
			ret.Sout = value * 4 * 1024
		}
	}
	return ret, nil
}
<commit_msg>AvailableMemory is't calculated automatically under kenel 3.14 so it is needed to calcuate manually<commit_after>// +build linux

package mem

import (
	"context"
	"math"
	"os"
	"strconv"
	"strings"

	"github.com/shirou/gopsutil/internal/common"
	"golang.org/x/sys/unix"
)

func VirtualMemory() (*VirtualMemoryStat, error) {
	return VirtualMemoryWithContext(context.Background())
}

func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
	filename := common.HostProc("meminfo")
	lines, _ := common.ReadLines(filename)
	// flag if MemAvailable is in /proc/meminfo (kernel 3.14+)
	memavail := false

	ret := &VirtualMemoryStat{}
	for _, line := range lines {
		fields := strings.Split(line, ":")
		if len(fields) != 2 {
			continue
		}
		key := strings.TrimSpace(fields[0])
		value := strings.TrimSpace(fields[1])
		value = strings.Replace(value, " kB", "", -1)

		t, err := strconv.ParseUint(value, 10, 64)
		if err != nil {
			return ret, err
		}
		switch key {
		case "MemTotal":
			ret.Total = t * 1024
		case "MemFree":
			ret.Free = t * 1024
		case "MemAvailable":
			memavail = true
			ret.Available = t * 1024
		case "Buffers":
			ret.Buffers = t * 1024
		case "Cached":
			ret.Cached = t * 1024
		case "Active":
			ret.Active = t * 1024
		case "Inactive":
			ret.Inactive = t * 1024
		case "Writeback":
			ret.Writeback = t * 1024
		case "WritebackTmp":
			ret.WritebackTmp = t * 1024
		case "Dirty":
			ret.Dirty = t * 1024
		case "Shmem":
			ret.Shared = t * 1024
		case "Slab":
			ret.Slab = t * 1024
		case "SReclaimable":
			ret.SReclaimable = t * 1024
		case "PageTables":
			ret.PageTables = t * 1024
		case "SwapCached":
			ret.SwapCached = t * 1024
		case "CommitLimit":
			ret.CommitLimit = t * 1024
		case "Committed_AS":
			ret.CommittedAS = t * 1024
		case "HighTotal":
			ret.HighTotal = t * 1024
		case "HighFree":
			ret.HighFree = t * 1024
		case "LowTotal":
			ret.LowTotal = t * 1024
		case "LowFree":
			ret.LowFree = t * 1024
		case "SwapTotal":
			ret.SwapTotal = t * 1024
		case "SwapFree":
			ret.SwapFree = t * 1024
		case "Mapped":
			ret.Mapped = t * 1024
		case "VmallocTotal":
			ret.VMallocTotal = t * 1024
		case "VmallocUsed":
			ret.VMallocUsed = t * 1024
		case "VmallocChunk":
			ret.VMallocChunk = t * 1024
		case "HugePages_Total":
			ret.HugePagesTotal = t
		case "HugePages_Free":
			ret.HugePagesFree = t
		case "Hugepagesize":
			ret.HugePageSize = t * 1024
		}
	}

	ret.Cached += ret.SReclaimable

	if !memavail {
		ret.Available = calcuateAvailVmem(ret)
	}

	ret.Used = ret.Total - ret.Free - ret.Buffers - ret.Cached
	ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0

	return ret, nil
}

func SwapMemory() (*SwapMemoryStat, error) {
	return SwapMemoryWithContext(context.Background())
}

func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
	sysinfo := &unix.Sysinfo_t{}

	if err := unix.Sysinfo(sysinfo); err != nil {
		return nil, err
	}
	ret := &SwapMemoryStat{
		Total: uint64(sysinfo.Totalswap) * uint64(sysinfo.Unit),
		Free:  uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit),
	}
	ret.Used = ret.Total - ret.Free
	//check Infinity
	if ret.Total != 0 {
		ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0
	} else {
		ret.UsedPercent = 0
	}
	filename := common.HostProc("vmstat")
	lines, _ := common.ReadLines(filename)
	for _, l := range lines {
		fields := strings.Fields(l)
		if len(fields) < 2 {
			continue
		}
		switch fields[0] {
		case "pswpin":
			value, err := strconv.ParseUint(fields[1], 10, 64)
			if err != nil {
				continue
			}
			ret.Sin = value * 4 * 1024
		case "pswpout":
			value, err := strconv.ParseUint(fields[1], 10, 64)
			if err != nil {
				continue
			}
			ret.Sout = value * 4 * 1024
		}
	}
	return ret, nil
}

func calcuateAvailVmem(ret *VirtualMemoryStat) uint64 {
	var watermarkLow uint64
	fn := common.HostProc("zoneinfo")
	lines, _ := common.ReadLines(fn)
	pagesize := uint64(os.Getpagesize())
	watermarkLow = 0

	for _, line := range lines {
		fields := strings.Fields(line)

		if strings.HasPrefix(fields[0], "low") {
			lowValue, err := strconv.ParseUint(fields[1], 10, 64)

			if err != nil {
				lowValue = 0
			}

			watermarkLow += lowValue
		}
	}

	watermarkLow *= pagesize

	availMemory := ret.Free - watermarkLow
	pageCache := ret.Active + ret.Inactive
	pageCache -= uint64(math.Min(float64(pageCache/2), float64(watermarkLow)))
	availMemory += pageCache
	availMemory += ret.SReclaimable - uint64(math.Min(float64(ret.SReclaimable/2.0), float64(watermarkLow)))

	if availMemory < 0 {
		availMemory = 0
	}

	return availMemory
}
<|endoftext|>


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

// Package provision provides interfaces that need to be satisfied in order to
// implement a new provisioner on tsuru.
package provision

import (
	"fmt"
	"github.com/tsuru/tsuru/action"
	"github.com/tsuru/tsuru/app/bind"
	"io"
)

type Status string

func (s Status) String() string {
	return string(s)
}

const (
	// building - is while the unit is being provisioned,
	// it occurs during a deploy.
	StatusBuilding = Status("building")
	// error - when an error occurs caused by the application code.
	StatusError = Status("error")
	// is when an error occurs caused by tsuru internal problems.
	StatusDown = Status("down")
	// is when the app process is up but it is not bound to the
	// right host ("0.0.0.0") and right port ($PORT).
	// If your process is a worker its state will be unreachable.
	StatusUnreachable = Status("unreachable")
	// Is when the app process is up and bound to the right
	// host ("0.0.0.0") and right port ($PORT).
	StatusStarted = Status("started")
	// stopped - is when the Docker container is stopped
	StatusStopped = Status("stopped")
)

// Unit represents a provision unit. Can be a machine, container or anything
// IP-addressable.
type Unit struct {
	Name    string
	AppName string
	Type    string
	Ip      string
	Status  Status
}

//  GetIp returns the Unit.IP.
func (u *Unit) GetIp() string {
	return u.Ip
}

// Available returns true if the unit status is started or unreachable.
func (u *Unit) Available() bool {
	return u.Status == StatusStarted || u.Status == StatusUnreachable
}

// Named is something that has a name, providing the GetName method.
type Named interface {
	GetName() string
}

// App represents a tsuru app.
//
// It contains only relevant information for provisioning.
type App interface {
	Named
	// Log should be used to log messages in the app.
	Log(message, source, unit string) error

	// GetPlatform returns the platform (type) of the app. It is equivalent
	// to the Unit `Type` field.
	GetPlatform() string

	// GetDeploy returns the deploys that an app has.
	GetDeploys() uint

	Units() []Unit

	// Run executes the command in app units. Commands executed with this
	// method should have access to environment variables defined in the
	// app.
	Run(cmd string, w io.Writer, once bool) error

	Restart(io.Writer) error

	SerializeEnvVars() error

	Envs() map[string]bind.EnvVar

	// Ready marks the app as ready for deployment.
	Ready() error

	GetMemory() int
	GetSwap() int
	GetUpdatePlatform() bool
}

type CNameManager interface {
	SetCName(app App, cname string) error
	UnsetCName(app App, cname string) error
}

// ArchiveDeployer is a provisioner that can deploy archives.
type ArchiveDeployer interface {
	ArchiveDeploy(app App, archiveURL string, w io.Writer) error
}

// GitDeployer is a provisioner that can deploy the application from a Git
// repository.
type GitDeployer interface {
	GitDeploy(app App, version string, w io.Writer) error
}

// Provisioner is the basic interface of this package.
//
// Any tsuru provisioner must implement this interface in order to provision
// tsuru apps.
type Provisioner interface {
	// Provision is called when tsuru is creating the app.
	Provision(App) error

	// Destroy is called when tsuru is destroying the app.
	Destroy(App) error

	// AddUnits adds units to an app. The first parameter is the app, the
	// second is the number of units to be added.
	//
	// It returns a slice containing all added units
	AddUnits(App, uint) ([]Unit, error)

	// RemoveUnits "undoes" AddUnits, removing the given number of units
	// from the app.
	RemoveUnits(App, uint) error

	// RemoveUnit removes a unit from the app. It receives the unit to be
	// removed.
	RemoveUnit(Unit) error

	// ExecuteCommand runs a command in all units of the app.
	ExecuteCommand(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	// ExecuteCommandOnce runs a command in one unit of the app.
	ExecuteCommandOnce(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	Restart(App) error
	Stop(App) error

	// Start start the app units.
	Start(App) error

	// Addr returns the address for an app.
	//
	// tsuru will use this method to get the IP (although it might not be
	// an actual IP, collector calls it "IP") of the app from the
	// provisioner.
	Addr(App) (string, error)

	// Swap change the router between two apps.
	Swap(App, App) error

	// Units returns information about units by App.
	Units(App) []Unit
}

// CustomizedDeployPipelineProvisioner is a provisioner with a customized
// deploy pipeline.
type CustomizedDeployPipelineProvisioner interface {
	DeployPipeline() *action.Pipeline
}

// ExtensibleProvisioner is a provisioner where administrators can manage
// platforms (automatically adding, removing and updating platforms).
type ExtensibleProvisioner interface {
	PlatformAdd(name string, args map[string]string, w io.Writer) error
	PlatformUpdate(name string, args map[string]string, w io.Writer) error
}

var provisioners = make(map[string]Provisioner)

// Register registers a new provisioner in the Provisioner registry.
func Register(name string, p Provisioner) {
	provisioners[name] = p
}

// Get gets the named provisioner from the registry.
func Get(name string) (Provisioner, error) {
	p, ok := provisioners[name]
	if !ok {
		return nil, fmt.Errorf("Unknown provisioner: %q.", name)
	}
	return p, nil
}

// Registry returns the list of registered provisioners.
func Registry() []Provisioner {
	registry := make([]Provisioner, 0, len(provisioners))
	for _, p := range provisioners {
		registry = append(registry, p)
	}
	return registry
}

type Error struct {
	Reason string
	Err    error
}

func (e *Error) Error() string {
	var err string
	if e.Err != nil {
		err = e.Err.Error() + ": " + e.Reason
	} else {
		err = e.Reason
	}
	return err
}
<commit_msg>provision: improve docs and fix some golint warnings<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package provision provides interfaces that need to be satisfied in order to
// implement a new provisioner on tsuru.
package provision

import (
	"fmt"
	"github.com/tsuru/tsuru/action"
	"github.com/tsuru/tsuru/app/bind"
	"io"
)

// Status represents the status of a unit in tsuru.
type Status string

func (s Status) String() string {
	return string(s)
}

const (
	// StatusBuilding is the status for units being provisined by the
	// provisioner, like in the deployment.
	StatusBuilding = Status("building")

	// StatusError is the status for units that failed to start, because of
	// an application error.
	StatusError = Status("error")

	// StatusDown is the status for units that failed to start, because of
	// some internal error on tsuru.
	StatusDown = Status("down")

	// StatusUnreachable is the case where the process is up and running,
	// but the unit is not reachable. Probably because it's not bound to
	// the right host ("0.0.0.0") and/or right port ($PORT).
	StatusUnreachable = Status("unreachable")

	// StatusStarted is for cases where the unit is up and running, and
	// bound to the proper status.
	StatusStarted = Status("started")

	// StatusStopped is for cases where the unit has been stopped.
	StatusStopped = Status("stopped")
)

// Unit represents a provision unit. Can be a machine, container or anything
// IP-addressable.
type Unit struct {
	Name    string
	AppName string
	Type    string
	Ip      string
	Status  Status
}

// GetIp returns the Unit.IP.
func (u *Unit) GetIp() string {
	return u.Ip
}

// Available returns true if the unit status is started or unreachable.
func (u *Unit) Available() bool {
	return u.Status == StatusStarted || u.Status == StatusUnreachable
}

// Named is something that has a name, providing the GetName method.
type Named interface {
	GetName() string
}

// App represents a tsuru app.
//
// It contains only relevant information for provisioning.
type App interface {
	Named
	// Log should be used to log messages in the app.
	Log(message, source, unit string) error

	// GetPlatform returns the platform (type) of the app. It is equivalent
	// to the Unit `Type` field.
	GetPlatform() string

	// GetDeploy returns the deploys that an app has.
	GetDeploys() uint

	Units() []Unit

	// Run executes the command in app units. Commands executed with this
	// method should have access to environment variables defined in the
	// app.
	Run(cmd string, w io.Writer, once bool) error

	Restart(io.Writer) error

	SerializeEnvVars() error

	Envs() map[string]bind.EnvVar

	// Ready marks the app as ready for deployment.
	Ready() error

	GetMemory() int
	GetSwap() int
	GetUpdatePlatform() bool
}

// CNameManager represents a provisioner that supports cname on applications.
type CNameManager interface {
	SetCName(app App, cname string) error
	UnsetCName(app App, cname string) error
}

// ArchiveDeployer is a provisioner that can deploy archives.
type ArchiveDeployer interface {
	ArchiveDeploy(app App, archiveURL string, w io.Writer) error
}

// GitDeployer is a provisioner that can deploy the application from a Git
// repository.
type GitDeployer interface {
	GitDeploy(app App, version string, w io.Writer) error
}

// Provisioner is the basic interface of this package.
//
// Any tsuru provisioner must implement this interface in order to provision
// tsuru apps.
type Provisioner interface {
	// Provision is called when tsuru is creating the app.
	Provision(App) error

	// Destroy is called when tsuru is destroying the app.
	Destroy(App) error

	// AddUnits adds units to an app. The first parameter is the app, the
	// second is the number of units to be added.
	//
	// It returns a slice containing all added units
	AddUnits(App, uint) ([]Unit, error)

	// RemoveUnits "undoes" AddUnits, removing the given number of units
	// from the app.
	RemoveUnits(App, uint) error

	// RemoveUnit removes a unit from the app. It receives the unit to be
	// removed.
	RemoveUnit(Unit) error

	// ExecuteCommand runs a command in all units of the app.
	ExecuteCommand(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	// ExecuteCommandOnce runs a command in one unit of the app.
	ExecuteCommandOnce(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	Restart(App) error
	Stop(App) error

	// Start start the app units.
	Start(App) error

	// Addr returns the address for an app.
	//
	// tsuru will use this method to get the IP (although it might not be
	// an actual IP, collector calls it "IP") of the app from the
	// provisioner.
	Addr(App) (string, error)

	// Swap change the router between two apps.
	Swap(App, App) error

	// Units returns information about units by App.
	Units(App) []Unit
}

// CustomizedDeployPipelineProvisioner is a provisioner with a customized
// deploy pipeline.
type CustomizedDeployPipelineProvisioner interface {
	DeployPipeline() *action.Pipeline
}

// ExtensibleProvisioner is a provisioner where administrators can manage
// platforms (automatically adding, removing and updating platforms).
type ExtensibleProvisioner interface {
	PlatformAdd(name string, args map[string]string, w io.Writer) error
	PlatformUpdate(name string, args map[string]string, w io.Writer) error
}

var provisioners = make(map[string]Provisioner)

// Register registers a new provisioner in the Provisioner registry.
func Register(name string, p Provisioner) {
	provisioners[name] = p
}

// Get gets the named provisioner from the registry.
func Get(name string) (Provisioner, error) {
	p, ok := provisioners[name]
	if !ok {
		return nil, fmt.Errorf("unknown provisioner: %q", name)
	}
	return p, nil
}

// Registry returns the list of registered provisioners.
func Registry() []Provisioner {
	registry := make([]Provisioner, 0, len(provisioners))
	for _, p := range provisioners {
		registry = append(registry, p)
	}
	return registry
}

// Error represents a provisioning error. It encapsulates further errors.
type Error struct {
	Reason string
	Err    error
}

// Error is the string representation of a provisioning error.
func (e *Error) Error() string {
	var err string
	if e.Err != nil {
		err = e.Err.Error() + ": " + e.Reason
	} else {
		err = e.Reason
	}
	return err
}
<|endoftext|>


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

// Acknowledgement API support - Fetch, Create, Update, Delete*, and Search
// See: https://login.circonus.com/resources/api/calls/acknowledgement
// *  : delete (cancel) by updating with AcknowledgedUntil set to 0

package api

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"

	"github.com/circonus-labs/circonus-gometrics/api/config"
)

// Acknowledgement defines a acknowledgement. See https://login.circonus.com/resources/api/calls/acknowledgement for more information.
type Acknowledgement struct {
	CID               string      `json:"_cid,omitempty"`
	AcknowledgedBy    string      `json:"_acknowledged_by,omitempty"`
	AcknowledgedOn    uint        `json:"_acknowledged_on,omitempty"`
	Active            bool        `json:"_active,omitempty"`
	LastModified      uint        `json:"_last_modified,omitempty"`
	LastModifiedBy    string      `json:"_last_modified_by,omitempty"`
	AcknowledgedUntil interface{} `json:"acknowledged_until,omitempty"` // NOTE always received as uint; can be set using string or uint
	AlertCID          string      `json:"alert,omitempty"`
	Notes             string      `json:"notes,omitempty"`
}

// NewAcknowledgement returns new Acknowledgement (with defaults, if applicable).
func NewAcknowledgement() *Acknowledgement {
	return &Acknowledgement{}
}

// FetchAcknowledgement retrieves acknowledgement with passed cid.
func (a *API) FetchAcknowledgement(cid CIDType) (*Acknowledgement, error) {
	if cid == nil || *cid == "" {
		return nil, fmt.Errorf("Invalid acknowledgement CID [none]")
	}

	acknowledgementCID := string(*cid)

	matched, err := regexp.MatchString(config.AcknowledgementCIDRegex, acknowledgementCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid acknowledgement CID [%s]", acknowledgementCID)
	}

	result, err := a.Get(acknowledgementCID)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] acknowledgement fetch, received JSON: %s", string(result))
	}

	acknowledgement := &Acknowledgement{}
	if err := json.Unmarshal(result, acknowledgement); err != nil {
		return nil, err
	}

	return acknowledgement, nil
}

// FetchAcknowledgements retrieves all acknowledgements available to the API Token.
func (a *API) FetchAcknowledgements() (*[]Acknowledgement, error) {
	result, err := a.Get(config.AcknowledgementPrefix)
	if err != nil {
		return nil, err
	}

	var acknowledgements []Acknowledgement
	if err := json.Unmarshal(result, &acknowledgements); err != nil {
		return nil, err
	}

	return &acknowledgements, nil
}

// UpdateAcknowledgement updates passed acknowledgement.
func (a *API) UpdateAcknowledgement(cfg *Acknowledgement) (*Acknowledgement, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid acknowledgement config [nil]")
	}

	acknowledgementCID := string(cfg.CID)

	matched, err := regexp.MatchString(config.AcknowledgementCIDRegex, acknowledgementCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid acknowledgement CID [%s]", acknowledgementCID)
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] acknowledgement update, sending JSON: %s", string(jsonCfg))
	}

	result, err := a.Put(acknowledgementCID, jsonCfg)
	if err != nil {
		return nil, err
	}

	acknowledgement := &Acknowledgement{}
	if err := json.Unmarshal(result, acknowledgement); err != nil {
		return nil, err
	}

	return acknowledgement, nil
}

// CreateAcknowledgement creates a new acknowledgement.
func (a *API) CreateAcknowledgement(cfg *Acknowledgement) (*Acknowledgement, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid acknowledgement config [nil]")
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	result, err := a.Post(config.AcknowledgementPrefix, jsonCfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] acknowledgement create, sending JSON: %s", string(jsonCfg))
	}

	acknowledgement := &Acknowledgement{}
	if err := json.Unmarshal(result, acknowledgement); err != nil {
		return nil, err
	}

	return acknowledgement, nil
}

// SearchAcknowledgements returns acknowledgements matching
// the specified search query and/or filter. If nil is passed for
// both parameters all acknowledgements will be returned.
func (a *API) SearchAcknowledgements(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]Acknowledgement, error) {
	q := url.Values{}

	if searchCriteria != nil && *searchCriteria != "" {
		q.Set("search", string(*searchCriteria))
	}

	if filterCriteria != nil && len(*filterCriteria) > 0 {
		for filter, criteria := range *filterCriteria {
			for _, val := range criteria {
				q.Add(filter, val)
			}
		}
	}

	if q.Encode() == "" {
		return a.FetchAcknowledgements()
	}

	reqURL := url.URL{
		Path:     config.AcknowledgementPrefix,
		RawQuery: q.Encode(),
	}

	result, err := a.Get(reqURL.String())
	if err != nil {
		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
	}

	var acknowledgements []Acknowledgement
	if err := json.Unmarshal(result, &acknowledgements); err != nil {
		return nil, err
	}

	return &acknowledgements, nil
}
<commit_msg>upd: document struct member types as received from api<commit_after>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Acknowledgement API support - Fetch, Create, Update, Delete*, and Search
// See: https://login.circonus.com/resources/api/calls/acknowledgement
// *  : delete (cancel) by updating with AcknowledgedUntil set to 0

package api

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"

	"github.com/circonus-labs/circonus-gometrics/api/config"
)

// Acknowledgement defines a acknowledgement. See https://login.circonus.com/resources/api/calls/acknowledgement for more information.
type Acknowledgement struct {
	CID               string      `json:"_cid,omitempty"`               // string
	AcknowledgedBy    string      `json:"_acknowledged_by,omitempty"`   // string
	AcknowledgedOn    uint        `json:"_acknowledged_on,omitempty"`   // uint
	Active            bool        `json:"_active,omitempty"`            // bool
	LastModified      uint        `json:"_last_modified,omitempty"`     // uint
	LastModifiedBy    string      `json:"_last_modified_by,omitempty"`  // string
	AcknowledgedUntil interface{} `json:"acknowledged_until,omitempty"` // NOTE received as uint; can be set using string or uint
	AlertCID          string      `json:"alert,omitempty"`              // string
	Notes             string      `json:"notes,omitempty"`              // string
}

// NewAcknowledgement returns new Acknowledgement (with defaults, if applicable).
func NewAcknowledgement() *Acknowledgement {
	return &Acknowledgement{}
}

// FetchAcknowledgement retrieves acknowledgement with passed cid.
func (a *API) FetchAcknowledgement(cid CIDType) (*Acknowledgement, error) {
	if cid == nil || *cid == "" {
		return nil, fmt.Errorf("Invalid acknowledgement CID [none]")
	}

	acknowledgementCID := string(*cid)

	matched, err := regexp.MatchString(config.AcknowledgementCIDRegex, acknowledgementCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid acknowledgement CID [%s]", acknowledgementCID)
	}

	result, err := a.Get(acknowledgementCID)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] acknowledgement fetch, received JSON: %s", string(result))
	}

	acknowledgement := &Acknowledgement{}
	if err := json.Unmarshal(result, acknowledgement); err != nil {
		return nil, err
	}

	return acknowledgement, nil
}

// FetchAcknowledgements retrieves all acknowledgements available to the API Token.
func (a *API) FetchAcknowledgements() (*[]Acknowledgement, error) {
	result, err := a.Get(config.AcknowledgementPrefix)
	if err != nil {
		return nil, err
	}

	var acknowledgements []Acknowledgement
	if err := json.Unmarshal(result, &acknowledgements); err != nil {
		return nil, err
	}

	return &acknowledgements, nil
}

// UpdateAcknowledgement updates passed acknowledgement.
func (a *API) UpdateAcknowledgement(cfg *Acknowledgement) (*Acknowledgement, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid acknowledgement config [nil]")
	}

	acknowledgementCID := string(cfg.CID)

	matched, err := regexp.MatchString(config.AcknowledgementCIDRegex, acknowledgementCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid acknowledgement CID [%s]", acknowledgementCID)
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] acknowledgement update, sending JSON: %s", string(jsonCfg))
	}

	result, err := a.Put(acknowledgementCID, jsonCfg)
	if err != nil {
		return nil, err
	}

	acknowledgement := &Acknowledgement{}
	if err := json.Unmarshal(result, acknowledgement); err != nil {
		return nil, err
	}

	return acknowledgement, nil
}

// CreateAcknowledgement creates a new acknowledgement.
func (a *API) CreateAcknowledgement(cfg *Acknowledgement) (*Acknowledgement, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid acknowledgement config [nil]")
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	result, err := a.Post(config.AcknowledgementPrefix, jsonCfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] acknowledgement create, sending JSON: %s", string(jsonCfg))
	}

	acknowledgement := &Acknowledgement{}
	if err := json.Unmarshal(result, acknowledgement); err != nil {
		return nil, err
	}

	return acknowledgement, nil
}

// SearchAcknowledgements returns acknowledgements matching
// the specified search query and/or filter. If nil is passed for
// both parameters all acknowledgements will be returned.
func (a *API) SearchAcknowledgements(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]Acknowledgement, error) {
	q := url.Values{}

	if searchCriteria != nil && *searchCriteria != "" {
		q.Set("search", string(*searchCriteria))
	}

	if filterCriteria != nil && len(*filterCriteria) > 0 {
		for filter, criteria := range *filterCriteria {
			for _, val := range criteria {
				q.Add(filter, val)
			}
		}
	}

	if q.Encode() == "" {
		return a.FetchAcknowledgements()
	}

	reqURL := url.URL{
		Path:     config.AcknowledgementPrefix,
		RawQuery: q.Encode(),
	}

	result, err := a.Get(reqURL.String())
	if err != nil {
		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
	}

	var acknowledgements []Acknowledgement
	if err := json.Unmarshal(result, &acknowledgements); err != nil {
		return nil, err
	}

	return &acknowledgements, nil
}
<|endoftext|>


<commit_before>package wdte_test

import (
	"strings"
	"testing"

	"github.com/DeedleFake/wdte"
)

func TestModule(t *testing.T) {
	const test = `
'test' => test;

fib n => switch n {
	0 => 0;
	default => + (fib (- n 1)) (fib (- n 2));
};

main => print (fib 5);
`

	m, err := wdte.Parse(strings.NewReader(test), nil)
	if err != nil {
		t.Fatal(err)
	}

	m.Funcs["+"] = wdte.GoFunc(func(scope []wdte.Func, args ...wdte.Func) wdte.Func {
		a1 := args[0].Call(scope)
		a2 := args[1].Call(scope)

		return a1.(wdte.Number) + a2.(wdte.Number)
	})

	m.Funcs["-"] = wdte.GoFunc(func(scope []wdte.Func, args ...wdte.Func) wdte.Func {
		a1 := args[0].Call(scope)
		a2 := args[1].Call(scope)

		return a1.(wdte.Number) - a2.(wdte.Number)
	})

	m.Funcs["print"] = wdte.GoFunc(func(scope []wdte.Func, args ...wdte.Func) wdte.Func {
		a := args[0].Call(scope)
		t.Logf("%v", a)
		return a
	})

	t.Log("Imports:")
	for i := range m.Imports {
		t.Logf("\t%q", i)
	}

	t.Log("Funcs:")
	for f := range m.Funcs {
		t.Logf("\t%q", f)
	}

	m.Funcs["main"].Call(nil)
}
<commit_msg>wdte: Fix syntax error in test.<commit_after>package wdte_test

import (
	"strings"
	"testing"

	"github.com/DeedleFake/wdte"
)

func TestModule(t *testing.T) {
	const test = `
'test' => test;

fib n => switch n {
	0 => 0;
	default => + (fib (- n 1;);) (fib (- n 2;););
};

main => print (fib 5;);
`

	m, err := wdte.Parse(strings.NewReader(test), nil)
	if err != nil {
		t.Fatal(err)
	}

	m.Funcs["+"] = wdte.GoFunc(func(scope []wdte.Func, args ...wdte.Func) wdte.Func {
		a1 := args[0].Call(scope)
		a2 := args[1].Call(scope)

		return a1.(wdte.Number) + a2.(wdte.Number)
	})

	m.Funcs["-"] = wdte.GoFunc(func(scope []wdte.Func, args ...wdte.Func) wdte.Func {
		a1 := args[0].Call(scope)
		a2 := args[1].Call(scope)

		return a1.(wdte.Number) - a2.(wdte.Number)
	})

	m.Funcs["print"] = wdte.GoFunc(func(scope []wdte.Func, args ...wdte.Func) wdte.Func {
		a := args[0].Call(scope)
		t.Logf("%v", a)
		return a
	})

	t.Log("Imports:")
	for i := range m.Imports {
		t.Logf("\t%q", i)
	}

	t.Log("Funcs:")
	for f := range m.Funcs {
		t.Logf("\t%q", f)
	}

	m.Funcs["main"].Call(nil)
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

type SymbolClass int

// SymbolClass enumerates the classes of symbols found in the program text.
const (
	VarSymbol    SymbolClass = iota // Variables
	CaprefSymbol                    // Capture group references
	DefSymbol                       // Definitions

	endSymbol
)

// symbol is an entry in the symbol table within a certain scope.
type symbol struct {
	name    string      // Symbol name
	class   SymbolClass // Type
	binding interface{} // Binding to storage allocated
	loc     *position   // Source file position
	addr    int         // Address offset in another structure
	typ     Type        // Type of this symbol
}

// scope maps an object name to a list of symbols with that name.  Objects with
// the same SymbolClass cannot exist at the same scope.  Objects with different
// SymbolClass may exist at the same scope.
type scope map[string][]*symbol

// SymbolTable is a stack of scopes.  As new scopes are entered, they are
// pushed onto the end of the stack.  As scopes are exited, they are removed
// from the stack.  References to each scope are held by the AST nodes that are
// contained within them, for speed of access when performing a lookup, and
// preventing garbage collection until the AST is no longer referenced.
type SymbolTable []*scope

func (s *SymbolTable) EnterScope(sc *scope) *scope {
	if sc == nil {
		sc = &scope{}
	}
	*s = append(*s, sc)
	return sc
}

func (s *SymbolTable) ExitScope() {
	if len(*s) > 1 {
		*s = (*s)[:len(*s)-1]
	}
}

func (s *SymbolTable) CurrentScope() *scope {
	return (*s)[len(*s)-1]
}

func (s *SymbolTable) Lookup(name string, class SymbolClass) (*symbol, bool) {
	for i := len(*s) - 1; i >= 0; i-- {
		if r, ok := (*(*s)[i])[name]; ok && r[class] != nil {
			return r[class], ok
		}
	}
	return nil, false
}

func (s *SymbolTable) Add(name string, class SymbolClass, loc *position) (sym *symbol) {
	sym = &symbol{name, class, nil, loc, 0, Int}
	cs := s.CurrentScope()
	if _, ok := (*cs)[name]; !ok {
		(*cs)[name] = make([]*symbol, endSymbol)
	}
	(*cs)[name][class] = sym
	return sym
}
<commit_msg>Comments<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

type SymbolClass int

// SymbolClass enumerates the classes of symbols found in the program text.
const (
	VarSymbol    SymbolClass = iota // Variables
	CaprefSymbol                    // Capture group references
	DefSymbol                       // Definitions

	endSymbol
)

// symbol is an entry in the symbol table within a certain scope.
type symbol struct {
	name    string      // Symbol name
	class   SymbolClass // Symbol class, of program object
	binding interface{} // Binding to storage allocated in runtime
	loc     *position   // Source file position of definition
	addr    int         // Address offset in another structure
	typ     Type        // Symbol type
}

// scope maps an object name to a list of symbols with that name.  Objects with
// the same SymbolClass cannot exist at the same scope.  Objects with different
// SymbolClass may exist at the same scope.
type scope map[string][]*symbol

// SymbolTable is a stack of scopes.  As new scopes are entered, they are
// pushed onto the end of the stack.  As scopes are exited, they are removed
// from the stack.  References to each scope are held by the AST nodes that are
// contained within them, for speed of access when performing a lookup, and
// preventing garbage collection until the AST is no longer referenced.
type SymbolTable []*scope

func (s *SymbolTable) EnterScope(sc *scope) *scope {
	if sc == nil {
		sc = &scope{}
	}
	*s = append(*s, sc)
	return sc
}

func (s *SymbolTable) ExitScope() {
	if len(*s) > 1 {
		*s = (*s)[:len(*s)-1]
	}
}

func (s *SymbolTable) CurrentScope() *scope {
	return (*s)[len(*s)-1]
}

func (s *SymbolTable) Lookup(name string, class SymbolClass) (*symbol, bool) {
	for i := len(*s) - 1; i >= 0; i-- {
		if r, ok := (*(*s)[i])[name]; ok && r[class] != nil {
			return r[class], ok
		}
	}
	return nil, false
}

func (s *SymbolTable) Add(name string, class SymbolClass, loc *position) (sym *symbol) {
	sym = &symbol{name, class, nil, loc, 0, Int}
	cs := s.CurrentScope()
	if _, ok := (*cs)[name]; !ok {
		(*cs)[name] = make([]*symbol, endSymbol)
	}
	(*cs)[name][class] = sym
	return sym
}
<|endoftext|>


<commit_before>package algoholic

import (
	"math/rand"
	"sort"
)

type RandomOrderSlice []int

func (slice RandomOrderSlice) Len() int {
	return len(slice)
}

func (slice RandomOrderSlice) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func (slice RandomOrderSlice) Less(i, j int) bool {
	return rand.Float64() < 0.5
}

// In-place Fisher-Yates shuffle.
// O(n) assuming an O(1) PRNG.
func ShuffleFisherYates(ns []int) {
	for i := len(ns) - 1; i >= 1; i-- {
		j := rand.Intn(i + 1)
		ns[i], ns[j] = ns[j], ns[i]
	}
}

// In-place shuffle using a sort based on a random number.
// O(n log n) assuming an O(1) PRNG.
func ShuffleRandomSort(ns []int) {
	sort.Sort(RandomOrderSlice(ns))
}
<commit_msg>Seed the PRNG correctly.<commit_after>package algoholic

import (
	"math/rand"
	"sort"
	"time"
)

type RandomOrderSlice []int

func init() {
	rand.Seed(time.Now().UnixNano())
}

func (slice RandomOrderSlice) Len() int {
	return len(slice)
}

func (slice RandomOrderSlice) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func (slice RandomOrderSlice) Less(i, j int) bool {
	return rand.Float64() < 0.5
}

// In-place Fisher-Yates shuffle.
// O(n) assuming an O(1) PRNG.
func ShuffleFisherYates(ns []int) {
	for i := len(ns) - 1; i >= 1; i-- {
		j := rand.Intn(i + 1)
		ns[i], ns[j] = ns[j], ns[i]
	}
}

// In-place shuffle using a sort based on a random number.
// O(n log n) assuming an O(1) PRNG.
func ShuffleRandomSort(ns []int) {
	sort.Sort(RandomOrderSlice(ns))
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"

	"github.com/hoffie/larasync/repository"
	"github.com/hoffie/larasync/repository/nib"
)

// Uploader returns the uploader for the given client in the passed
// repository.
func (c *Client) Uploader(r *repository.ClientRepository) *Uploader {
	return &Uploader{
		client: c,
		r:      r,
	}
}

// Uploader handles uploads from server to client
type Uploader struct {
	client *Client
	r      *repository.ClientRepository
}

// PushAll ensures that the remote state is synced with the local state.
func (ul *Uploader) PushAll() error {
	r := ul.r
	transaction, err := r.CurrentTransaction()
	if err != nil {
		return err
	}
	err = ul.uploadNIBs()
	if err != nil {
		return err
	}
	return ul.saveLastUploadedTransaction(transaction)
}

// PushDelta pushes all nibs from the stored local transaction id.
func (ul *Uploader) PushDelta() error {
	r := ul.r
	s, err := r.StateConfig()
	if err != nil {
		return err
	}

	defaultServer := s.DefaultServer
	if defaultServer.LocalTransactionID != 0 {
		err = ul.pushFromTransactionID(defaultServer.LocalTransactionID)
	} else {
		err = ul.PushAll()
	}
	return err
}

// PushFromTransactionID pushes all NIBs which have been entered after
// the given local transaction ID.
func (ul *Uploader) pushFromTransactionID(transactionID int64) error {
	r := ul.r
	transactions, err := r.TransactionsFrom(transactionID)
	if err != nil {
		return fmt.Errorf("unable to get transactions (%s)", err)
	}

	var lastTransaction *repository.Transaction
	for _, transaction := range transactions {
		err = ul.uploadTransaction(transaction)
		if err != nil {
			return err
		}
		lastTransaction = transaction
	}

	if lastTransaction != nil {
		err = ul.saveLastUploadedTransaction(lastTransaction)
		if err != nil {
			return err
		}
	}

	return nil
}

// saveLastUploadedTransaction takes the given transaction and configures it to the
// state config to store it as the last transaction.
func (ul *Uploader) saveLastUploadedTransaction(transaction *repository.Transaction) error {
	r := ul.r
	s, err := r.StateConfig()
	if err != nil {
		return nil
	}
	s.DefaultServer.LocalTransactionID = transaction.ID
	err = s.Save()
	if err != nil {
		return err
	}
	return nil
}

// uploadTransaction uploads all nibs in the added transaction.
func (ul *Uploader) uploadTransaction(transaction *repository.Transaction) error {
	r := ul.r
	for _, nibID := range transaction.NIBIDs {
		nib, err := r.GetNIB(nibID)
		if err != nil {
			return fmt.Errorf("could not load NIB with id %s (%s)", nibID, err)
		}
		err = ul.uploadNIB(nib)
		if err != nil {
			return err
		}
	}
	return nil
}

// uploadNIBs uploads all local NIBs and content of the NIBs to
// the server.
func (ul *Uploader) uploadNIBs() error {
	r := ul.r
	nibs, err := r.GetAllNibs()
	if err != nil {
		return fmt.Errorf("unable to get NIB list (%s)", err)
	}

	for n := range nibs {
		err = ul.uploadNIB(n)
		if err != nil {
			return err
		}
	}

	return nil
}

// uploadNIB uploads a single passed NIB to the remote server.
func (ul *Uploader) uploadNIB(n *nib.NIB) error {
	r := ul.r
	client := ul.client
	nibReader, err := r.GetNIBReader(n.ID)
	if err != nil {
		return err
	}
	defer nibReader.Close()

	err = client.PutNIB(n.ID, nibReader)
	var objectIDs []string
	if err == nil {
		return nil
	}
	if !repository.IsNIBContentMissing(err) {
		return fmt.Errorf("uploading nib %s failed (%s)", n.ID, err)
	}
	nibContentMissing := err.(*repository.ErrNIBContentMissing)
	objectIDs = nibContentMissing.MissingContentIDs()
	for _, objectID := range objectIDs {
		err = ul.uploadObject(objectID)
		if err != nil {
			return err
		}
	}
	nibReader, err = r.GetNIBReader(n.ID)
	if err != nil {
		return err
	}
	defer nibReader.Close()

	err = client.PutNIB(n.ID, nibReader)
	if err != nil {
		return fmt.Errorf("uploading nib %s failed (%s)", n.ID, err)
	}

	return nil
}

func (ul *Uploader) uploadObject(objectID string) error {
	r := ul.r
	client := ul.client

	object, err := r.GetObjectData(objectID)
	if err != nil {
		return fmt.Errorf("unable to load object %s (%s)\n", objectID, err)
	}
	defer object.Close()
	err = client.PutObject(objectID, object)
	if err != nil {
		return fmt.Errorf("uploading object %s failed (%s)", objectID, err)
	}
	return nil
}
<commit_msg>api/client: Added basic logging for the uploader handler.<commit_after>package client

import (
	"fmt"

	"github.com/hoffie/larasync/repository"
	"github.com/hoffie/larasync/repository/nib"
)

// Uploader returns the uploader for the given client in the passed
// repository.
func (c *Client) Uploader(r *repository.ClientRepository) *Uploader {
	return &Uploader{
		client: c,
		r:      r,
	}
}

// Uploader handles uploads from server to client
type Uploader struct {
	client *Client
	r      *repository.ClientRepository
}

// PushAll ensures that the remote state is synced with the local state.
func (ul *Uploader) PushAll() error {
	r := ul.r
	transaction, err := r.CurrentTransaction()
	if err != nil {
		return err
	}
	err = ul.uploadNIBs()
	if err != nil {
		return err
	}
	return ul.saveLastUploadedTransaction(transaction)
}

// PushDelta pushes all nibs from the stored local transaction id.
func (ul *Uploader) PushDelta() error {
	r := ul.r
	s, err := r.StateConfig()
	if err != nil {
		return err
	}

	defaultServer := s.DefaultServer
	if defaultServer.LocalTransactionID != 0 {
		err = ul.pushFromTransactionID(defaultServer.LocalTransactionID)
	} else {
		err = ul.PushAll()
	}
	return err
}

// PushFromTransactionID pushes all NIBs which have been entered after
// the given local transaction ID.
func (ul *Uploader) pushFromTransactionID(transactionID int64) error {
	r := ul.r
	transactions, err := r.TransactionsFrom(transactionID)
	if err != nil {
		return fmt.Errorf("unable to get transactions (%s)", err)
	}

	var lastTransaction *repository.Transaction
	for _, transaction := range transactions {
		err = ul.uploadTransaction(transaction)
		if err != nil {
			return err
		}
		lastTransaction = transaction
	}

	if lastTransaction != nil {
		err = ul.saveLastUploadedTransaction(lastTransaction)
		if err != nil {
			return err
		}
	}

	return nil
}

// saveLastUploadedTransaction takes the given transaction and configures it to the
// state config to store it as the last transaction.
func (ul *Uploader) saveLastUploadedTransaction(transaction *repository.Transaction) error {
	r := ul.r
	s, err := r.StateConfig()
	if err != nil {
		return nil
	}
	s.DefaultServer.LocalTransactionID = transaction.ID
	err = s.Save()
	if err != nil {
		return err
	}
	return nil
}

// uploadTransaction uploads all nibs in the added transaction.
func (ul *Uploader) uploadTransaction(transaction *repository.Transaction) error {
	r := ul.r
	for _, nibID := range transaction.NIBIDs {
		nib, err := r.GetNIB(nibID)
		if err != nil {
			return fmt.Errorf("could not load NIB with id %s (%s)", nibID, err)
		}
		err = ul.uploadNIB(nib)
		if err != nil {
			return err
		}
	}
	return nil
}

// uploadNIBs uploads all local NIBs and content of the NIBs to
// the server.
func (ul *Uploader) uploadNIBs() error {
	r := ul.r
	nibs, err := r.GetAllNibs()
	if err != nil {
		return fmt.Errorf("unable to get NIB list (%s)", err)
	}

	for n := range nibs {
		err = ul.uploadNIB(n)
		if err != nil {
			return err
		}
	}

	return nil
}

// uploadNIB uploads a single passed NIB to the remote server.
func (ul *Uploader) uploadNIB(n *nib.NIB) error {
	r := ul.r
	client := ul.client
    Log.Debug(fmt.Sprintf("Uploading nib with ID %s", n.ID))
	nibReader, err := r.GetNIBReader(n.ID)
	if err != nil {
		return err
	}
	defer nibReader.Close()

	err = client.PutNIB(n.ID, nibReader)
	var objectIDs []string
	if err == nil {
		return nil
	}
	if !repository.IsNIBContentMissing(err) {
		return fmt.Errorf("uploading nib %s failed (%s)", n.ID, err)
	}
	nibContentMissing := err.(*repository.ErrNIBContentMissing)
	objectIDs = nibContentMissing.MissingContentIDs()
	for _, objectID := range objectIDs {
		err = ul.uploadObject(objectID)
		if err != nil {
			return err
		}
	}
	nibReader, err = r.GetNIBReader(n.ID)
	if err != nil {
		return err
	}
	defer nibReader.Close()

	err = client.PutNIB(n.ID, nibReader)
	if err != nil {
		return fmt.Errorf("uploading nib %s failed (%s)", n.ID, err)
	}

	return nil
}

func (ul *Uploader) uploadObject(objectID string) error {
	r := ul.r
	client := ul.client

    Log.Debug(fmt.Sprintf("Uploading object with ID %s", objectID))
	object, err := r.GetObjectData(objectID)
	if err != nil {
		return fmt.Errorf("unable to load object %s (%s)\n", objectID, err)
	}
	defer object.Close()
	err = client.PutObject(objectID, object)
	if err != nil {
		return fmt.Errorf("uploading object %s failed (%s)", objectID, err)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package mempool

import (
	"errors"
	"fmt"

	"github.com/decred/dcrd/blockchain/v3"
	"github.com/decred/dcrd/wire"
)

// RuleError identifies a rule violation.  It is used to indicate that
// processing of a transaction failed due to one of the many validation
// rules.  The caller can use type assertions to determine if a failure was
// specifically due to a rule violation and use the Err field to access the
// underlying error, which will be either a TxRuleError or a
// blockchain.RuleError.
type RuleError struct {
	Err error
}

// Error satisfies the error interface and prints human-readable errors.
func (e RuleError) Error() string {
	if e.Err == nil {
		return "<nil>"
	}
	return e.Err.Error()
}

// ErrorCode identifies the kind of error.
type ErrorCode int

const (
	ErrOther ErrorCode = iota
	ErrInvalid
	ErrOrphanPolicyViolation
	ErrMempoolDoubleSpend
	ErrAlreadyVoted
	ErrDuplicate
	ErrCoinbase
	ErrExpired
	ErrNonStandard
	ErrDustOutput
	ErrInsufficientFee
	ErrTooManyVotes
	ErrDuplicateRevocation
	ErrOldVote
	ErrAlreadyExists
	ErrSeqLockUnmet
	ErrInsufficientPriority
	ErrFeeTooHigh
	ErrOrphan
)

// TxRuleError identifies a rule violation.  It is used to indicate that
// processing of a transaction failed due to one of the many validation
// rules.  The caller can use type assertions to determine if a failure was
// specifically due to a rule violation and access the ErrorCode field to
// ascertain the specific reason for the rule violation.
type TxRuleError struct {
	// RejectCode is the corresponding rejection code to send when
	// reporting the error via 'reject' wire protocol messages.
	//
	// Deprecated: This will be removed in the next major version. Use
	// ErrorCode instead.
	RejectCode wire.RejectCode

	// ErrorCode is the mempool package error code ID.
	ErrorCode ErrorCode

	// Description is an additional human readable description of the
	// error.
	Description string
}

// Error satisfies the error interface and prints human-readable errors.
func (e TxRuleError) Error() string {
	return e.Description
}

// txRuleError creates an underlying TxRuleError with the given a set of
// arguments and returns a RuleError that encapsulates it.
func txRuleError(c wire.RejectCode, code ErrorCode, desc string) RuleError {
	return RuleError{
		Err: TxRuleError{RejectCode: c, ErrorCode: code, Description: desc},
	}
}

// chainRuleError returns a RuleError that encapsulates the given
// blockchain.RuleError.
func chainRuleError(chainErr blockchain.RuleError) RuleError {
	return RuleError{
		Err: chainErr,
	}
}

// IsErrorCode returns true if the passed error encodes a TxRuleError with the
// given ErrorCode, either directly or embedded in an outer RuleError.
func IsErrorCode(err error, code ErrorCode) bool {
	// Unwrap RuleError if necessary.
	var rerr RuleError
	if errors.As(err, &rerr) {
		err = rerr.Err
	}

	var trerr TxRuleError
	return errors.As(err, &trerr) &&
		trerr.ErrorCode == code
}

// wrapTxRuleError returns a new RuleError with an underlying TxRuleError,
// replacing the description with the provided one while retaining both the
// error code and rejection code from the original error if they can be
// determined.
func wrapTxRuleError(rejectCode wire.RejectCode, errorCode ErrorCode, desc string, err error) error {
	// Unwrap the underlying error if err is a RuleError
	var rerr RuleError
	if errors.As(err, &rerr) {
		err = rerr.Err
	}

	// Override the passed rejectCode and errorCode with the ones from the
	// error, if it is a TxRuleError
	var txerr TxRuleError
	if errors.As(err, &txerr) {
		rejectCode = txerr.RejectCode
		errorCode = txerr.ErrorCode
	}

	// Fill a default error description if empty.
	if desc == "" {
		desc = fmt.Sprintf("rejected: %v", err)
	}

	return txRuleError(rejectCode, errorCode, desc)
}

// extractRejectCode attempts to return a relevant reject code for a given error
// by examining the error for known types.  It will return true if a code
// was successfully extracted.
func extractRejectCode(err error) (wire.RejectCode, bool) {
	// Pull the underlying error out of a RuleError.
	var rerr RuleError
	if errors.As(err, &rerr) {
		err = rerr.Err
	}

	var berr blockchain.RuleError
	var terr TxRuleError
	switch {
	case errors.As(err, &berr):
		// Convert the chain error to a reject code.
		var code wire.RejectCode
		switch berr.ErrorCode {
		// Rejected due to duplicate.
		case blockchain.ErrDuplicateBlock:
			code = wire.RejectDuplicate

		// Rejected due to obsolete version.
		case blockchain.ErrBlockVersionTooOld:
			code = wire.RejectObsolete

		// Rejected due to checkpoint.
		case blockchain.ErrCheckpointTimeTooOld:
			fallthrough
		case blockchain.ErrDifficultyTooLow:
			fallthrough
		case blockchain.ErrBadCheckpoint:
			fallthrough
		case blockchain.ErrForkTooOld:
			code = wire.RejectCheckpoint

		// Everything else is due to the block or transaction being invalid.
		default:
			code = wire.RejectInvalid
		}

		return code, true

	case errors.As(err, &terr):
		return terr.RejectCode, true

	case err == nil:
		return wire.RejectInvalid, false
	}

	return wire.RejectInvalid, false
}

// ErrToRejectErr examines the underlying type of the error and returns a reject
// code and string appropriate to be sent in a wire.MsgReject message.
//
// Deprecated: This will be removed in the next major version of this package.
func ErrToRejectErr(err error) (wire.RejectCode, string) {
	// Return the reject code along with the error text if it can be
	// extracted from the error.
	rejectCode, found := extractRejectCode(err)
	if found {
		return rejectCode, err.Error()
	}

	// Return a generic rejected string if there is no error.  This really
	// should not happen unless the code elsewhere is not setting an error
	// as it should be, but it's best to be safe and simply return a generic
	// string rather than allowing the following code that dereferences the
	// err to panic.
	if err == nil {
		return wire.RejectInvalid, "rejected"
	}

	// When the underlying error is not one of the above cases, just return
	// wire.RejectInvalid with a generic rejected string plus the error
	// text.
	return wire.RejectInvalid, "rejected: " + err.Error()
}
<commit_msg>mempool: Remove deprecated ErrToRejectErr func.<commit_after>// Copyright (c) 2014-2016 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package mempool

import (
	"errors"
	"fmt"

	"github.com/decred/dcrd/blockchain/v3"
	"github.com/decred/dcrd/wire"
)

// RuleError identifies a rule violation.  It is used to indicate that
// processing of a transaction failed due to one of the many validation
// rules.  The caller can use type assertions to determine if a failure was
// specifically due to a rule violation and use the Err field to access the
// underlying error, which will be either a TxRuleError or a
// blockchain.RuleError.
type RuleError struct {
	Err error
}

// Error satisfies the error interface and prints human-readable errors.
func (e RuleError) Error() string {
	if e.Err == nil {
		return "<nil>"
	}
	return e.Err.Error()
}

// ErrorCode identifies the kind of error.
type ErrorCode int

const (
	ErrOther ErrorCode = iota
	ErrInvalid
	ErrOrphanPolicyViolation
	ErrMempoolDoubleSpend
	ErrAlreadyVoted
	ErrDuplicate
	ErrCoinbase
	ErrExpired
	ErrNonStandard
	ErrDustOutput
	ErrInsufficientFee
	ErrTooManyVotes
	ErrDuplicateRevocation
	ErrOldVote
	ErrAlreadyExists
	ErrSeqLockUnmet
	ErrInsufficientPriority
	ErrFeeTooHigh
	ErrOrphan
)

// TxRuleError identifies a rule violation.  It is used to indicate that
// processing of a transaction failed due to one of the many validation
// rules.  The caller can use type assertions to determine if a failure was
// specifically due to a rule violation and access the ErrorCode field to
// ascertain the specific reason for the rule violation.
type TxRuleError struct {
	// RejectCode is the corresponding rejection code to send when
	// reporting the error via 'reject' wire protocol messages.
	//
	// Deprecated: This will be removed in the next major version. Use
	// ErrorCode instead.
	RejectCode wire.RejectCode

	// ErrorCode is the mempool package error code ID.
	ErrorCode ErrorCode

	// Description is an additional human readable description of the
	// error.
	Description string
}

// Error satisfies the error interface and prints human-readable errors.
func (e TxRuleError) Error() string {
	return e.Description
}

// txRuleError creates an underlying TxRuleError with the given a set of
// arguments and returns a RuleError that encapsulates it.
func txRuleError(c wire.RejectCode, code ErrorCode, desc string) RuleError {
	return RuleError{
		Err: TxRuleError{RejectCode: c, ErrorCode: code, Description: desc},
	}
}

// chainRuleError returns a RuleError that encapsulates the given
// blockchain.RuleError.
func chainRuleError(chainErr blockchain.RuleError) RuleError {
	return RuleError{
		Err: chainErr,
	}
}

// IsErrorCode returns true if the passed error encodes a TxRuleError with the
// given ErrorCode, either directly or embedded in an outer RuleError.
func IsErrorCode(err error, code ErrorCode) bool {
	// Unwrap RuleError if necessary.
	var rerr RuleError
	if errors.As(err, &rerr) {
		err = rerr.Err
	}

	var trerr TxRuleError
	return errors.As(err, &trerr) &&
		trerr.ErrorCode == code
}

// wrapTxRuleError returns a new RuleError with an underlying TxRuleError,
// replacing the description with the provided one while retaining both the
// error code and rejection code from the original error if they can be
// determined.
func wrapTxRuleError(rejectCode wire.RejectCode, errorCode ErrorCode, desc string, err error) error {
	// Unwrap the underlying error if err is a RuleError
	var rerr RuleError
	if errors.As(err, &rerr) {
		err = rerr.Err
	}

	// Override the passed rejectCode and errorCode with the ones from the
	// error, if it is a TxRuleError
	var txerr TxRuleError
	if errors.As(err, &txerr) {
		rejectCode = txerr.RejectCode
		errorCode = txerr.ErrorCode
	}

	// Fill a default error description if empty.
	if desc == "" {
		desc = fmt.Sprintf("rejected: %v", err)
	}

	return txRuleError(rejectCode, errorCode, desc)
}
<|endoftext|>


<commit_before>package mesh

import (
	"errors"
	"sync"
	"time"

	"github.com/keybase/saltpack/basic"

	"github.com/jinzhu/copier"
)

var (
	ErrNotKnown               = errors.New("not found")
	ErrCannotPutLocalPeerInfo = errors.New("cannot put local peer info")
)

var (
	peerInfoExpireAfter = time.Hour * 1
)

type Registry interface {
	GetLocalPeerInfo() *SecretPeerInfo
	PutLocalPeerInfo(*SecretPeerInfo) error // TODO Deprecate
	GetPeerInfo(peerID string) (*PeerInfo, error)
	GetAllPeerInfo() ([]*PeerInfo, error)
	PutPeerInfo(*PeerInfo) error
	// Resolve(ctx context.Context, peerID string) (string, error)
	// Discover(ctx context.Context, peerID, protocol string) ([]net.Address, error)
	LoadOrCreateLocalPeerInfo(path string) (*SecretPeerInfo, error)
	CreateNewPeer() (*SecretPeerInfo, error)
	LoadSecretPeerInfo(path string) (*SecretPeerInfo, error)
	StoreSecretPeerInfo(pi *SecretPeerInfo, path string) error
	GetKeyring() *basic.Keyring
}

// NewRegisty creates a new registry with an empty keyring
// TODO Rename to AddressBook
func NewRegisty() Registry {
	reg := &registry{
		peers:   map[string]*PeerInfo{},
		keyring: basic.NewKeyring(),
	}

	return reg
}

type registry struct {
	sync.RWMutex
	peers     map[string]*PeerInfo
	localPeer *SecretPeerInfo
	keyring   *basic.Keyring
}

func (reg *registry) GetKeyring() *basic.Keyring {
	return reg.keyring
}

func (reg *registry) PutPeerInfo(peerInfo *PeerInfo) error {
	reg.Lock()
	defer reg.Unlock()
	if reg.localPeer.ID == peerInfo.ID {
		return ErrCannotPutLocalPeerInfo
	}

	if peerInfo.ID == "" {
		return nil
	}

	reg.peers[peerInfo.ID] = peerInfo
	return nil
}

func (reg *registry) GetLocalPeerInfo() *SecretPeerInfo {
	return reg.localPeer
}

func (reg *registry) PutLocalPeerInfo(peerInfo *SecretPeerInfo) error {
	reg.Lock()
	defer reg.Unlock()
	reg.localPeer = peerInfo
	return nil
}

func (reg *registry) GetPeerInfo(peerID string) (*PeerInfo, error) {
	reg.RLock()
	defer reg.RUnlock()
	peerInfo, ok := reg.peers[peerID]
	if !ok {
		return nil, ErrNotKnown
	}

	newPeerInfo := &PeerInfo{}
	copier.Copy(newPeerInfo, peerInfo)
	return newPeerInfo, nil
}

func (reg *registry) GetAllPeerInfo() ([]*PeerInfo, error) {
	reg.RLock()
	defer reg.RUnlock()
	newPeerInfos := []*PeerInfo{}
	for _, peerInfo := range reg.peers {
		newPeerInfo := &PeerInfo{}
		copier.Copy(newPeerInfo, peerInfo)
		newPeerInfos = append(newPeerInfos, newPeerInfo)
	}
	return newPeerInfos, nil
}
<commit_msg>Add updated at when modifying the peerinfo in the registry<commit_after>package mesh

import (
	"errors"
	"sync"
	"time"

	"github.com/keybase/saltpack/basic"

	"github.com/jinzhu/copier"
)

var (
	ErrNotKnown               = errors.New("not found")
	ErrCannotPutLocalPeerInfo = errors.New("cannot put local peer info")
)

var (
	peerInfoExpireAfter = time.Hour * 1
)

type Registry interface {
	GetLocalPeerInfo() *SecretPeerInfo
	PutLocalPeerInfo(*SecretPeerInfo) error // TODO Deprecate
	GetPeerInfo(peerID string) (*PeerInfo, error)
	GetAllPeerInfo() ([]*PeerInfo, error)
	PutPeerInfo(*PeerInfo) error
	// Resolve(ctx context.Context, peerID string) (string, error)
	// Discover(ctx context.Context, peerID, protocol string) ([]net.Address, error)
	LoadOrCreateLocalPeerInfo(path string) (*SecretPeerInfo, error)
	CreateNewPeer() (*SecretPeerInfo, error)
	LoadSecretPeerInfo(path string) (*SecretPeerInfo, error)
	StoreSecretPeerInfo(pi *SecretPeerInfo, path string) error
	GetKeyring() *basic.Keyring
}

// NewRegisty creates a new registry with an empty keyring
// TODO Rename to AddressBook
func NewRegisty() Registry {
	reg := &registry{
		peers:   map[string]*PeerInfo{},
		keyring: basic.NewKeyring(),
	}

	return reg
}

type registry struct {
	sync.RWMutex
	peers     map[string]*PeerInfo
	localPeer *SecretPeerInfo
	keyring   *basic.Keyring
}

func (reg *registry) GetKeyring() *basic.Keyring {
	return reg.keyring
}

func (reg *registry) PutPeerInfo(peerInfo *PeerInfo) error {
	reg.Lock()
	defer reg.Unlock()
	if reg.localPeer.ID == peerInfo.ID {
		return ErrCannotPutLocalPeerInfo
	}

	if peerInfo.ID == "" {
		return nil
	}

	peerInfo.UpdatedAt = time.Now()

	reg.peers[peerInfo.ID] = peerInfo
	return nil
}

func (reg *registry) GetLocalPeerInfo() *SecretPeerInfo {
	return reg.localPeer
}

func (reg *registry) PutLocalPeerInfo(peerInfo *SecretPeerInfo) error {
	reg.Lock()
	defer reg.Unlock()
	peerInfo.UpdatedAt = time.Now()
	reg.localPeer = peerInfo
	return nil
}

func (reg *registry) GetPeerInfo(peerID string) (*PeerInfo, error) {
	reg.RLock()
	defer reg.RUnlock()
	peerInfo, ok := reg.peers[peerID]
	if !ok {
		return nil, ErrNotKnown
	}

	newPeerInfo := &PeerInfo{}
	copier.Copy(newPeerInfo, peerInfo)
	return newPeerInfo, nil
}

func (reg *registry) GetAllPeerInfo() ([]*PeerInfo, error) {
	reg.RLock()
	defer reg.RUnlock()
	newPeerInfos := []*PeerInfo{}
	for _, peerInfo := range reg.peers {
		newPeerInfo := &PeerInfo{}
		copier.Copy(newPeerInfo, peerInfo)
		newPeerInfos = append(newPeerInfos, newPeerInfo)
	}
	return newPeerInfos, nil
}
<|endoftext|>


<commit_before>package mesos

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"

	"github.com/Dataman-Cloud/swan/agent/janitor/upstream"
	"github.com/Dataman-Cloud/swan/agent/resolver"
	"github.com/Dataman-Cloud/swan/mole"
	"github.com/Dataman-Cloud/swan/types"
)

func (s *Scheduler) ClusterAgents() map[string]*mole.ClusterAgent {
	return s.clusterMaster.Agents()
}

func (s *Scheduler) ClusterAgent(id string) *mole.ClusterAgent {
	return s.clusterMaster.Agent(id)
}

type broadcastRes struct {
	sync.Mutex
	m [][2]string // agent-id, errmsg
}

func (br *broadcastRes) Error() string {
	bs, _ := json.Marshal(br.m)
	return string(bs)
}

// sync calling agent Api to update agent's proxy & dns records on task healthy events.
func (s *Scheduler) broadcastEventRecords(ev *types.TaskEvent) error {
	var (
		res = &broadcastRes{m: make([][2]string, 0, 0)}
	)

	var wg sync.WaitGroup
	for _, agent := range s.ClusterAgents() {
		wg.Add(1)
		go func(agent *mole.ClusterAgent) {
			var err error

			defer func() {
				if err != nil {
					res.Lock()
					res.m = append(res.m, [2]string{agent.ID(), err.Error()})
					res.Unlock()
				}

				wg.Done()
			}()

			funcDoReq := func(req *http.Request) error {
				resp, err := agent.Client().Do(req)
				if err != nil {
					return err
				}
				defer resp.Body.Close()

				if code := resp.StatusCode; code >= 400 {
					bs, _ := ioutil.ReadAll(resp.Body)
					return fmt.Errorf("%d - %s", code, string(bs))
				}

				return nil
			}

			reqProxy, err := s.buildAgentProxyReq(ev)
			if err != nil {
				return
			}
			err = funcDoReq(reqProxy)
			if err != nil {
				return
			}

			reqDNS, err := s.buildAgentDNSReq(ev)
			if err != nil {
				return
			}
			err = funcDoReq(reqDNS)
			if err != nil {
				return
			}

		}(agent)
	}

	wg.Wait()

	if len(res.m) == 0 {
		return nil
	}

	return res
}

func (s *Scheduler) buildAgentDNSRecord(ev *types.TaskEvent) *resolver.Record {
	return &resolver.Record{
		ID:          ev.TaskID,
		Parent:      ev.AppID,
		IP:          ev.IP,
		Port:        fmt.Sprintf("%d", ev.Port),
		Weight:      ev.Weight,
		ProxyRecord: false,
	}
}

func (s *Scheduler) buildAgentDNSReq(ev *types.TaskEvent) (*http.Request, error) {
	body := s.buildAgentDNSRecord(ev)

	bs, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}

	switch typ := ev.Type; typ {
	case types.EventTypeTaskHealthy:
		return http.NewRequest("PUT", "http://xxx/dns/records", bytes.NewBuffer(bs))
	case types.EventTypeTaskUnhealthy:
		return http.NewRequest("DELETE", "http://xxx/dns/records", bytes.NewBuffer(bs))
	case types.EventTypeTaskWeightChange:
		return nil, nil
	default:
		return nil, errors.New("unknown event type: " + typ)
	}
}

func (s *Scheduler) buildAgentProxyRecord(ev *types.TaskEvent) *upstream.BackendCombined {
	return &upstream.BackendCombined{
		Upstream: &upstream.Upstream{
			Name:   ev.AppID,
			Alias:  ev.AppAlias,
			Listen: ev.AppListen,
			Sticky: ev.AppSticky,
		},
		Backend: &upstream.Backend{
			ID:        ev.TaskID,
			IP:        ev.IP,
			Port:      ev.Port,
			Scheme:    "",
			Version:   ev.VersionID,
			Weight:    ev.Weight,
			CleanName: "",
		},
	}
}

func (s *Scheduler) buildAgentProxyReq(ev *types.TaskEvent) (*http.Request, error) {
	body := s.buildAgentProxyRecord(ev)

	bs, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}

	switch typ := ev.Type; typ {
	case types.EventTypeTaskHealthy, types.EventTypeTaskWeightChange:
		return http.NewRequest("PUT", "http://xxx/proxy/upstreams", bytes.NewBuffer(bs))
	case types.EventTypeTaskUnhealthy:
		return http.NewRequest("DELETE", "http://xxx/proxy/upstreams", bytes.NewBuffer(bs))
	default:
		return nil, errors.New("unknown event type: " + typ)
	}
}
<commit_msg>prevent fd leak<commit_after>package mesos

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"

	"github.com/Dataman-Cloud/swan/agent/janitor/upstream"
	"github.com/Dataman-Cloud/swan/agent/resolver"
	"github.com/Dataman-Cloud/swan/mole"
	"github.com/Dataman-Cloud/swan/types"
)

func (s *Scheduler) ClusterAgents() map[string]*mole.ClusterAgent {
	return s.clusterMaster.Agents()
}

func (s *Scheduler) ClusterAgent(id string) *mole.ClusterAgent {
	return s.clusterMaster.Agent(id)
}

type broadcastRes struct {
	sync.Mutex
	m [][2]string // agent-id, errmsg
}

func (br *broadcastRes) Error() string {
	bs, _ := json.Marshal(br.m)
	return string(bs)
}

// sync calling agent Api to update agent's proxy & dns records on task healthy events.
func (s *Scheduler) broadcastEventRecords(ev *types.TaskEvent) error {
	var (
		res = &broadcastRes{m: make([][2]string, 0, 0)}
	)

	var wg sync.WaitGroup
	for _, agent := range s.ClusterAgents() {
		wg.Add(1)
		go func(agent *mole.ClusterAgent) {
			var err error

			defer func() {
				if err != nil {
					res.Lock()
					res.m = append(res.m, [2]string{agent.ID(), err.Error()})
					res.Unlock()
				}

				wg.Done()
			}()

			funcDoReq := func(req *http.Request) error {
				resp, err := agent.Client().Do(req)
				if err != nil {
					return err
				}
				defer resp.Body.Close()

				if code := resp.StatusCode; code >= 400 {
					bs, _ := ioutil.ReadAll(resp.Body)
					return fmt.Errorf("%d - %s", code, string(bs))
				}

				return nil
			}

			reqProxy, err := s.buildAgentProxyReq(ev)
			if err != nil {
				return
			}
			reqProxy.Close = true
			reqProxy.Header.Set("Connection", "close")
			reqProxy.Host = agent.ID()
			err = funcDoReq(reqProxy)
			if err != nil {
				return
			}

			reqDNS, err := s.buildAgentDNSReq(ev)
			if err != nil {
				return
			}
			reqDNS.Close = true
			reqDNS.Header.Set("Connection", "close")
			reqDNS.Host = agent.ID()
			err = funcDoReq(reqDNS)
			if err != nil {
				return
			}

		}(agent)
	}

	wg.Wait()

	if len(res.m) == 0 {
		return nil
	}

	return res
}

func (s *Scheduler) buildAgentDNSRecord(ev *types.TaskEvent) *resolver.Record {
	return &resolver.Record{
		ID:          ev.TaskID,
		Parent:      ev.AppID,
		IP:          ev.IP,
		Port:        fmt.Sprintf("%d", ev.Port),
		Weight:      ev.Weight,
		ProxyRecord: false,
	}
}

func (s *Scheduler) buildAgentDNSReq(ev *types.TaskEvent) (*http.Request, error) {
	body := s.buildAgentDNSRecord(ev)

	bs, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}

	switch typ := ev.Type; typ {
	case types.EventTypeTaskHealthy:
		return http.NewRequest("PUT", "http://xxx/dns/records", bytes.NewBuffer(bs))
	case types.EventTypeTaskUnhealthy:
		return http.NewRequest("DELETE", "http://xxx/dns/records", bytes.NewBuffer(bs))
	case types.EventTypeTaskWeightChange:
		return nil, nil
	default:
		return nil, errors.New("unknown event type: " + typ)
	}
}

func (s *Scheduler) buildAgentProxyRecord(ev *types.TaskEvent) *upstream.BackendCombined {
	return &upstream.BackendCombined{
		Upstream: &upstream.Upstream{
			Name:   ev.AppID,
			Alias:  ev.AppAlias,
			Listen: ev.AppListen,
			Sticky: ev.AppSticky,
		},
		Backend: &upstream.Backend{
			ID:        ev.TaskID,
			IP:        ev.IP,
			Port:      ev.Port,
			Scheme:    "",
			Version:   ev.VersionID,
			Weight:    ev.Weight,
			CleanName: "",
		},
	}
}

func (s *Scheduler) buildAgentProxyReq(ev *types.TaskEvent) (*http.Request, error) {
	body := s.buildAgentProxyRecord(ev)

	bs, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}

	switch typ := ev.Type; typ {
	case types.EventTypeTaskHealthy, types.EventTypeTaskWeightChange:
		return http.NewRequest("PUT", "http://xxx/proxy/upstreams", bytes.NewBuffer(bs))
	case types.EventTypeTaskUnhealthy:
		return http.NewRequest("DELETE", "http://xxx/proxy/upstreams", bytes.NewBuffer(bs))
	default:
		return nil, errors.New("unknown event type: " + typ)
	}
}
<|endoftext|>