<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 contiv

import (
	"context"
	"github.com/contiv/vpp/plugins/contiv/containeridx"
	"github.com/contiv/vpp/plugins/contiv/model/cni"
	"github.com/contiv/vpp/plugins/kvdbproxy"
	"github.com/golang/protobuf/proto"
	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/logging/logroot"
	"github.com/ligato/vpp-agent/clientv1/defaultplugins"
	"github.com/ligato/vpp-agent/clientv1/linux"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/aclplugin/model/acl"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/bfd"
	vpp_intf "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/interfaces"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/model/l2"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/model/l3"
	linux_intf "github.com/ligato/vpp-agent/plugins/linuxplugin/model/interfaces"
	"github.com/onsi/gomega"
	"net"
	"testing"
)

const (
	containerID = "sadfja813227wdhfjkh2319784dgh"
	podName     = "ubuntu"
)

var req = cni.CNIRequest{
	Version:          "0.2.3",
	InterfaceName:    "eth0",
	ContainerId:      containerID,
	NetworkNamespace: "/var/run/2345243",
	ExtraArguments:   "IgnoreUnknown=1;K8S_POD_NAMESPACE=default;K8S_POD_NAME=" + podName + ";K8S_POD_INFRA_CONTAINER_ID=7d673108b0ff9b2f59f977ca5f4cef347cb9ca66888614068882fbfaba4de752",
}

func TestVeth1NameFromRequest(t *testing.T) {
	gomega.RegisterTestingT(t)

	server := newRemoteCNIServer(logroot.StandardLogger(),
		func() linux.DataChangeDSL { return NewMockDataChangeDSL() },
		&kvdbproxy.Plugin{},
		nil,
		nil,
		nil)

	hostIfName := server.veth1HostIfNameFromRequest(&req)
	gomega.Expect(hostIfName).To(gomega.BeEquivalentTo("eth0"))
}

func TestAdd(t *testing.T) {
	gomega.RegisterTestingT(t)

	txns := &txnTracker{}
	configuredContainers := containeridx.NewConfigIndex(logroot.StandardLogger(), core.PluginName("Plugin-name"), "title")

	server := newRemoteCNIServer(logroot.StandardLogger(),
		txns.newTxn,
		kvdbproxy.NewKvdbsyncMock(),
		configuredContainers,
		nil,
		nil)
	server.hostCalls = &mockLinuxCalls{}

	reply, err := server.Add(context.Background(), &req)

	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

	gomega.Expect(len(txns.txns)).To(gomega.BeEquivalentTo(2))
	// TODO add asserts for txns

	res := configuredContainers.LookupPodName(podName)
	gomega.Expect(len(res)).To(gomega.BeEquivalentTo(1))
	gomega.Expect(res).To(gomega.ContainElement(containerID))

	// TODO clear txnTracker

	reply, err = server.Delete(context.Background(), &req)
	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

}

type txnTracker struct {
	txns []*MockDataChangeDSL
}

func (t *txnTracker) newTxn() linux.DataChangeDSL {
	txn := NewMockDataChangeDSL()
	t.txns = append(t.txns, txn)
	return txn
}

type MockDataChangeDSL struct {
	expectedPut    map[string]interface{}
	expectedDelete map[string]interface{}
	performedPut   map[string]proto.Message
	performedDel   []string
}

func NewMockDataChangeDSL() *MockDataChangeDSL {
	return &MockDataChangeDSL{expectedPut: map[string]interface{}{},
		expectedDelete: map[string]interface{}{},
		performedPut:   map[string]proto.Message{}}
}

type MockPutDSL struct {
	parent *MockDataChangeDSL
}

type MockDeleteDSL struct {
	parent *MockDataChangeDSL
}

// Put initiates a chained sequence of data change DSL statements declaring
// new or changing existing configurable objects.
func (dsl *MockDataChangeDSL) Put() linux.PutDSL {
	return &MockPutDSL{dsl}
}

// Delete initiates a chained sequence of data change DSL statements
// removing existing configurable objects.
func (dsl *MockDataChangeDSL) Delete() linux.DeleteDSL {
	return &MockDeleteDSL{dsl}
}

// Send propagates requested changes to the plugins.
func (dsl *MockDataChangeDSL) Send() defaultplugins.Reply {

	return &Reply{nil}
}

// Interface adds a request to create or update VPP network interface.
func (dsl *MockPutDSL) VppInterface(val *vpp_intf.Interfaces_Interface) linux.PutDSL {
	dsl.parent.performedPut[vpp_intf.InterfaceKey(val.Name)] = val
	return dsl
}

// BfdSession adds a request to create or update bidirectional forwarding
// detection session.
func (dsl *MockPutDSL) BfdSession(val *bfd.SingleHopBFD_Session) linux.PutDSL {
	dsl.parent.performedPut[bfd.SessionKey(val.Interface)] = val
	return dsl
}

// BfdAuthKeys adds a request to create or update bidirectional forwarding
// detection key.
func (dsl *MockPutDSL) BfdAuthKeys(val *bfd.SingleHopBFD_Key) linux.PutDSL {
	dsl.parent.performedPut[bfd.AuthKeysKey(string(val.Id))] = val
	return dsl
}

// BfdEchoFunction adds a request to create or update bidirectional forwarding
// detection echo function.
func (dsl *MockPutDSL) BfdEchoFunction(val *bfd.SingleHopBFD_EchoFunction) linux.PutDSL {
	dsl.parent.performedPut[bfd.EchoFunctionKey(val.EchoSourceInterface)] = val
	return dsl
}

// BD adds a request to create or update VPP Bridge Domain.
func (dsl *MockPutDSL) BD(val *l2.BridgeDomains_BridgeDomain) linux.PutDSL {
	dsl.parent.performedPut[l2.BridgeDomainKey(val.Name)] = val
	return dsl
}

// BDFIB adds a request to create or update VPP L2 Forwarding Information Base.
func (dsl *MockPutDSL) BDFIB(val *l2.FibTableEntries_FibTableEntry) linux.PutDSL {
	dsl.parent.performedPut[l2.FibKey(val.BridgeDomain, val.PhysAddress)] = val
	return dsl
}

// XConnect adds a request to create or update VPP Cross Connect.
func (dsl *MockPutDSL) XConnect(val *l2.XConnectPairs_XConnectPair) linux.PutDSL {
	dsl.parent.performedPut[l2.XConnectKey(val.ReceiveInterface)] = val
	return dsl
}

// StaticRoute adds a request to create or update VPP L3 Static Route.
func (dsl *MockPutDSL) StaticRoute(val *l3.StaticRoutes_Route) linux.PutDSL {
	_, dstAddr, _ := net.ParseCIDR(val.DstIpAddr)
	dsl.parent.performedPut[l3.RouteKey(val.VrfId, dstAddr, val.NextHopAddr)] = val
	return dsl
}

// ACL adds a request to create or update VPP Access Control List.
func (dsl *MockPutDSL) ACL(val *acl.AccessLists_Acl) linux.PutDSL {
	dsl.parent.performedPut[acl.Key(val.AclName)] = val
	return dsl
}

func (dsl *MockPutDSL) LinuxInterface(val *linux_intf.LinuxInterfaces_Interface) linux.PutDSL {
	return dsl
}

// Delete changes the DSL mode to allow removal of an existing configuration.
func (dsl *MockPutDSL) Delete() linux.DeleteDSL {
	return &MockDeleteDSL{dsl.parent}
}

// Send propagates requested changes to the plugins.
func (dsl *MockPutDSL) Send() defaultplugins.Reply {
	return dsl.parent.Send()
}

// Interface adds a request to delete an existing VPP network interface.
func (dsl *MockDeleteDSL) VppInterface(interfaceName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, vpp_intf.InterfaceKey(interfaceName))
	return dsl
}

// BfdSession adds a request to delete an existing bidirectional forwarding
// detection session.
func (dsl *MockDeleteDSL) BfdSession(bfdSessionIfaceName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, bfd.SessionKey(bfdSessionIfaceName))
	return dsl
}

// BfdAuthKeys adds a request to delete an existing bidirectional forwarding
// detection key.
func (dsl *MockDeleteDSL) BfdAuthKeys(bfdKeyName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, bfd.AuthKeysKey(bfdKeyName))
	return dsl
}

// BfdEchoFunction adds a request to delete an existing bidirectional forwarding
// detection echo function.
func (dsl *MockDeleteDSL) BfdEchoFunction(bfdEchoName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, bfd.EchoFunctionKey(bfdEchoName))
	return dsl
}

// BD adds a request to delete an existing VPP Bridge Domain.
func (dsl *MockDeleteDSL) BD(bdName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, l2.BridgeDomainKey(bdName))
	return dsl
}

// BDFIB adds a request to delete an existing VPP L2 Forwarding Information
// Base.
func (dsl *MockDeleteDSL) BDFIB(bdName string, mac string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, l2.FibKey(bdName, mac))
	return dsl
}

// XConnect adds a request to delete an existing VPP Cross Connect.
func (dsl *MockDeleteDSL) XConnect(rxIfName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, l2.XConnectKey(rxIfName))
	return dsl
}

// StaticRoute adds a request to delete an existing VPP L3 Static Route..
func (dsl *MockDeleteDSL) StaticRoute(vrf uint32, dstAddrInput *net.IPNet, nextHopAddr net.IP) linux.DeleteDSL {
	//_, dstAddr, _ := net.ParseCIDR(dstAddrInput)
	dsl.parent.performedDel = append(dsl.parent.performedDel, l3.RouteKey(vrf, dstAddrInput, nextHopAddr.String()))
	return dsl
}

// ACL adds a request to delete an existing VPP Access Control List.
func (dsl *MockDeleteDSL) ACL(aclName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, acl.Key(aclName))
	return dsl
}
func (dsl *MockDeleteDSL) LinuxInterface(ifname string) linux.DeleteDSL {
	return dsl
}

// Put changes the DSL mode to allow configuration editing.
func (dsl *MockDeleteDSL) Put() linux.PutDSL {
	return &MockPutDSL{dsl.parent}
}

// Send propagates requested changes to the plugins.
func (dsl *MockDeleteDSL) Send() defaultplugins.Reply {
	return dsl.parent.Send()
}

// Reply interface allows to wait for a reply to previously called Send() and
// extract the result from it (success/error).
type Reply struct {
	err error
}

// ReceiveReply waits for a reply to previously called Send() and returns
// the result (error or nil).
func (dsl Reply) ReceiveReply() error {
	return dsl.err
}
<commit_msg>fix tests<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 contiv

import (
	"context"
	"net"
	"testing"

	"github.com/contiv/vpp/plugins/contiv/containeridx"
	"github.com/contiv/vpp/plugins/contiv/model/cni"
	"github.com/contiv/vpp/plugins/kvdbproxy"
	"github.com/golang/protobuf/proto"
	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/logging/logroot"
	"github.com/ligato/vpp-agent/clientv1/defaultplugins"
	"github.com/ligato/vpp-agent/clientv1/linux"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/aclplugin/model/acl"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/bfd"
	vpp_intf "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/interfaces"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/model/l2"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l3plugin/model/l3"
	linux_intf "github.com/ligato/vpp-agent/plugins/linuxplugin/model/interfaces"
	"github.com/onsi/gomega"
)

const (
	containerID = "sadfja813227wdhfjkh2319784dgh"
	podName     = "ubuntu"
)

var req = cni.CNIRequest{
	Version:          "0.2.3",
	InterfaceName:    "eth0",
	ContainerId:      containerID,
	NetworkNamespace: "/var/run/2345243",
	ExtraArguments:   "IgnoreUnknown=1;K8S_POD_NAMESPACE=default;K8S_POD_NAME=" + podName + ";K8S_POD_INFRA_CONTAINER_ID=7d673108b0ff9b2f59f977ca5f4cef347cb9ca66888614068882fbfaba4de752",
}

func TestVeth1NameFromRequest(t *testing.T) {
	gomega.RegisterTestingT(t)

	server := newRemoteCNIServer(logroot.StandardLogger(),
		func() linux.DataChangeDSL { return NewMockDataChangeDSL() },
		&kvdbproxy.Plugin{},
		nil,
		nil,
		nil)

	hostIfName := server.veth1HostIfNameFromRequest(&req)
	gomega.Expect(hostIfName).To(gomega.BeEquivalentTo("eth0"))
}

func TestAdd(t *testing.T) {
	gomega.RegisterTestingT(t)

	txns := &txnTracker{}
	configuredContainers := containeridx.NewConfigIndex(logroot.StandardLogger(), core.PluginName("Plugin-name"), "title")

	server := newRemoteCNIServer(logroot.StandardLogger(),
		txns.newTxn,
		kvdbproxy.NewKvdbsyncMock(),
		configuredContainers,
		nil,
		nil)
	server.hostCalls = &mockLinuxCalls{}

	reply, err := server.Add(context.Background(), &req)

	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

	gomega.Expect(len(txns.txns)).To(gomega.BeEquivalentTo(3))
	// TODO add asserts for txns

	res := configuredContainers.LookupPodName(podName)
	gomega.Expect(len(res)).To(gomega.BeEquivalentTo(1))
	gomega.Expect(res).To(gomega.ContainElement(containerID))

	// TODO clear txnTracker

	reply, err = server.Delete(context.Background(), &req)
	gomega.Expect(err).To(gomega.BeNil())
	gomega.Expect(reply).NotTo(gomega.BeNil())

}

type txnTracker struct {
	txns []*MockDataChangeDSL
}

func (t *txnTracker) newTxn() linux.DataChangeDSL {
	txn := NewMockDataChangeDSL()
	t.txns = append(t.txns, txn)
	return txn
}

type MockDataChangeDSL struct {
	expectedPut    map[string]interface{}
	expectedDelete map[string]interface{}
	performedPut   map[string]proto.Message
	performedDel   []string
}

func NewMockDataChangeDSL() *MockDataChangeDSL {
	return &MockDataChangeDSL{expectedPut: map[string]interface{}{},
		expectedDelete: map[string]interface{}{},
		performedPut:   map[string]proto.Message{}}
}

type MockPutDSL struct {
	parent *MockDataChangeDSL
}

type MockDeleteDSL struct {
	parent *MockDataChangeDSL
}

// Put initiates a chained sequence of data change DSL statements declaring
// new or changing existing configurable objects.
func (dsl *MockDataChangeDSL) Put() linux.PutDSL {
	return &MockPutDSL{dsl}
}

// Delete initiates a chained sequence of data change DSL statements
// removing existing configurable objects.
func (dsl *MockDataChangeDSL) Delete() linux.DeleteDSL {
	return &MockDeleteDSL{dsl}
}

// Send propagates requested changes to the plugins.
func (dsl *MockDataChangeDSL) Send() defaultplugins.Reply {

	return &Reply{nil}
}

// Interface adds a request to create or update VPP network interface.
func (dsl *MockPutDSL) VppInterface(val *vpp_intf.Interfaces_Interface) linux.PutDSL {
	dsl.parent.performedPut[vpp_intf.InterfaceKey(val.Name)] = val
	return dsl
}

// BfdSession adds a request to create or update bidirectional forwarding
// detection session.
func (dsl *MockPutDSL) BfdSession(val *bfd.SingleHopBFD_Session) linux.PutDSL {
	dsl.parent.performedPut[bfd.SessionKey(val.Interface)] = val
	return dsl
}

// BfdAuthKeys adds a request to create or update bidirectional forwarding
// detection key.
func (dsl *MockPutDSL) BfdAuthKeys(val *bfd.SingleHopBFD_Key) linux.PutDSL {
	dsl.parent.performedPut[bfd.AuthKeysKey(string(val.Id))] = val
	return dsl
}

// BfdEchoFunction adds a request to create or update bidirectional forwarding
// detection echo function.
func (dsl *MockPutDSL) BfdEchoFunction(val *bfd.SingleHopBFD_EchoFunction) linux.PutDSL {
	dsl.parent.performedPut[bfd.EchoFunctionKey(val.EchoSourceInterface)] = val
	return dsl
}

// BD adds a request to create or update VPP Bridge Domain.
func (dsl *MockPutDSL) BD(val *l2.BridgeDomains_BridgeDomain) linux.PutDSL {
	dsl.parent.performedPut[l2.BridgeDomainKey(val.Name)] = val
	return dsl
}

// BDFIB adds a request to create or update VPP L2 Forwarding Information Base.
func (dsl *MockPutDSL) BDFIB(val *l2.FibTableEntries_FibTableEntry) linux.PutDSL {
	dsl.parent.performedPut[l2.FibKey(val.BridgeDomain, val.PhysAddress)] = val
	return dsl
}

// XConnect adds a request to create or update VPP Cross Connect.
func (dsl *MockPutDSL) XConnect(val *l2.XConnectPairs_XConnectPair) linux.PutDSL {
	dsl.parent.performedPut[l2.XConnectKey(val.ReceiveInterface)] = val
	return dsl
}

// StaticRoute adds a request to create or update VPP L3 Static Route.
func (dsl *MockPutDSL) StaticRoute(val *l3.StaticRoutes_Route) linux.PutDSL {
	_, dstAddr, _ := net.ParseCIDR(val.DstIpAddr)
	dsl.parent.performedPut[l3.RouteKey(val.VrfId, dstAddr, val.NextHopAddr)] = val
	return dsl
}

// ACL adds a request to create or update VPP Access Control List.
func (dsl *MockPutDSL) ACL(val *acl.AccessLists_Acl) linux.PutDSL {
	dsl.parent.performedPut[acl.Key(val.AclName)] = val
	return dsl
}

func (dsl *MockPutDSL) LinuxInterface(val *linux_intf.LinuxInterfaces_Interface) linux.PutDSL {
	return dsl
}

// Delete changes the DSL mode to allow removal of an existing configuration.
func (dsl *MockPutDSL) Delete() linux.DeleteDSL {
	return &MockDeleteDSL{dsl.parent}
}

// Send propagates requested changes to the plugins.
func (dsl *MockPutDSL) Send() defaultplugins.Reply {
	return dsl.parent.Send()
}

// Interface adds a request to delete an existing VPP network interface.
func (dsl *MockDeleteDSL) VppInterface(interfaceName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, vpp_intf.InterfaceKey(interfaceName))
	return dsl
}

// BfdSession adds a request to delete an existing bidirectional forwarding
// detection session.
func (dsl *MockDeleteDSL) BfdSession(bfdSessionIfaceName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, bfd.SessionKey(bfdSessionIfaceName))
	return dsl
}

// BfdAuthKeys adds a request to delete an existing bidirectional forwarding
// detection key.
func (dsl *MockDeleteDSL) BfdAuthKeys(bfdKeyName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, bfd.AuthKeysKey(bfdKeyName))
	return dsl
}

// BfdEchoFunction adds a request to delete an existing bidirectional forwarding
// detection echo function.
func (dsl *MockDeleteDSL) BfdEchoFunction(bfdEchoName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, bfd.EchoFunctionKey(bfdEchoName))
	return dsl
}

// BD adds a request to delete an existing VPP Bridge Domain.
func (dsl *MockDeleteDSL) BD(bdName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, l2.BridgeDomainKey(bdName))
	return dsl
}

// BDFIB adds a request to delete an existing VPP L2 Forwarding Information
// Base.
func (dsl *MockDeleteDSL) BDFIB(bdName string, mac string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, l2.FibKey(bdName, mac))
	return dsl
}

// XConnect adds a request to delete an existing VPP Cross Connect.
func (dsl *MockDeleteDSL) XConnect(rxIfName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, l2.XConnectKey(rxIfName))
	return dsl
}

// StaticRoute adds a request to delete an existing VPP L3 Static Route..
func (dsl *MockDeleteDSL) StaticRoute(vrf uint32, dstAddrInput *net.IPNet, nextHopAddr net.IP) linux.DeleteDSL {
	//_, dstAddr, _ := net.ParseCIDR(dstAddrInput)
	dsl.parent.performedDel = append(dsl.parent.performedDel, l3.RouteKey(vrf, dstAddrInput, nextHopAddr.String()))
	return dsl
}

// ACL adds a request to delete an existing VPP Access Control List.
func (dsl *MockDeleteDSL) ACL(aclName string) linux.DeleteDSL {
	dsl.parent.performedDel = append(dsl.parent.performedDel, acl.Key(aclName))
	return dsl
}
func (dsl *MockDeleteDSL) LinuxInterface(ifname string) linux.DeleteDSL {
	return dsl
}

// Put changes the DSL mode to allow configuration editing.
func (dsl *MockDeleteDSL) Put() linux.PutDSL {
	return &MockPutDSL{dsl.parent}
}

// Send propagates requested changes to the plugins.
func (dsl *MockDeleteDSL) Send() defaultplugins.Reply {
	return dsl.parent.Send()
}

// Reply interface allows to wait for a reply to previously called Send() and
// extract the result from it (success/error).
type Reply struct {
	err error
}

// ReceiveReply waits for a reply to previously called Send() and returns
// the result (error or nil).
func (dsl Reply) ReceiveReply() error {
	return dsl.err
}
<|endoftext|>


<commit_before>package vault

import (
	"context"
	"fmt"
	"math/rand"
	"path"
	"time"

	uuid "github.com/hashicorp/go-uuid"
	"github.com/hashicorp/vault/helper/namespace"
	"github.com/hashicorp/vault/sdk/logical"
)

type basicLeaseTestInfo struct {
	id     string
	mount  string
	expire time.Time
}

// add an irrevocable lease for test purposes
// returns the lease ID and expire time
func (c *Core) AddIrrevocableLease(ctx context.Context, pathPrefix string) (*basicLeaseTestInfo, error) {
	exp := c.expiration

	uuid, err := uuid.GenerateUUID()
	if err != nil {
		return nil, fmt.Errorf("error generating uuid: %w", err)
	}

	ns, err := namespace.FromContext(ctx)
	if err != nil {
		return nil, fmt.Errorf("error getting namespace from context: %w", err)
	}
	if ns == nil {
		ns = namespace.RootNamespace
	}

	leaseID := path.Join(pathPrefix, "lease"+uuid)

	if ns != namespace.RootNamespace {
		leaseID = fmt.Sprintf("%s.%s", leaseID, ns.ID)
	}

	randomTimeDelta := time.Duration(rand.Int31n(24))
	le := &leaseEntry{
		LeaseID:    leaseID,
		Path:       pathPrefix,
		namespace:  ns,
		IssueTime:  time.Now(),
		ExpireTime: time.Now().Add(randomTimeDelta * time.Hour),
		RevokeErr:  "some error message",
	}

	exp.pendingLock.Lock()
	defer exp.pendingLock.Unlock()

	if err := exp.persistEntry(context.Background(), le); err != nil {
		return nil, fmt.Errorf("error persisting irrevocable lease: %w", err)
	}

	exp.updatePendingInternal(le)

	return &basicLeaseTestInfo{
		id:     le.LeaseID,
		expire: le.ExpireTime,
	}, nil
}

// InjectIrrevocableLeases injects `count` irrevocable leases (currently to a
// single mount).
// It returns a map of the mount accessor to the number of leases stored there
func (c *Core) InjectIrrevocableLeases(ctx context.Context, count int) (map[string]int, error) {
	out := make(map[string]int)
	for i := 0; i < count; i++ {
		le, err := c.AddIrrevocableLease(ctx, "foo/")
		if err != nil {
			return nil, err
		}

		mountAccessor := c.expiration.getLeaseMountAccessor(ctx, le.id)
		if _, ok := out[mountAccessor]; !ok {
			out[mountAccessor] = 0
		}

		out[mountAccessor]++
	}

	return out, nil
}

type backend struct {
	path string
	ns   *namespace.Namespace
}

// set up multiple mounts, and return a mapping of the path to the mount accessor
func mountNoopBackends(c *Core, backends []*backend) (map[string]string, error) {
	// enable the noop backend
	c.logicalBackends["noop"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
		return &NoopBackend{}, nil
	}

	pathToMount := make(map[string]string)
	for _, backend := range backends {
		me := &MountEntry{
			Table: mountTableType,
			Path:  backend.path,
			Type:  "noop",
		}

		nsCtx := namespace.ContextWithNamespace(context.Background(), backend.ns)
		if err := c.mount(nsCtx, me); err != nil {
			return nil, fmt.Errorf("error mounting backend %s: %w", backend.path, err)
		}

		mount := c.router.MatchingMountEntry(nsCtx, backend.path)
		if mount == nil {
			return nil, fmt.Errorf("couldn't find mount for path %s", backend.path)
		}
		pathToMount[backend.path] = mount.Accessor
	}

	return pathToMount, nil
}
<commit_msg>[VAULT-1981] Add OSS changes (#11999)<commit_after>package vault

import (
	"context"
	"fmt"
	"math/rand"
	"path"
	"time"

	uuid "github.com/hashicorp/go-uuid"
	"github.com/hashicorp/vault/helper/namespace"
	"github.com/hashicorp/vault/sdk/logical"
)

type basicLeaseTestInfo struct {
	id     string
	mount  string
	expire time.Time
}

// add an irrevocable lease for test purposes
// returns the lease ID and expire time
func (c *Core) AddIrrevocableLease(ctx context.Context, pathPrefix string) (*basicLeaseTestInfo, error) {
	exp := c.expiration

	uuid, err := uuid.GenerateUUID()
	if err != nil {
		return nil, fmt.Errorf("error generating uuid: %w", err)
	}

	ns, err := namespace.FromContext(ctx)
	if err != nil {
		return nil, fmt.Errorf("error getting namespace from context: %w", err)
	}
	if ns == nil {
		ns = namespace.RootNamespace
	}

	leaseID := path.Join(pathPrefix, "lease"+uuid)

	if ns != namespace.RootNamespace {
		leaseID = fmt.Sprintf("%s.%s", leaseID, ns.ID)
	}

	randomTimeDelta := time.Duration(rand.Int31n(24))
	le := &leaseEntry{
		LeaseID:    leaseID,
		Path:       pathPrefix,
		namespace:  ns,
		IssueTime:  time.Now(),
		ExpireTime: time.Now().Add(randomTimeDelta * time.Hour),
		RevokeErr:  "some error message",
	}

	exp.pendingLock.Lock()
	defer exp.pendingLock.Unlock()

	if err := exp.persistEntry(context.Background(), le); err != nil {
		return nil, fmt.Errorf("error persisting irrevocable lease: %w", err)
	}

	exp.updatePendingInternal(le)

	return &basicLeaseTestInfo{
		id:     le.LeaseID,
		expire: le.ExpireTime,
	}, nil
}

// InjectIrrevocableLeases injects `count` irrevocable leases (currently to a
// single mount).
// It returns a map of the mount accessor to the number of leases stored there
func (c *Core) InjectIrrevocableLeases(ctx context.Context, count int) (map[string]int, error) {
	out := make(map[string]int)
	for i := 0; i < count; i++ {
		le, err := c.AddIrrevocableLease(ctx, "foo/")
		if err != nil {
			return nil, err
		}

		mountAccessor := c.expiration.getLeaseMountAccessor(ctx, le.id)
		if _, ok := out[mountAccessor]; !ok {
			out[mountAccessor] = 0
		}

		out[mountAccessor]++
	}

	return out, nil
}

type backend struct {
	path string
	ns   *namespace.Namespace
}

// set up multiple mounts, and return a mapping of the path to the mount accessor
func mountNoopBackends(c *Core, backends []*backend) (map[string]string, error) {
	// enable the noop backend
	c.logicalBackends["noop"] = func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) {
		return &NoopBackend{}, nil
	}

	pathToMount := make(map[string]string)
	for _, backend := range backends {
		me := &MountEntry{
			Table: mountTableType,
			Path:  backend.path,
			Type:  "noop",
		}

		nsCtx := namespace.ContextWithNamespace(context.Background(), backend.ns)
		if err := c.mount(nsCtx, me); err != nil {
			return nil, fmt.Errorf("error mounting backend %s: %w", backend.path, err)
		}

		mount := c.router.MatchingMountEntry(nsCtx, backend.path)
		if mount == nil {
			return nil, fmt.Errorf("couldn't find mount for path %s", backend.path)
		}
		pathToMount[backend.path] = mount.Accessor
	}

	return pathToMount, nil
}

func (c *Core) FetchLeaseCountToRevoke() int {
	c.expiration.pendingLock.RLock()
	defer c.expiration.pendingLock.RUnlock()
	return c.expiration.leaseCount
}
<|endoftext|>


<commit_before>package notifications

import (
	"time"

	"code.cloudfoundry.org/lager"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"red/redpb"
	"rolodex/rolodexpb"
)

//go:generate counterfeiter . RolodexClient

type RolodexClient interface {
	GetOwners(ctx context.Context, in *rolodexpb.GetOwnersRequest, opts ...grpc.CallOption) (*rolodexpb.GetOwnersResponse, error)
}

type Address struct {
	URL     string
	Channel string
}

type TeamURLs struct {
	slackTeamURLs  map[string]string
	defaultAddress Address
}

func NewTeamURLs(defaultURL string, defaultChannel string, mapping map[string]string) TeamURLs {
	return TeamURLs{
		slackTeamURLs: mapping,
		defaultAddress: Address{
			URL:     defaultURL,
			Channel: defaultChannel,
		},
	}
}

func (t TeamURLs) Default() Address {
	return t.defaultAddress
}

func (t TeamURLs) Lookup(logger lager.Logger, teamName string, channelName string) Address {
	url, found := t.slackTeamURLs[teamName]
	if !found {
		logger.Info("unknown-slack-team", lager.Data{
			"team-name": teamName,
		})
		return t.defaultAddress
	}

	return Address{
		URL:     url,
		Channel: channelName,
	}
}

//go:generate counterfeiter . AddressBook

type AddressBook interface {
	AddressForRepo(logger lager.Logger, owner, name string) []Address
}

type rolodex struct {
	client   RolodexClient
	teamURLs TeamURLs
}

func NewRolodex(client RolodexClient, teamURLs TeamURLs) AddressBook {
	return &rolodex{
		client:   client,
		teamURLs: teamURLs,
	}
}

func (r *rolodex) AddressForRepo(logger lager.Logger, owner, name string) []Address {
	logger = logger.Session("rolodex", lager.Data{
		"owner":      owner,
		"repository": name,
	})

	ctx, cancel := context.WithTimeout(context.TODO(), 100 * time.Millisecond)
	defer cancel()

	response, err := r.client.GetOwners(ctx, &rolodexpb.GetOwnersRequest{
		Repository: &redpb.Repository{
			Owner: owner,
			Name:  name,
		},
	})

	if err != nil {
		logger.Error("getting-owners-failed", err)

		return []Address{r.teamURLs.Default()}
	}

	return r.addressesFor(logger, response.GetTeams())
}

func (r *rolodex) addressesFor(logger lager.Logger, teams []*rolodexpb.Team) []Address {
	if len(teams) == 0 {
		logger.Info("no-owners-found")
		return []Address{r.teamURLs.Default()}
	}

	addresses := []Address{}

	for _, team := range teams {
		channel := team.GetSlackChannel()
		address := r.teamURLs.Lookup(logger, channel.GetTeam(), channel.GetName())
		addresses = append(addresses, address)
	}

	return addresses
}
<commit_msg>Formatting<commit_after>package notifications

import (
	"time"

	"code.cloudfoundry.org/lager"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	"red/redpb"
	"rolodex/rolodexpb"
)

//go:generate counterfeiter . RolodexClient

type RolodexClient interface {
	GetOwners(ctx context.Context, in *rolodexpb.GetOwnersRequest, opts ...grpc.CallOption) (*rolodexpb.GetOwnersResponse, error)
}

type Address struct {
	URL     string
	Channel string
}

type TeamURLs struct {
	slackTeamURLs  map[string]string
	defaultAddress Address
}

func NewTeamURLs(defaultURL string, defaultChannel string, mapping map[string]string) TeamURLs {
	return TeamURLs{
		slackTeamURLs: mapping,
		defaultAddress: Address{
			URL:     defaultURL,
			Channel: defaultChannel,
		},
	}
}

func (t TeamURLs) Default() Address {
	return t.defaultAddress
}

func (t TeamURLs) Lookup(logger lager.Logger, teamName string, channelName string) Address {
	url, found := t.slackTeamURLs[teamName]
	if !found {
		logger.Info("unknown-slack-team", lager.Data{
			"team-name": teamName,
		})
		return t.defaultAddress
	}

	return Address{
		URL:     url,
		Channel: channelName,
	}
}

//go:generate counterfeiter . AddressBook

type AddressBook interface {
	AddressForRepo(logger lager.Logger, owner, name string) []Address
}

type rolodex struct {
	client   RolodexClient
	teamURLs TeamURLs
}

func NewRolodex(client RolodexClient, teamURLs TeamURLs) AddressBook {
	return &rolodex{
		client:   client,
		teamURLs: teamURLs,
	}
}

func (r *rolodex) AddressForRepo(logger lager.Logger, owner, name string) []Address {
	logger = logger.Session("rolodex", lager.Data{
		"owner":      owner,
		"repository": name,
	})

	ctx, cancel := context.WithTimeout(context.TODO(), 100*time.Millisecond)
	defer cancel()

	response, err := r.client.GetOwners(ctx, &rolodexpb.GetOwnersRequest{
		Repository: &redpb.Repository{
			Owner: owner,
			Name:  name,
		},
	})

	if err != nil {
		logger.Error("getting-owners-failed", err)

		return []Address{r.teamURLs.Default()}
	}

	return r.addressesFor(logger, response.GetTeams())
}

func (r *rolodex) addressesFor(logger lager.Logger, teams []*rolodexpb.Team) []Address {
	if len(teams) == 0 {
		logger.Info("no-owners-found")
		return []Address{r.teamURLs.Default()}
	}

	addresses := []Address{}

	for _, team := range teams {
		channel := team.GetSlackChannel()
		address := r.teamURLs.Lookup(logger, channel.GetTeam(), channel.GetName())
		addresses = append(addresses, address)
	}

	return addresses
}
<|endoftext|>


<commit_before>package revok

import (
	"cred-alert/db"
	"fmt"
	"os"
	"time"

	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/lager"
	"github.com/tedsuo/ifrit"
)

type RepoDiscoverer struct {
	logger               lager.Logger
	workdir              string
	cloneMsgCh           chan CloneMsg
	ghClient             GitHubClient
	clock                clock.Clock
	interval             time.Duration
	repositoryRepository db.RepositoryRepository
}

func NewRepoDiscoverer(
	logger lager.Logger,
	workdir string,
	cloneMsgCh chan CloneMsg,
	ghClient GitHubClient,
	clock clock.Clock,
	interval time.Duration,
	repositoryRepository db.RepositoryRepository,
) ifrit.Runner {
	return &RepoDiscoverer{
		logger:               logger,
		workdir:              workdir,
		cloneMsgCh:           cloneMsgCh,
		ghClient:             ghClient,
		clock:                clock,
		interval:             interval,
		repositoryRepository: repositoryRepository,
	}
}

func (r *RepoDiscoverer) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := r.logger.Session("repo-discoverer")
	logger.Info("started")

	close(ready)

	timer := r.clock.NewTicker(r.interval)

	defer func() {
		logger.Info("done")
		timer.Stop()
	}()

	r.work(logger)

	for {
		select {
		case <-timer.C():
			r.work(logger)
		case <-signals:
			return nil
		}
	}
}

type CloneMsg struct {
	Repository string
	Owner      string
	URL        string
}

func (r *RepoDiscoverer) work(logger lager.Logger) {
	logger = logger.Session("work")
	defer logger.Info("done")

	repos, err := r.ghClient.ListRepositories(logger)
	if err != nil {
		logger.Error("failed", err)
		return
	}

	dbRepos, err := r.repositoryRepository.All()
	if err != nil {
		logger.Error("failed", err)
		return
	}

	knownRepos := make(map[string]struct{}, len(dbRepos))
	for _, existingRepo := range dbRepos {
		key := fmt.Sprintf("%s-%s", existingRepo.Owner, existingRepo.Name)
		knownRepos[key] = struct{}{}
	}

	for _, repo := range repos {
		key := fmt.Sprintf("%s-%s", repo.Owner, repo.Name)
		if _, found := knownRepos[key]; found {
			continue
		}

		err = r.repositoryRepository.Create(&db.Repository{
			Owner:         repo.Owner,
			Name:          repo.Name,
			SSHURL:        repo.SSHURL,
			Private:       repo.Private,
			DefaultBranch: repo.DefaultBranch,
			RawJSON:       repo.RawJSON,
		})
		if err != nil {
			logger.Error("failed-to-create-repository", err, lager.Data{
				"owner":      repo.Owner,
				"repository": repo.Name,
			})
			continue
		}

		r.cloneMsgCh <- CloneMsg{
			Repository: repo.Name,
			Owner:      repo.Owner,
			URL:        repo.SSHURL,
		}
	}
}
<commit_msg>RepoDiscoverer can be interrupted quickly<commit_after>package revok

import (
	"context"
	"cred-alert/db"
	"fmt"
	"os"
	"time"

	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/lager"
	"github.com/tedsuo/ifrit"
)

type RepoDiscoverer struct {
	logger               lager.Logger
	workdir              string
	cloneMsgCh           chan CloneMsg
	ghClient             GitHubClient
	clock                clock.Clock
	interval             time.Duration
	repositoryRepository db.RepositoryRepository
}

func NewRepoDiscoverer(
	logger lager.Logger,
	workdir string,
	cloneMsgCh chan CloneMsg,
	ghClient GitHubClient,
	clock clock.Clock,
	interval time.Duration,
	repositoryRepository db.RepositoryRepository,
) ifrit.Runner {
	return &RepoDiscoverer{
		logger:               logger,
		workdir:              workdir,
		cloneMsgCh:           cloneMsgCh,
		ghClient:             ghClient,
		clock:                clock,
		interval:             interval,
		repositoryRepository: repositoryRepository,
	}
}

func (r *RepoDiscoverer) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := r.logger.Session("repo-discoverer")
	logger.Info("started")

	close(ready)

	timer := r.clock.NewTicker(r.interval)

	ctx, cancel := context.WithCancel(context.Background())

	defer func() {
		logger.Info("done")
		timer.Stop()
	}()

	r.work(logger, signals, cancel)

	for {
		select {
		case <-signals:
			cancel()
		case <-ctx.Done():
			return nil
		case <-timer.C():
			r.work(logger, signals, cancel)
		}
	}

	return nil
}

type CloneMsg struct {
	Repository string
	Owner      string
	URL        string
}

func (r *RepoDiscoverer) work(logger lager.Logger, signals <-chan os.Signal, cancel context.CancelFunc) {
	logger = logger.Session("work")
	defer logger.Info("done")

	repos, err := r.ghClient.ListRepositories(logger)
	if err != nil {
		logger.Error("failed", err)
		return
	}

	dbRepos, err := r.repositoryRepository.All()
	if err != nil {
		logger.Error("failed", err)
		return
	}

	knownRepos := make(map[string]struct{}, len(dbRepos))
	for _, existingRepo := range dbRepos {
		key := fmt.Sprintf("%s-%s", existingRepo.Owner, existingRepo.Name)
		knownRepos[key] = struct{}{}
	}

	for _, repo := range repos {
		select {
		case <-signals:
			cancel()
			return
		default:
			key := fmt.Sprintf("%s-%s", repo.Owner, repo.Name)
			if _, found := knownRepos[key]; found {
				continue
			}

			err = r.repositoryRepository.Create(&db.Repository{
				Owner:         repo.Owner,
				Name:          repo.Name,
				SSHURL:        repo.SSHURL,
				Private:       repo.Private,
				DefaultBranch: repo.DefaultBranch,
				RawJSON:       repo.RawJSON,
			})
			if err != nil {
				logger.Error("failed-to-create-repository", err, lager.Data{
					"owner":      repo.Owner,
					"repository": repo.Name,
				})
				continue
			}

			r.cloneMsgCh <- CloneMsg{
				Repository: repo.Name,
				Owner:      repo.Owner,
				URL:        repo.SSHURL,
			}
		}
	}
}
<|endoftext|>


<commit_before>// vagrant implements the packer.PostProcessor interface and adds a
// post-processor that turns artifacts of known builders into Vagrant
// boxes.
package vagrant

import (
	"fmt"
	"github.com/mitchellh/mapstructure"
	"github.com/mitchellh/packer/packer"
	"log"
	"text/template"
)

var builtins = map[string]string{
	"mitchellh.amazonebs":  "aws",
	"mitchellh.virtualbox": "virtualbox",
	"mitchellh.vmware":     "vmware",
}

type Config struct {
	OutputPath string `mapstructure:"output"`
}

type PostProcessor struct {
	config     Config
	premade    map[string]packer.PostProcessor
	rawConfigs []interface{}
}

func (p *PostProcessor) Configure(raws ...interface{}) error {
	// Store the raw configs for usage later
	p.rawConfigs = raws

	for _, raw := range raws {
		err := mapstructure.Decode(raw, &p.config)
		if err != nil {
			return err
		}
	}

	ppExtraConfig := make(map[string]interface{})
	if p.config.OutputPath == "" {
		p.config.OutputPath = "packer_{{ .BuildName }}_{{.Provider}}.box"
		ppExtraConfig["output"] = p.config.OutputPath
	}

	_, err := template.New("output").Parse(p.config.OutputPath)
	if err != nil {
		return fmt.Errorf("output invalid template: %s", err)
	}

	// Store the extra configuration for post-processors
	p.rawConfigs = append(p.rawConfigs, ppExtraConfig)

	// TODO(mitchellh): Properly handle multiple raw configs
	var mapConfig map[string]interface{}
	if err := mapstructure.Decode(raws[0], &mapConfig); err != nil {
		return err
	}

	p.premade = make(map[string]packer.PostProcessor)
	errors := make([]error, 0)
	for k, raw := range mapConfig {
		pp := keyToPostProcessor(k)
		if pp == nil {
			continue
		}

		// Create the proper list of configurations
		ppConfigs := make([]interface{}, 0, len(p.rawConfigs)+1)
		copy(ppConfigs, p.rawConfigs)
		ppConfigs = append(ppConfigs, raw)

		if err := pp.Configure(ppConfigs...); err != nil {
			errors = append(errors, err)
		}

		p.premade[k] = pp
	}

	if len(errors) > 0 {
		return &packer.MultiError{errors}
	}

	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	ppName, ok := builtins[artifact.BuilderId()]
	if !ok {
		return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
	}

	// Use the premade PostProcessor if we have one. Otherwise, we
	// create it and configure it here.
	pp, ok := p.premade[ppName]
	if !ok {
		log.Printf("Premade post-processor for '%s' not found. Creating.", ppName)
		pp = keyToPostProcessor(ppName)
		if pp == nil {
			return nil, false, fmt.Errorf("Vagrant box post-processor not found: %s", ppName)
		}

		if err := pp.Configure(p.rawConfigs...); err != nil {
			return nil, false, err
		}
	}

	ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", ppName))
	return pp.PostProcess(ui, artifact)
}

func keyToPostProcessor(key string) packer.PostProcessor {
	switch key {
	case "aws":
		return new(AWSBoxPostProcessor)
	case "virtualbox":
		return new(VBoxBoxPostProcessor)
	case "vmware":
		return new(VMwareBoxPostProcessor)
	default:
		return nil
	}
}
<commit_msg>post-processor/vagrant: fix output ConfigTemplate validation [GH-324]<commit_after>// vagrant implements the packer.PostProcessor interface and adds a
// post-processor that turns artifacts of known builders into Vagrant
// boxes.
package vagrant

import (
	"fmt"
	"github.com/mitchellh/mapstructure"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"log"
)

var builtins = map[string]string{
	"mitchellh.amazonebs":  "aws",
	"mitchellh.virtualbox": "virtualbox",
	"mitchellh.vmware":     "vmware",
}

type Config struct {
	common.PackerConfig `mapstructure:",squash"`

	OutputPath string `mapstructure:"output"`
}

type PostProcessor struct {
	config     Config
	premade    map[string]packer.PostProcessor
	rawConfigs []interface{}
}

func (p *PostProcessor) Configure(raws ...interface{}) error {
	// Store the raw configs for usage later
	p.rawConfigs = raws

	md, err := common.DecodeConfig(&p.config, raws...)
	if err != nil {
		return err
	}

	tpl, err := packer.NewConfigTemplate()
	if err != nil {
		return err
	}
	tpl.UserVars = p.config.PackerUserVars

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)

	ppExtraConfig := make(map[string]interface{})
	if p.config.OutputPath == "" {
		p.config.OutputPath = "packer_{{ .BuildName }}_{{.Provider}}.box"
		ppExtraConfig["output"] = p.config.OutputPath
	}

	//	_, err := template.New("output").Parse(p.config.OutputPath)
	if err := tpl.Validate(p.config.OutputPath); err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Error parsing output template: %s", err))
		return errs
	}

	// Store the extra configuration for post-processors
	p.rawConfigs = append(p.rawConfigs, ppExtraConfig)

	// TODO(mitchellh): Properly handle multiple raw configs
	var mapConfig map[string]interface{}
	if err := mapstructure.Decode(raws[0], &mapConfig); err != nil {
		return err
	}

	p.premade = make(map[string]packer.PostProcessor)
	errors := make([]error, 0)
	for k, raw := range mapConfig {
		pp := keyToPostProcessor(k)
		if pp == nil {
			continue
		}

		// Create the proper list of configurations
		ppConfigs := make([]interface{}, 0, len(p.rawConfigs)+1)
		copy(ppConfigs, p.rawConfigs)
		ppConfigs = append(ppConfigs, raw)

		if err := pp.Configure(ppConfigs...); err != nil {
			errors = append(errors, err)
		}

		p.premade[k] = pp
	}

	if len(errors) > 0 {
		return &packer.MultiError{errors}
	}

	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	ppName, ok := builtins[artifact.BuilderId()]
	if !ok {
		return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
	}

	// Use the premade PostProcessor if we have one. Otherwise, we
	// create it and configure it here.
	pp, ok := p.premade[ppName]
	if !ok {
		log.Printf("Premade post-processor for '%s' not found. Creating.", ppName)
		pp = keyToPostProcessor(ppName)
		if pp == nil {
			return nil, false, fmt.Errorf("Vagrant box post-processor not found: %s", ppName)
		}

		if err := pp.Configure(p.rawConfigs...); err != nil {
			return nil, false, err
		}
	}

	ui.Say(fmt.Sprintf("Creating Vagrant box for '%s' provider", ppName))
	return pp.PostProcess(ui, artifact)
}

func keyToPostProcessor(key string) packer.PostProcessor {
	switch key {
	case "aws":
		return new(AWSBoxPostProcessor)
	case "virtualbox":
		return new(VBoxBoxPostProcessor)
	case "vmware":
		return new(VMwareBoxPostProcessor)
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>package vsphere

import (
	"bytes"
	"fmt"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"os/exec"
	"strings"
)

var builtins = map[string]string{
	"mitchellh.vmware": "vmware",
}

type Config struct {
	common.PackerConfig `mapstructure:",squash"`

	Insecure           bool   `mapstructure:"insecure"`
	Datacenter         string `mapstructure:"datacenter"`
	Datastore          string `mapstructure:"datastore"`
	Host               string `mapstructure:"host"`
	Password           string `mapstructure:"password"`
	PathToResourcePool string `mapstructure:"path_to_resource_pool"`
	Username           string `mapstructure:"username"`
	VMFolder           string `mapstructure:"vm_folder"`
	VMName             string `mapstructure:"vm_name"`
	VMNetwork          string `mapstructure:"vm_network"`
}

type PostProcessor struct {
	config Config
}

func (p *PostProcessor) Configure(raws ...interface{}) error {
	_, err := common.DecodeConfig(&p.config, raws...)
	if err != nil {
		return err
	}

	tpl, err := packer.NewConfigTemplate()
	if err != nil {
		return err
	}
	tpl.UserVars = p.config.PackerUserVars

	// Accumulate any errors
	errs := new(packer.MultiError)

	if _, err := exec.LookPath("ovftool"); err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("ovftool not found: %s", err))
	}

	validates := map[string]*string{
		"datacenter":            &p.config.Datacenter,
		"datastore":             &p.config.Datastore,
		"host":                  &p.config.Host,
		"vm_network":            &p.config.VMNetwork,
		"password":              &p.config.Password,
		"path_to_resource_pool": &p.config.PathToResourcePool,
		"username":              &p.config.Username,
		"vm_folder":             &p.config.VMFolder,
		"vm_name":               &p.config.VMName,
	}

	for n := range validates {
		if *validates[n] == "" {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("%s must be set", n))
		}
	}

	if len(errs.Errors) > 0 {
		return errs
	}

	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	if _, ok := builtins[artifact.BuilderId()]; !ok {
		return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
	}

	vmx := ""
	for _, path := range artifact.Files() {
		if strings.HasSuffix(path, ".vmx") {
			vmx = path
			break
		}
	}

	if vmx == "" {
		return nil, false, fmt.Errorf("VMX file not found")
	}

	ui.Message(fmt.Sprintf("Uploading %s to vSphere", vmx))

	args := []string{
		fmt.Sprintf("--noSSLVerify=%t", p.config.Insecure),
		"--acceptAllEulas",
		fmt.Sprintf("--name=%s", p.config.VMName),
		fmt.Sprintf("--datastore=%s", p.config.Datastore),
		fmt.Sprintf("--network=%s", p.config.VMNetwork),
		fmt.Sprintf("--vmFolder=%s", p.config.VMFolder),
		fmt.Sprintf("vi://%s:%s@%s/%s/%s",
			p.config.Username,
			p.config.Password,
			p.config.Host,
			p.config.Datacenter,
			p.config.PathToResourcePool),
	}

	var out bytes.Buffer
	cmd := exec.Command("ovftool", args...)
	cmd.Stdout = &out
	if err := cmd.Run(); err != nil {
		return nil, false, fmt.Errorf("Failed: %s\nStdout: %s", err, out.String())
	}

	ui.Message(fmt.Sprintf("%s", out.String()))

	return artifact, false, nil
}
<commit_msg>fix post-processor vsphere<commit_after>package vsphere

import (
	"bytes"
	"fmt"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"os/exec"
	"strings"
)

var builtins = map[string]string{
	"mitchellh.vmware": "vmware",
}

type Config struct {
	common.PackerConfig `mapstructure:",squash"`

	Insecure           bool   `mapstructure:"insecure"`
	Cluster            string `mapstructure:"cluster"`
	Datacenter         string `mapstructure:"datacenter"`
	Datastore          string `mapstructure:"datastore"`
	Debug              bool   `mapstructure:"debug"`
	Host               string `mapstructure:"host"`
	Password           string `mapstructure:"password"`
	ResourcePool       string `mapstructure:"resource_pool"`
	Username           string `mapstructure:"username"`
	VMFolder           string `mapstructure:"vm_folder"`
	VMName             string `mapstructure:"vm_name"`
	VMNetwork          string `mapstructure:"vm_network"`
}

type PostProcessor struct {
	config Config
}

func (p *PostProcessor) Configure(raws ...interface{}) error {
	_, err := common.DecodeConfig(&p.config, raws...)
	if err != nil {
		return err
	}

	tpl, err := packer.NewConfigTemplate()
	if err != nil {
		return err
	}
	tpl.UserVars = p.config.PackerUserVars

	// Accumulate any errors
	errs := new(packer.MultiError)

	if err := tpl.Validate(p.config.VMName); err != nil {
			errs = packer.MultiErrorAppend(
					errs, fmt.Errorf("Error parsing output template: %s", err))
	}

	if _, err := exec.LookPath("ovftool"); err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("ovftool not found: %s", err))
	}

	validates := map[string]*string{
		"cluster":      &p.config.Cluster,
		"datacenter":   &p.config.Datacenter,
		"datastore":    &p.config.Datastore,
		"host":         &p.config.Host,
		"vm_network":   &p.config.VMNetwork,
		"password":     &p.config.Password,
		"resource_pool": &p.config.ResourcePool,
		"username":     &p.config.Username,
		"vm_folder":    &p.config.VMFolder,
		"vm_name":      &p.config.VMName,
	}

	for n := range validates {
		if *validates[n] == "" {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("%s must be set", n))
		}
	}

	if len(errs.Errors) > 0 {
		return errs
	}

	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	if _, ok := builtins[artifact.BuilderId()]; !ok {
		return nil, false, fmt.Errorf("Unknown artifact type, can't build box: %s", artifact.BuilderId())
	}

	vmx := ""
	for _, path := range artifact.Files() {
		if strings.HasSuffix(path, ".vmx") {
			vmx = path
			break
		}
	}

	if vmx == "" {
		return nil, false, fmt.Errorf("VMX file not found")
	}

	ui.Message(fmt.Sprintf("Uploading %s to vSphere", vmx))

	args := []string{
		fmt.Sprintf("--noSSLVerify=%t", p.config.Insecure),
		"--acceptAllEulas",
		fmt.Sprintf("--name=%s", p.config.VMName),
		fmt.Sprintf("--datastore=%s", p.config.Datastore),
		fmt.Sprintf("--network=%s", p.config.VMNetwork),
		fmt.Sprintf("--vmFolder=%s", p.config.VMFolder),
		fmt.Sprintf("%s", vmx),
		fmt.Sprintf("vi://%s:%s@%s/%s/host/%s/Resources/%s",
			p.config.Username,
			p.config.Password,
			p.config.Host,
			p.config.Datacenter,
			p.config.Cluster,
			p.config.ResourcePool),
	}

	if p.config.Debug {
		ui.Message(fmt.Sprintf("DEBUG: %s", args))
	}

	var out bytes.Buffer
	cmd := exec.Command("ovftool", args...)
	cmd.Stdout = &out
	if err := cmd.Run(); err != nil {
		return nil, false, fmt.Errorf("Failed: %s\nStdout: %s", err, out.String())
	}

	ui.Message(fmt.Sprintf("%s", out.String()))

	return artifact, false, nil
}
<|endoftext|>


<commit_before>package reactive

import (
	"context"
	"errors"
	"sync"
	"time"
)

var (
	// Sentinel error to tell the rerunner to not dump the current
	// computation cache and let the error'd function retry.
	RetrySentinelError = errors.New("retry")

	// WriteThenReadDelay is how long to wait after hearing a change
	// was made, before reading that change by rerunning.
	WriteThenReadDelay = 200 * time.Millisecond
)

// locker is a collection of mutexes indexed by arbitrary keys
type locker struct {
	mu sync.Mutex
	m  map[interface{}]*lock
}

// newLocker creates a new locker instance.
func newLocker() *locker {
	return &locker{
		m: make(map[interface{}]*lock),
	}
}

// lock is a single mutex in a locker
type lock struct {
	ref int
	mu  ctxMutex
}

// Lock locks a locker by (optionally) allocating, increasing the ref count,
// and locking
func (l *locker) Lock(ctx context.Context, k interface{}) error {
	l.mu.Lock()
	m, ok := l.m[k]
	if !ok {
		m = new(lock)
		l.m[k] = m
	}
	m.ref++
	l.mu.Unlock()
	return m.mu.Lock(ctx)
}

// Unlock unlocks a locker by unlocking, decreasing the ref count, and
// (optionally) deleting
func (l *locker) Unlock(k interface{}) {
	l.mu.Lock()
	m := l.m[k]
	m.mu.Unlock()
	m.ref--
	if m.ref == 0 {
		delete(l.m, k)
	}
	l.mu.Unlock()
}

type computation struct {
	node  node
	value interface{}
}

// cache caches computations
type cache struct {
	mu           sync.Mutex
	locker       *locker
	computations map[interface{}]*computation
}

func (c *cache) get(key interface{}) *computation {
	c.mu.Lock()
	defer c.mu.Unlock()

	return c.computations[key]
}

// set adds a computation to the cache for the given key
func (c *cache) set(key interface{}, computation *computation) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.computations[key] == nil {
		c.computations[key] = computation
	}
}

func (c *cache) cleanInvalidated() {
	c.mu.Lock()
	defer c.mu.Unlock()

	for key, computation := range c.computations {
		if computation.node.Invalidated() {
			delete(c.computations, key)
		}
	}
}

// PurgeCache is meant to be use as a transition off of using the reactive cache.
// It allows slowly removing caching whenever the user wants, ideally between
// cache execution runs.
func PurgeCache(ctx context.Context) {
	cVal := ctx.Value(cacheKey{})
	if cVal == nil {
		return
	}
	c, ok := cVal.(*cache)
	if !ok {
		return
	}
	c.purgeCache()
}

func (c *cache) purgeCache() {
	c.mu.Lock()
	defer c.mu.Unlock()

	c.computations = make(map[interface{}]*computation)
}

// Resource represents a leaf-level dependency in a computation
type Resource struct {
	node
}

// NewResource creates a new Resource
func NewResource() *Resource {
	return &Resource{
		node: node{},
	}
}

// Invalidate permanently invalidates r
func (r *Resource) Invalidate() {
	go r.invalidate()
}

// Store invalidates all computations currently depending on r
func (r *Resource) Strobe() {
	go r.strobe()
}

// Cleanup registers a handler to be called when all computations using r stop
//
// NOTE: For f to be called, at least one computation must AddDependency r!
func (r *Resource) Cleanup(f func()) {
	r.node.handleRelease(f)
}

type computationKey struct{}
type cacheKey struct{}

type dependencySetKey struct{}

type dependencySet struct {
	mu           sync.Mutex
	dependencies []Dependency
}

func (ds *dependencySet) add(dep Dependency) {
	ds.mu.Lock()
	defer ds.mu.Unlock()
	ds.dependencies = append(ds.dependencies, dep)
}

func (ds *dependencySet) get() []Dependency {
	ds.mu.Lock()
	defer ds.mu.Unlock()
	return ds.dependencies
}

type Dependency interface{}

type DependencyCallbackFunc func(context.Context, Dependency)

type dependencyCallbackKey struct{}

func AddDependency(ctx context.Context, r *Resource, dep Dependency) {
	if !HasRerunner(ctx) {
		r.node.addOut(&node{released: true})
		return
	}

	computation := ctx.Value(computationKey{}).(*computation)
	r.node.addOut(&computation.node)

	if dep != nil {
		depSet, ok := ctx.Value(dependencySetKey{}).(*dependencySet)
		if ok && depSet != nil {
			depSet.add(dep)
		}
		if callback, ok := ctx.Value(dependencyCallbackKey{}).(DependencyCallbackFunc); ok && callback != nil {
			callback(ctx, dep)
		}
	}
}

// WithDependencyCallback registers a callback that is invoked when
// AddDependency is called with non-nil serializable dependency.
func WithDependencyCallback(ctx context.Context, f DependencyCallbackFunc) context.Context {
	return context.WithValue(ctx, dependencyCallbackKey{}, f)
}

func Dependencies(ctx context.Context) []Dependency {
	depSet := ctx.Value(dependencySetKey{}).(*dependencySet)
	if depSet == nil {
		return nil
	}
	return depSet.get()
}

type ComputeFunc func(context.Context) (interface{}, error)

func run(ctx context.Context, f ComputeFunc) (*computation, error) {
	// build result computation and local computation Ctx
	c := &computation{
		// this node will be freed either when the computation fails, or by our
		// caller
		node: node{},
	}

	childCtx := context.WithValue(ctx, computationKey{}, c)

	// Compute f and write the results to the c
	value, err := f(childCtx)
	if err != nil {
		go c.node.release()
		return nil, err
	}

	c.value = value

	return c, nil
}

func Cache(ctx context.Context, key interface{}, f ComputeFunc) (interface{}, error) {
	if !HasRerunner(ctx) {
		val, err := f(ctx)
		return val, err
	}

	cache := ctx.Value(cacheKey{}).(*cache)
	computation := ctx.Value(computationKey{}).(*computation)

	if err := cache.locker.Lock(ctx, key); err != nil {
		return nil, err
	}
	defer cache.locker.Unlock(key)

	if child := cache.get(key); child != nil {
		child.node.addOut(&computation.node)
		return child.value, nil
	}

	child, err := run(ctx, f)
	if err != nil {
		return nil, err
	}
	cache.set(key, child)

	child.node.addOut(&computation.node)
	return child.value, nil
}

// Rerunner automatically reruns a computation whenever its dependencies
// change.
//
// The computation stops when it returns an error or after calling Stop.  There
// is no way to get the output value from a computation. Instead, the
// computation should communicate its result before returning.
type Rerunner struct {
	ctx       context.Context
	cancelCtx context.CancelFunc

	f                    ComputeFunc
	cache                *cache
	minRerunInterval     time.Duration
	retryDelay           time.Duration
	alwaysSpawnGoroutine bool

	// flushed tracks if the next computation should run without delay. It is set
	// to false as soon as the next computation starts. flushCh is closed when
	// flushed is set to true.
	flushMu sync.Mutex
	flushCh chan struct{}
	flushed bool

	mu          sync.Mutex
	computation *computation
	stop        bool

	lastRun time.Time
}

// NewRerunner runs f continuously
func NewRerunner(ctx context.Context, f ComputeFunc, minRerunInterval time.Duration, alwaysSpawnGoroutine bool) *Rerunner {
	ctx, cancelCtx := context.WithCancel(ctx)

	r := &Rerunner{
		ctx:       ctx,
		cancelCtx: cancelCtx,

		f: f,
		cache: &cache{
			computations: make(map[interface{}]*computation),
			locker:       newLocker(),
		},
		minRerunInterval:     minRerunInterval,
		retryDelay:           minRerunInterval,
		alwaysSpawnGoroutine: alwaysSpawnGoroutine,

		flushCh: make(chan struct{}, 0),
	}
	go r.run()
	return r
}

// RerunImmediately removes the delay from the next recomputation.
func (r *Rerunner) RerunImmediately() {
	r.flushMu.Lock()
	defer r.flushMu.Unlock()

	if !r.flushed {
		close(r.flushCh)
		r.flushed = true
	}
}

// run performs an actual computation
func (r *Rerunner) run() {
	// Wait for the minimum rerun interval. Exit early if the computation is stopped.
	delta := r.retryDelay - time.Now().Sub(r.lastRun)

	t := time.NewTimer(delta)
	select {
	case <-r.ctx.Done():
	case <-t.C:
	case <-r.flushCh:
	}
	t.Stop()
	if r.ctx.Err() != nil {
		return
	}

	r.flushMu.Lock()
	if r.flushed {
		r.flushCh = make(chan struct{}, 0)
		r.flushed = false
	}
	r.flushMu.Unlock()

	r.mu.Lock()
	defer r.mu.Unlock()

	// Bail out if the computation has been stopped.
	if r.stop {
		return
	}

	if !r.lastRun.IsZero() {
		// Delay the rerun in order to emulate write-then-read consistency.
		time.Sleep(WriteThenReadDelay)
	}
	r.cache.cleanInvalidated()
	ctx := context.WithValue(r.ctx, cacheKey{}, r.cache)
	ctx = context.WithValue(ctx, dependencySetKey{}, &dependencySet{})

	currentComputation, err := run(ctx, r.f)
	r.lastRun = time.Now()
	if err != nil {
		if err != RetrySentinelError {
			// If we encountered an error that is not the retry sentinel,
			// we should stop the rerunner.
			return
		}
		// Reset the cache for sentinel errors so we get a clean slate.
		r.cache.purgeCache()

		r.retryDelay = r.retryDelay * 2

		// Max out the retry delay to at 1 minute.
		if r.retryDelay > time.Minute {
			r.retryDelay = time.Minute
		}
		go r.run()
	} else {
		// If we succeeded in the computation, we can release the old computation
		// and reset the retry delay.
		if r.computation != nil {
			go r.computation.node.release()
			r.computation = nil
		}

		r.computation = currentComputation
		r.retryDelay = r.minRerunInterval

		// Schedule a rerun whenever our node becomes invalidated (which might already
		// have happened!)
		currentComputation.node.handleInvalidate(func() {
			if r.alwaysSpawnGoroutine {
				go r.run()
			} else {
				r.run()
			}
		})
	}
}

func (r *Rerunner) Stop() {
	// Call cancelCtx before acquiring the lock as the lock might be held for a long time during a running computation.
	r.cancelCtx()

	r.mu.Lock()
	r.stop = true
	if r.computation != nil {
		go r.computation.node.release()
		r.computation = nil
	}
	r.mu.Unlock()
}

func HasRerunner(ctx context.Context) bool {
	return ctx.Value(computationKey{}) != nil
}
<commit_msg>go reactive: Cancel context after each reactive Run<commit_after>package reactive

import (
	"context"
	"errors"
	"sync"
	"time"
)

var (
	// Sentinel error to tell the rerunner to not dump the current
	// computation cache and let the error'd function retry.
	RetrySentinelError = errors.New("retry")

	// WriteThenReadDelay is how long to wait after hearing a change
	// was made, before reading that change by rerunning.
	WriteThenReadDelay = 200 * time.Millisecond
)

// locker is a collection of mutexes indexed by arbitrary keys
type locker struct {
	mu sync.Mutex
	m  map[interface{}]*lock
}

// newLocker creates a new locker instance.
func newLocker() *locker {
	return &locker{
		m: make(map[interface{}]*lock),
	}
}

// lock is a single mutex in a locker
type lock struct {
	ref int
	mu  ctxMutex
}

// Lock locks a locker by (optionally) allocating, increasing the ref count,
// and locking
func (l *locker) Lock(ctx context.Context, k interface{}) error {
	l.mu.Lock()
	m, ok := l.m[k]
	if !ok {
		m = new(lock)
		l.m[k] = m
	}
	m.ref++
	l.mu.Unlock()
	return m.mu.Lock(ctx)
}

// Unlock unlocks a locker by unlocking, decreasing the ref count, and
// (optionally) deleting
func (l *locker) Unlock(k interface{}) {
	l.mu.Lock()
	m := l.m[k]
	m.mu.Unlock()
	m.ref--
	if m.ref == 0 {
		delete(l.m, k)
	}
	l.mu.Unlock()
}

type computation struct {
	node  node
	value interface{}
}

// cache caches computations
type cache struct {
	mu           sync.Mutex
	locker       *locker
	computations map[interface{}]*computation
}

func (c *cache) get(key interface{}) *computation {
	c.mu.Lock()
	defer c.mu.Unlock()

	return c.computations[key]
}

// set adds a computation to the cache for the given key
func (c *cache) set(key interface{}, computation *computation) {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.computations[key] == nil {
		c.computations[key] = computation
	}
}

func (c *cache) cleanInvalidated() {
	c.mu.Lock()
	defer c.mu.Unlock()

	for key, computation := range c.computations {
		if computation.node.Invalidated() {
			delete(c.computations, key)
		}
	}
}

// PurgeCache is meant to be use as a transition off of using the reactive cache.
// It allows slowly removing caching whenever the user wants, ideally between
// cache execution runs.
func PurgeCache(ctx context.Context) {
	cVal := ctx.Value(cacheKey{})
	if cVal == nil {
		return
	}
	c, ok := cVal.(*cache)
	if !ok {
		return
	}
	c.purgeCache()
}

func (c *cache) purgeCache() {
	c.mu.Lock()
	defer c.mu.Unlock()

	c.computations = make(map[interface{}]*computation)
}

// Resource represents a leaf-level dependency in a computation
type Resource struct {
	node
}

// NewResource creates a new Resource
func NewResource() *Resource {
	return &Resource{
		node: node{},
	}
}

// Invalidate permanently invalidates r
func (r *Resource) Invalidate() {
	go r.invalidate()
}

// Store invalidates all computations currently depending on r
func (r *Resource) Strobe() {
	go r.strobe()
}

// Cleanup registers a handler to be called when all computations using r stop
//
// NOTE: For f to be called, at least one computation must AddDependency r!
func (r *Resource) Cleanup(f func()) {
	r.node.handleRelease(f)
}

type computationKey struct{}
type cacheKey struct{}

type dependencySetKey struct{}

type dependencySet struct {
	mu           sync.Mutex
	dependencies []Dependency
}

func (ds *dependencySet) add(dep Dependency) {
	ds.mu.Lock()
	defer ds.mu.Unlock()
	ds.dependencies = append(ds.dependencies, dep)
}

func (ds *dependencySet) get() []Dependency {
	ds.mu.Lock()
	defer ds.mu.Unlock()
	return ds.dependencies
}

type Dependency interface{}

type DependencyCallbackFunc func(context.Context, Dependency)

type dependencyCallbackKey struct{}

func AddDependency(ctx context.Context, r *Resource, dep Dependency) {
	if !HasRerunner(ctx) {
		r.node.addOut(&node{released: true})
		return
	}

	computation := ctx.Value(computationKey{}).(*computation)
	r.node.addOut(&computation.node)

	if dep != nil {
		depSet, ok := ctx.Value(dependencySetKey{}).(*dependencySet)
		if ok && depSet != nil {
			depSet.add(dep)
		}
		if callback, ok := ctx.Value(dependencyCallbackKey{}).(DependencyCallbackFunc); ok && callback != nil {
			callback(ctx, dep)
		}
	}
}

// WithDependencyCallback registers a callback that is invoked when
// AddDependency is called with non-nil serializable dependency.
func WithDependencyCallback(ctx context.Context, f DependencyCallbackFunc) context.Context {
	return context.WithValue(ctx, dependencyCallbackKey{}, f)
}

func Dependencies(ctx context.Context) []Dependency {
	depSet := ctx.Value(dependencySetKey{}).(*dependencySet)
	if depSet == nil {
		return nil
	}
	return depSet.get()
}

type ComputeFunc func(context.Context) (interface{}, error)

func run(ctx context.Context, f ComputeFunc) (*computation, error) {
	// build result computation and local computation Ctx
	c := &computation{
		// this node will be freed either when the computation fails, or by our
		// caller
		node: node{},
	}

	childCtx := context.WithValue(ctx, computationKey{}, c)

	// Compute f and write the results to the c
	value, err := f(childCtx)
	if err != nil {
		go c.node.release()
		return nil, err
	}

	c.value = value

	return c, nil
}

func Cache(ctx context.Context, key interface{}, f ComputeFunc) (interface{}, error) {
	if !HasRerunner(ctx) {
		val, err := f(ctx)
		return val, err
	}

	cache := ctx.Value(cacheKey{}).(*cache)
	computation := ctx.Value(computationKey{}).(*computation)

	if err := cache.locker.Lock(ctx, key); err != nil {
		return nil, err
	}
	defer cache.locker.Unlock(key)

	if child := cache.get(key); child != nil {
		child.node.addOut(&computation.node)
		return child.value, nil
	}

	child, err := run(ctx, f)
	if err != nil {
		return nil, err
	}
	cache.set(key, child)

	child.node.addOut(&computation.node)
	return child.value, nil
}

// Rerunner automatically reruns a computation whenever its dependencies
// change.
//
// The computation stops when it returns an error or after calling Stop.  There
// is no way to get the output value from a computation. Instead, the
// computation should communicate its result before returning.
type Rerunner struct {
	ctx       context.Context
	cancelCtx context.CancelFunc

	f                    ComputeFunc
	cache                *cache
	minRerunInterval     time.Duration
	retryDelay           time.Duration
	alwaysSpawnGoroutine bool

	// flushed tracks if the next computation should run without delay. It is set
	// to false as soon as the next computation starts. flushCh is closed when
	// flushed is set to true.
	flushMu sync.Mutex
	flushCh chan struct{}
	flushed bool

	mu          sync.Mutex
	computation *computation
	stop        bool

	lastRun time.Time
}

// NewRerunner runs f continuously
func NewRerunner(ctx context.Context, f ComputeFunc, minRerunInterval time.Duration, alwaysSpawnGoroutine bool) *Rerunner {
	ctx, cancelCtx := context.WithCancel(ctx)

	r := &Rerunner{
		ctx:       ctx,
		cancelCtx: cancelCtx,

		f: f,
		cache: &cache{
			computations: make(map[interface{}]*computation),
			locker:       newLocker(),
		},
		minRerunInterval:     minRerunInterval,
		retryDelay:           minRerunInterval,
		alwaysSpawnGoroutine: alwaysSpawnGoroutine,

		flushCh: make(chan struct{}, 0),
	}
	go r.run()
	return r
}

// RerunImmediately removes the delay from the next recomputation.
func (r *Rerunner) RerunImmediately() {
	r.flushMu.Lock()
	defer r.flushMu.Unlock()

	if !r.flushed {
		close(r.flushCh)
		r.flushed = true
	}
}

// run performs an actual computation
func (r *Rerunner) run() {
	// Wait for the minimum rerun interval. Exit early if the computation is stopped.
	delta := r.retryDelay - time.Now().Sub(r.lastRun)

	t := time.NewTimer(delta)
	select {
	case <-r.ctx.Done():
	case <-t.C:
	case <-r.flushCh:
	}
	t.Stop()
	if r.ctx.Err() != nil {
		return
	}

	r.flushMu.Lock()
	if r.flushed {
		r.flushCh = make(chan struct{}, 0)
		r.flushed = false
	}
	r.flushMu.Unlock()

	r.mu.Lock()
	defer r.mu.Unlock()

	// Bail out if the computation has been stopped.
	if r.stop {
		return
	}

	if !r.lastRun.IsZero() {
		// Delay the rerun in order to emulate write-then-read consistency.
		time.Sleep(WriteThenReadDelay)
	}
	r.cache.cleanInvalidated()

	// Cancel the context passed to "run". Canceling the context ensures that
	// libraries let go of the context when they might otherwise hold onto it long
	// past this run.
	ctx, cancel := context.WithCancel(r.ctx)
	defer cancel()
	ctx = context.WithValue(ctx, cacheKey{}, r.cache)
	ctx = context.WithValue(ctx, dependencySetKey{}, &dependencySet{})

	currentComputation, err := run(ctx, r.f)
	r.lastRun = time.Now()
	if err != nil {
		if err != RetrySentinelError {
			// If we encountered an error that is not the retry sentinel,
			// we should stop the rerunner.
			return
		}
		// Reset the cache for sentinel errors so we get a clean slate.
		r.cache.purgeCache()

		r.retryDelay = r.retryDelay * 2

		// Max out the retry delay to at 1 minute.
		if r.retryDelay > time.Minute {
			r.retryDelay = time.Minute
		}
		go r.run()
	} else {
		// If we succeeded in the computation, we can release the old computation
		// and reset the retry delay.
		if r.computation != nil {
			go r.computation.node.release()
			r.computation = nil
		}

		r.computation = currentComputation
		r.retryDelay = r.minRerunInterval

		// Schedule a rerun whenever our node becomes invalidated (which might already
		// have happened!)
		currentComputation.node.handleInvalidate(func() {
			if r.alwaysSpawnGoroutine {
				go r.run()
			} else {
				r.run()
			}
		})
	}
}

func (r *Rerunner) Stop() {
	// Call cancelCtx before acquiring the lock as the lock might be held for a long time during a running computation.
	r.cancelCtx()

	r.mu.Lock()
	r.stop = true
	if r.computation != nil {
		go r.computation.node.release()
		r.computation = nil
	}
	r.mu.Unlock()
}

func HasRerunner(ctx context.Context) bool {
	return ctx.Value(computationKey{}) != nil
}
<|endoftext|>


<commit_before>// +build integration

package recipes

import (
	"flag"
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/betable/ezk"
	"github.com/samuel/go-zookeeper/zk"
)

var testClient *ezk.Client
var acl = zk.WorldACL(zk.PermAll)

func TestLock(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)

	// Simple
	if err := l1.Lock(); err != nil {
		t.Fatal(err)
	}
	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}

	ch := make(chan int, 3)

	// Two locks
	if err := l1.Lock(); err != nil {
		t.Fatal(err)
	}

	go func() {
		if err := l2.Lock(); err != nil {
			t.Fatal(err)
		}
		ch <- 2
		if err := l2.Unlock(); err != nil {
			t.Fatal(err)
		}
		ch <- 3
	}()

	time.Sleep(time.Millisecond * 100)

	ch <- 1
	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}
	if x := <-ch; x != 1 {
		t.Fatalf("Expected 1 instead of %d", x)
	}
	if x := <-ch; x != 2 {
		t.Fatalf("Expected 2 instead of %d", x)
	}
	if x := <-ch; x != 3 {
		t.Fatalf("Expected 3 instead of %d", x)
	}
}

func TestLockWithCleaner(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)
	l2.WithCleaner(100 * time.Millisecond)

	ch := make(chan int, 3)

	// Two locks
	if err := l1.Lock(); err != nil {
		t.Fatal(err)
	}

	time.Sleep(100 * time.Millisecond)

	go func() {
		if err := l2.Lock(); err != nil {
			t.Fatal(err)
		}
		ch <- 1
		if err := l2.Unlock(); err != nil {
			t.Fatal(err)
		}
		ch <- 2
	}()

	if x := <-ch; x != 1 {
		t.Fatalf("Expected 1 instead of %d", x)
	}
	if x := <-ch; x != 2 {
		t.Fatalf("Expected 2 instead of %d", x)
	}
	if err := l1.Unlock(); err != zk.ErrNoNode {
		t.Fatal("Expected zk.ErrNoNode instead of %v", err)
	}
}

func TestTryLock(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)

	// Simple
	if err := l1.TryLock(); err != nil {
		t.Fatal(err)
	}
	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}

	ch := make(chan struct{})

	// Two locks
	if err := l1.TryLock(); err != nil {
		t.Fatal(err)
	}

	go func() {
		if err := l2.TryLock(); err != ErrLockFound {
			t.Fatalf("Expected ErrLockFound instead of %v", err)
		}
		ch <- struct{}{}
	}()

	time.Sleep(time.Millisecond * 100)

	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}
	// Wait for goroutine
	<-ch
}

func TestTryLockWithCleaner(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)
	l2.WithCleaner(100 * time.Millisecond)

	ch := make(chan struct{})

	// Two locks
	if err := l1.TryLock(); err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 100)

	go func() {
		if err := l2.TryLock(); err != nil {
			t.Fatalf("Expected nil instead of %v", err)
		}
		ch <- struct{}{}
	}()

	// Wait for goroutine
	<-ch

	if err := l1.Unlock(); err != zk.ErrNoNode {
		t.Fatal("Expected zk.ErrNoNode instead of %v", err)
	}
}

func TestMain(m *testing.M) {
	flag.Parse()
	cfg := ezk.ClientConfig{
		Chroot:  "/ezk",
		Servers: []string{"127.0.0.1:2181"},
	}
	testClient = ezk.NewClient(cfg)
	if err := testClient.Connect(); err != nil {
		fmt.Fprintf(os.Stderr, "Error connecting zookeeper: %s", err.Error())
		os.Exit(1)
	}
	result := m.Run()
	testClient.Close()
	os.Exit(result)
}
<commit_msg>run test without needing +build integration<commit_after>package recipes

import (
	"flag"
	"fmt"
	"os"
	"testing"
	"time"

	"github.com/betable/ezk"
	"github.com/samuel/go-zookeeper/zk"
)

var testClient *ezk.Client
var acl = zk.WorldACL(zk.PermAll)

func TestLock(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)

	// Simple
	if err := l1.Lock(); err != nil {
		t.Fatal(err)
	}
	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}

	ch := make(chan int, 3)

	// Two locks
	if err := l1.Lock(); err != nil {
		t.Fatal(err)
	}

	go func() {
		if err := l2.Lock(); err != nil {
			t.Fatal(err)
		}
		ch <- 2
		if err := l2.Unlock(); err != nil {
			t.Fatal(err)
		}
		ch <- 3
	}()

	time.Sleep(time.Millisecond * 100)

	ch <- 1
	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}
	if x := <-ch; x != 1 {
		t.Fatalf("Expected 1 instead of %d", x)
	}
	if x := <-ch; x != 2 {
		t.Fatalf("Expected 2 instead of %d", x)
	}
	if x := <-ch; x != 3 {
		t.Fatalf("Expected 3 instead of %d", x)
	}
}

func TestLockWithCleaner(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)
	l2.WithCleaner(100 * time.Millisecond)

	ch := make(chan int, 3)

	// Two locks
	if err := l1.Lock(); err != nil {
		t.Fatal(err)
	}

	time.Sleep(100 * time.Millisecond)

	go func() {
		if err := l2.Lock(); err != nil {
			t.Fatal(err)
		}
		ch <- 1
		if err := l2.Unlock(); err != nil {
			t.Fatal(err)
		}
		ch <- 2
	}()

	if x := <-ch; x != 1 {
		t.Fatalf("Expected 1 instead of %d", x)
	}
	if x := <-ch; x != 2 {
		t.Fatalf("Expected 2 instead of %d", x)
	}
	if err := l1.Unlock(); err != zk.ErrNoNode {
		t.Fatal("Expected zk.ErrNoNode instead of %v", err)
	}
}

func TestTryLock(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)

	// Simple
	if err := l1.TryLock(); err != nil {
		t.Fatal(err)
	}
	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}

	ch := make(chan struct{})

	// Two locks
	if err := l1.TryLock(); err != nil {
		t.Fatal(err)
	}

	go func() {
		if err := l2.TryLock(); err != ErrLockFound {
			t.Fatalf("Expected ErrLockFound instead of %v", err)
		}
		ch <- struct{}{}
	}()

	time.Sleep(time.Millisecond * 100)

	if err := l1.Unlock(); err != nil {
		t.Fatal(err)
	}
	// Wait for goroutine
	<-ch
}

func TestTryLockWithCleaner(t *testing.T) {
	defer testClient.DeleteNodeRecursively("testlock")

	l1 := NewLock(testClient, "testlock", acl)
	l2 := NewLock(testClient, "testlock", acl)
	l2.WithCleaner(100 * time.Millisecond)

	ch := make(chan struct{})

	// Two locks
	if err := l1.TryLock(); err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 100)

	go func() {
		if err := l2.TryLock(); err != nil {
			t.Fatalf("Expected nil instead of %v", err)
		}
		ch <- struct{}{}
	}()

	// Wait for goroutine
	<-ch

	if err := l1.Unlock(); err != zk.ErrNoNode {
		t.Fatal("Expected zk.ErrNoNode instead of %v", err)
	}
}

func TestMain(m *testing.M) {
	flag.Parse()
	cfg := ezk.ClientConfig{
		Chroot:  "/ezk",
		Servers: []string{"127.0.0.1:2181"},
	}
	testClient = ezk.NewClient(cfg)
	if err := testClient.Connect(); err != nil {
		fmt.Fprintf(os.Stderr, "Error connecting zookeeper: %s", err.Error())
		os.Exit(1)
	}
	result := m.Run()
	testClient.Close()
	os.Exit(result)
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"time"

	"github.com/koding/bongo"
)

type MessageReply struct {
	// unique identifier of the MessageReply
	Id int64 `json:"id"`

	// Id of the interacted message
	MessageId int64 `json:"messageId"`

	// Id of the reply
	ReplyId int64 `json:"replyId"`

	// Creation of the MessageReply
	CreatedAt time.Time `json:"createdAt"`
}

func (m *MessageReply) GetId() int64 {
	return m.Id
}

func (m *MessageReply) TableName() string {
	return "message_reply"
}

func (m *MessageReply) Self() bongo.Modellable {
	return m
}

func NewMessageReply() *MessageReply {
	return &MessageReply{}
}

func (m *MessageReply) Fetch() error {
	return bongo.B.Fetch(m)
}

func (m *MessageReply) Create() error {
	return bongo.B.Create(m)
}

func (m *MessageReply) Delete() error {
	if err := bongo.B.DB.
		Where("message_id = ? and reply_id = ?", m.MessageId, m.ReplyId).
		Delete(m.Self()).Error; err != nil {
		return err
	}
	return nil
}

func (m *MessageReply) List() ([]ChannelMessage, error) {
	var replies []int64

	if m.MessageId == 0 {
		return nil, errors.New("MessageId is not set")
	}

	if err := bongo.B.DB.Table(m.TableName()).
		Where("message_id = ?", m.MessageId).
		Pluck("reply_id", &replies).
		Error; err != nil {
		return nil, err
	}

	parent := NewChannelMessage()
	channelMessageReplies, err := parent.FetchByIds(replies)
	if err != nil {
		return nil, err
	}

	return channelMessageReplies, nil
}
<commit_msg>Social: add plugins for realtime events<commit_after>package models

import (
	"errors"
	"time"

	"github.com/koding/bongo"
)

type MessageReply struct {
	// unique identifier of the MessageReply
	Id int64 `json:"id"`

	// Id of the interacted message
	MessageId int64 `json:"messageId"`

	// Id of the reply
	ReplyId int64 `json:"replyId"`

	// Creation of the MessageReply
	CreatedAt time.Time `json:"createdAt"`
}

func (m *MessageReply) GetId() int64 {
	return m.Id
}

func (m *MessageReply) TableName() string {
	return "message_reply"
}

func (m *MessageReply) Self() bongo.Modellable {
	return m
}

func NewMessageReply() *MessageReply {
	return &MessageReply{}
}

func (m *MessageReply) AfterCreate() {
	bongo.B.AfterCreate(m)
}

func (m *MessageReply) AfterUpdate() {
	bongo.B.AfterUpdate(m)
}

func (m *MessageReply) AfterDelete() {
	bongo.B.AfterDelete(m)
}

func (m *MessageReply) Fetch() error {
	return bongo.B.Fetch(m)
}

func (m *MessageReply) Create() error {
	return bongo.B.Create(m)
}

func (m *MessageReply) Delete() error {
	if err := bongo.B.DB.
		Where("message_id = ? and reply_id = ?", m.MessageId, m.ReplyId).
		Delete(m.Self()).Error; err != nil {
		return err
	}
	return nil
}

func (m *MessageReply) List() ([]ChannelMessage, error) {
	var replies []int64

	if m.MessageId == 0 {
		return nil, errors.New("MessageId is not set")
	}

	if err := bongo.B.DB.Table(m.TableName()).
		Where("message_id = ?", m.MessageId).
		Pluck("reply_id", &replies).
		Error; err != nil {
		return nil, err
	}

	parent := NewChannelMessage()
	channelMessageReplies, err := parent.FetchByIds(replies)
	if err != nil {
		return nil, err
	}

	return channelMessageReplies, nil
}
<|endoftext|>


<commit_before>package summultiples

import "fmt"

func SumMultiples(limit int, divisors ...int) (sum int) {
	multiples := getMultiples(limit, divisors)
	for multiple := range multiples {
		sum += multiple
	}
	return sum
}

func getMultiples(limit int, divisors []int) (multiples map[int]bool) {
	multiples = map[int]bool{}
	for _, divisor := range divisors {
		multiplesForDivisor := getMultiplesForDivisor(limit, divisor)
		for _, multiple := range multiplesForDivisor {
			multiples[multiple] = true
		}
	}
	return multiples
}

func getMultiplesForDivisor(limit int, divisor int) (multiples []int) {
	if divisor == 0 {
		return multiples
	}
	multiplyer := 1
	candidate := divisor * multiplyer
	for candidate < limit {
		fmt.Printf("candidate %d, multiplyer %d, limit %d\n", candidate, multiplyer, limit)
		multiples = append(multiples, candidate)
		multiplyer += 1
		candidate = divisor * multiplyer
	}
	fmt.Printf("returning multiples %v\n", multiples)
	return multiples
}
<commit_msg>Minor rename<commit_after>package summultiples

func SumMultiples(limit int, divisors ...int) (sum int) {
	multiples := getMultiples(limit, divisors)
	for multiple := range multiples {
		sum += multiple
	}
	return sum
}

func getMultiples(limit int, divisors []int) (set map[int]bool) {
	set = map[int]bool{}
	for _, divisor := range divisors {
		multiples := getMultiplesForDivisor(limit, divisor)
		for _, multiple := range multiples {
			set[multiple] = true
		}
	}
	return set
}

func getMultiplesForDivisor(limit int, divisor int) (multiples []int) {
	if divisor == 0 {
		return multiples
	}
	multiplyer := 1
	candidate := divisor * multiplyer
	for candidate < limit {
		multiples = append(multiples, candidate)
		multiplyer += 1
		candidate = divisor * multiplyer
	}
	return multiples
}
<|endoftext|>