<commit_before>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

package download

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/hashicorp/go-getter"
	"github.com/juju/mutex"
	"github.com/pkg/errors"
	"k8s.io/klog/v2"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/style"
	"k8s.io/minikube/pkg/util/lock"
)

var (
	// DownloadMock is called instead of the download implementation if not nil.
	DownloadMock func(src, dst string) error = nil
	checkCache                               = os.Stat
)

// CreateDstDownloadMock is the default mock implementation of download.
func CreateDstDownloadMock(src, dst string) error {
	if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		return errors.Wrap(err, "mkdir")
	}

	_, err := os.Create(dst)
	return err
}

// download is a well-configured atomic download function
func download(src string, dst string) error {
	progress := getter.WithProgress(DefaultProgressBar)
	if out.JSON {
		progress = getter.WithProgress(DefaultJSONOutput)
	}
	tmpDst := dst + ".download"
	client := &getter.Client{
		Src:     src,
		Dst:     tmpDst,
		Dir:     false,
		Mode:    getter.ClientModeFile,
		Options: []getter.ClientOption{progress},
		Getters: map[string]getter.Getter{
			"file":  &getter.FileGetter{Copy: false},
			"http":  &getter.HttpGetter{Netrc: false},
			"https": &getter.HttpGetter{Netrc: false},
		},
	}

	if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		return errors.Wrap(err, "mkdir")
	}

	if DownloadMock != nil {
		klog.Infof("Mock download: %s -> %s", src, dst)
		return DownloadMock(src, dst)
	}

	// Politely prevent tests from shooting themselves in the foot
	if withinUnitTest() {
		return fmt.Errorf("unmocked download under test")
	}

	klog.Infof("Downloading: %s -> %s", src, dst)
	if err := client.Get(); err != nil {
		return errors.Wrapf(err, "getter: %+v", client)
	}
	return os.Rename(tmpDst, dst)
}

// withinUnitTset detects if we are in running within a unit-test
func withinUnitTest() bool {
	// Nope, it's the integration test
	if flag.Lookup("minikube-start-args") != nil || strings.HasPrefix(filepath.Base(os.Args[0]), "e2e-") {
		return false
	}

	return flag.Lookup("test.v") != nil || strings.HasSuffix(os.Args[0], "test")
}

// lockDownload locks `file` if possible and returns a releaser that must be called to release the lock.
func lockDownload(file string) (mutex.Releaser, error) {
	type retPair struct {
		mutex.Releaser
		error
	}
	lockChannel := make(chan retPair)

	go func() {
		spec := lock.PathMutexSpec(file)
		releaser, err := mutex.Acquire(spec)
		if err != nil {
			lockChannel <- retPair{nil, errors.Wrapf(err, "failed to acquire lock \"%s\": %+v", file, spec)}
			return
		}
		lockChannel <- retPair{releaser, err}
	}()

	select {
	case r := <-lockChannel:
		return r.Releaser, r.error
	case <-time.After(time.Millisecond * 100):
		out.Step(style.WaitingWithSpinner, "Another minikube instance is downloading dependencies... ")
	}

	r := <-lockChannel
	return r.Releaser, r.error
}
<commit_msg>Add comment to explain lock wait timeout.<commit_after>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

package download

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/hashicorp/go-getter"
	"github.com/juju/mutex"
	"github.com/pkg/errors"
	"k8s.io/klog/v2"
	"k8s.io/minikube/pkg/minikube/out"
	"k8s.io/minikube/pkg/minikube/style"
	"k8s.io/minikube/pkg/util/lock"
)

var (
	// DownloadMock is called instead of the download implementation if not nil.
	DownloadMock func(src, dst string) error = nil
	checkCache                               = os.Stat
)

// CreateDstDownloadMock is the default mock implementation of download.
func CreateDstDownloadMock(src, dst string) error {
	if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		return errors.Wrap(err, "mkdir")
	}

	_, err := os.Create(dst)
	return err
}

// download is a well-configured atomic download function
func download(src string, dst string) error {
	progress := getter.WithProgress(DefaultProgressBar)
	if out.JSON {
		progress = getter.WithProgress(DefaultJSONOutput)
	}
	tmpDst := dst + ".download"
	client := &getter.Client{
		Src:     src,
		Dst:     tmpDst,
		Dir:     false,
		Mode:    getter.ClientModeFile,
		Options: []getter.ClientOption{progress},
		Getters: map[string]getter.Getter{
			"file":  &getter.FileGetter{Copy: false},
			"http":  &getter.HttpGetter{Netrc: false},
			"https": &getter.HttpGetter{Netrc: false},
		},
	}

	if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
		return errors.Wrap(err, "mkdir")
	}

	if DownloadMock != nil {
		klog.Infof("Mock download: %s -> %s", src, dst)
		return DownloadMock(src, dst)
	}

	// Politely prevent tests from shooting themselves in the foot
	if withinUnitTest() {
		return fmt.Errorf("unmocked download under test")
	}

	klog.Infof("Downloading: %s -> %s", src, dst)
	if err := client.Get(); err != nil {
		return errors.Wrapf(err, "getter: %+v", client)
	}
	return os.Rename(tmpDst, dst)
}

// withinUnitTset detects if we are in running within a unit-test
func withinUnitTest() bool {
	// Nope, it's the integration test
	if flag.Lookup("minikube-start-args") != nil || strings.HasPrefix(filepath.Base(os.Args[0]), "e2e-") {
		return false
	}

	return flag.Lookup("test.v") != nil || strings.HasSuffix(os.Args[0], "test")
}

// lockDownload locks `file` if possible and returns a releaser that must be called to release the lock.
func lockDownload(file string) (mutex.Releaser, error) {
	type retPair struct {
		mutex.Releaser
		error
	}
	lockChannel := make(chan retPair)

	go func() {
		spec := lock.PathMutexSpec(file)
		releaser, err := mutex.Acquire(spec)
		if err != nil {
			lockChannel <- retPair{nil, errors.Wrapf(err, "failed to acquire lock \"%s\": %+v", file, spec)}
			return
		}
		lockChannel <- retPair{releaser, err}
	}()

	select {
	case r := <-lockChannel:
		return r.Releaser, r.error
	case <-time.After(time.Millisecond * 100):
		out.Step(style.WaitingWithSpinner, "Another minikube instance is downloading dependencies... ")
	}

	// lock.PathMutexSpec returns a spec including a 60s timeout. Therefore, this
	// will not block indefinitely.
	r := <-lockChannel
	return r.Releaser, r.error
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 etcd3

import (
	"errors"
	"fmt"
	"reflect"
	"sync"
	"testing"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/integration"
	"golang.org/x/net/context"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/storage"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/watch"
)

func TestWatch(t *testing.T) {
	testWatch(t, false)
}

func TestWatchList(t *testing.T) {
	testWatch(t, true)
}

// It tests that
// - first occurrence of objects should notify Add event
// - update should trigger Modified event
// - update that gets filtered should trigger Deleted event
func testWatch(t *testing.T, recursive bool) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)

	podFoo := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
	podBar := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}}

	tests := []struct {
		key        string
		filter     func(runtime.Object) bool
		trigger    func() []storage.MatchValue
		watchTests []*testWatchStruct
	}{{ // create a key
		key:        "/somekey-1",
		watchTests: []*testWatchStruct{{podFoo, true, watch.Added}},
		filter:     storage.EverythingFunc,
		trigger:    storage.NoTriggerFunc,
	}, { // create a key but obj gets filtered
		key:        "/somekey-2",
		watchTests: []*testWatchStruct{{podFoo, false, ""}},
		filter:     func(runtime.Object) bool { return false },
		trigger:    storage.NoTriggerFunc,
	}, { // create a key but obj gets filtered. Then update it with unfiltered obj
		key:        "/somekey-3",
		watchTests: []*testWatchStruct{{podFoo, false, ""}, {podBar, true, watch.Added}},
		filter: func(obj runtime.Object) bool {
			pod := obj.(*api.Pod)
			return pod.Name == "bar"
		},
		trigger: storage.NoTriggerFunc,
	}, { // update
		key:        "/somekey-4",
		watchTests: []*testWatchStruct{{podFoo, true, watch.Added}, {podBar, true, watch.Modified}},
		filter:     storage.EverythingFunc,
		trigger:    storage.NoTriggerFunc,
	}, { // delete because of being filtered
		key:        "/somekey-5",
		watchTests: []*testWatchStruct{{podFoo, true, watch.Added}, {podBar, true, watch.Deleted}},
		filter: func(obj runtime.Object) bool {
			pod := obj.(*api.Pod)
			return pod.Name != "bar"
		},
		trigger: storage.NoTriggerFunc,
	}}
	for i, tt := range tests {
		filter := storage.NewSimpleFilter(tt.filter, tt.trigger)
		w, err := store.watch(ctx, tt.key, "0", filter, recursive)
		if err != nil {
			t.Fatalf("Watch failed: %v", err)
		}
		var prevObj *api.Pod
		for _, watchTest := range tt.watchTests {
			out := &api.Pod{}
			key := tt.key
			if recursive {
				key = key + "/item"
			}
			err := store.GuaranteedUpdate(ctx, key, out, true, nil, storage.SimpleUpdate(
				func(runtime.Object) (runtime.Object, error) {
					return watchTest.obj, nil
				}))
			if err != nil {
				t.Fatalf("GuaranteedUpdate failed: %v", err)
			}
			if watchTest.expectEvent {
				expectObj := out
				if watchTest.watchType == watch.Deleted {
					expectObj = prevObj
					expectObj.ResourceVersion = out.ResourceVersion
				}
				testCheckResult(t, i, watchTest.watchType, w, expectObj)
			}
			prevObj = out
		}
		w.Stop()
		testCheckStop(t, i, w)
	}
}

func TestDeleteTriggerWatch(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})
	w, err := store.Watch(ctx, key, storedObj.ResourceVersion, storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	if err := store.Delete(ctx, key, &api.Pod{}, nil); err != nil {
		t.Fatalf("Delete failed: %v", err)
	}
	testCheckEventType(t, watch.Deleted, w)
}

// TestWatchFromZero tests that
// - watch from 0 should sync up and grab the object added before
// - watch from non-0 should just watch changes after given version
func TestWatchFromZero(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})

	w, err := store.Watch(ctx, key, "0", storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	testCheckResult(t, 0, watch.Added, w, storedObj)
}

// TestWatchFromNoneZero tests that
// - watch from non-0 should just watch changes after given version
func TestWatchFromNoneZero(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})

	w, err := store.Watch(ctx, key, storedObj.ResourceVersion, storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	out := &api.Pod{}
	store.GuaranteedUpdate(ctx, key, out, true, nil, storage.SimpleUpdate(
		func(runtime.Object) (runtime.Object, error) {
			return &api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}}, err
		}))
	testCheckResult(t, 0, watch.Modified, w, out)
}

func TestWatchError(t *testing.T) {
	cluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer cluster.Terminate(t)
	invalidStore := newStore(cluster.RandClient(), &testCodec{testapi.Default.Codec()}, "")
	ctx := context.Background()
	w, err := invalidStore.Watch(ctx, "/abc", "0", storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	validStore := newStore(cluster.RandClient(), testapi.Default.Codec(), "")
	validStore.GuaranteedUpdate(ctx, "/abc", &api.Pod{}, true, nil, storage.SimpleUpdate(
		func(runtime.Object) (runtime.Object, error) {
			return &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}, nil
		}))
	testCheckEventType(t, watch.Error, w)
}

func TestWatchContextCancel(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	canceledCtx, cancel := context.WithCancel(ctx)
	cancel()
	w := store.watcher.createWatchChan(canceledCtx, "/abc", 0, false, storage.Everything)
	// When we do a client.Get with a canceled context, it will return error.
	// Nonetheless, when we try to send it over internal errChan, we should detect
	// it's context canceled and not send it.
	err := w.sync()
	w.ctx = ctx
	w.sendError(err)
	select {
	case err := <-w.errChan:
		t.Errorf("cancelling context shouldn't return any error. Err: %v", err)
	default:
	}
}

func TestWatchErrResultNotBlockAfterCancel(t *testing.T) {
	origCtx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	ctx, cancel := context.WithCancel(origCtx)
	w := store.watcher.createWatchChan(ctx, "/abc", 0, false, storage.Everything)
	// make resutlChan and errChan blocking to ensure ordering.
	w.resultChan = make(chan watch.Event)
	w.errChan = make(chan error)
	// The event flow goes like:
	// - first we send an error, it should block on resultChan.
	// - Then we cancel ctx. The blocking on resultChan should be freed up
	//   and run() goroutine should return.
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		w.run()
		wg.Done()
	}()
	w.errChan <- fmt.Errorf("some error")
	cancel()
	wg.Wait()
}

func TestWatchDeleteEventObjectHaveLatestRV(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})

	w, err := store.Watch(ctx, key, storedObj.ResourceVersion, storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	etcdW := cluster.RandClient().Watch(ctx, "/", clientv3.WithPrefix())

	if err := store.Delete(ctx, key, &api.Pod{}, &storage.Preconditions{}); err != nil {
		t.Fatalf("Delete failed: %v", err)
	}

	e := <-w.ResultChan()
	watchedDeleteObj := e.Object.(*api.Pod)
	var wres clientv3.WatchResponse
	wres = <-etcdW

	watchedDeleteRev, err := storage.ParseWatchResourceVersion(watchedDeleteObj.ResourceVersion)
	if err != nil {
		t.Fatalf("ParseWatchResourceVersion failed: %v", err)
	}
	if int64(watchedDeleteRev) != wres.Events[0].Kv.ModRevision {
		t.Errorf("Object from delete event have version: %v, should be the same as etcd delete's mod rev: %d",
			watchedDeleteRev, wres.Events[0].Kv.ModRevision)
	}
}

type testWatchStruct struct {
	obj         *api.Pod
	expectEvent bool
	watchType   watch.EventType
}

type testCodec struct {
	runtime.Codec
}

func (c *testCodec) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
	return nil, nil, errors.New("Expected decoding failure")
}

func testCheckEventType(t *testing.T, expectEventType watch.EventType, w watch.Interface) {
	select {
	case res := <-w.ResultChan():
		if res.Type != expectEventType {
			t.Errorf("event type want=%v, get=%v", expectEventType, res.Type)
		}
	case <-time.After(wait.ForeverTestTimeout):
		t.Errorf("time out after waiting %v on ResultChan", wait.ForeverTestTimeout)
	}
}

func testCheckResult(t *testing.T, i int, expectEventType watch.EventType, w watch.Interface, expectObj *api.Pod) {
	select {
	case res := <-w.ResultChan():
		if res.Type != expectEventType {
			t.Errorf("#%d: event type want=%v, get=%v", i, expectEventType, res.Type)
			return
		}
		if !reflect.DeepEqual(expectObj, res.Object) {
			t.Errorf("#%d: obj want=\n%#v\nget=\n%#v", i, expectObj, res.Object)
		}
	case <-time.After(wait.ForeverTestTimeout):
		t.Errorf("#%d: time out after waiting %v on ResultChan", i, wait.ForeverTestTimeout)
	}
}

func testCheckStop(t *testing.T, i int, w watch.Interface) {
	select {
	case e, ok := <-w.ResultChan():
		if ok {
			var obj string
			switch e.Object.(type) {
			case *api.Pod:
				obj = e.Object.(*api.Pod).Name
			case *unversioned.Status:
				obj = e.Object.(*unversioned.Status).Message
			}
			t.Errorf("#%d: ResultChan should have been closed. Event: %s. Object: %s", i, e.Type, obj)
		}
	case <-time.After(wait.ForeverTestTimeout):
		t.Errorf("#%d: time out after waiting 1s on ResultChan", i)
	}
}
<commit_msg>unshare cluster, store in each test suite<commit_after>/*
Copyright 2016 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 etcd3

import (
	"errors"
	"fmt"
	"reflect"
	"sync"
	"testing"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/integration"
	"golang.org/x/net/context"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/storage"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/watch"
)

func TestWatch(t *testing.T) {
	testWatch(t, false)
}

func TestWatchList(t *testing.T) {
	testWatch(t, true)
}

// It tests that
// - first occurrence of objects should notify Add event
// - update should trigger Modified event
// - update that gets filtered should trigger Deleted event
func testWatch(t *testing.T, recursive bool) {
	podFoo := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}
	podBar := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}}

	tests := []struct {
		key        string
		filter     func(runtime.Object) bool
		trigger    func() []storage.MatchValue
		watchTests []*testWatchStruct
	}{{ // create a key
		key:        "/somekey-1",
		watchTests: []*testWatchStruct{{podFoo, true, watch.Added}},
		filter:     storage.EverythingFunc,
		trigger:    storage.NoTriggerFunc,
	}, { // create a key but obj gets filtered
		key:        "/somekey-2",
		watchTests: []*testWatchStruct{{podFoo, false, ""}},
		filter:     func(runtime.Object) bool { return false },
		trigger:    storage.NoTriggerFunc,
	}, { // create a key but obj gets filtered. Then update it with unfiltered obj
		key:        "/somekey-3",
		watchTests: []*testWatchStruct{{podFoo, false, ""}, {podBar, true, watch.Added}},
		filter: func(obj runtime.Object) bool {
			pod := obj.(*api.Pod)
			return pod.Name == "bar"
		},
		trigger: storage.NoTriggerFunc,
	}, { // update
		key:        "/somekey-4",
		watchTests: []*testWatchStruct{{podFoo, true, watch.Added}, {podBar, true, watch.Modified}},
		filter:     storage.EverythingFunc,
		trigger:    storage.NoTriggerFunc,
	}, { // delete because of being filtered
		key:        "/somekey-5",
		watchTests: []*testWatchStruct{{podFoo, true, watch.Added}, {podBar, true, watch.Deleted}},
		filter: func(obj runtime.Object) bool {
			pod := obj.(*api.Pod)
			return pod.Name != "bar"
		},
		trigger: storage.NoTriggerFunc,
	}}
	for i, tt := range tests {
		ctx, store, cluster := testSetup(t)
		filter := storage.NewSimpleFilter(tt.filter, tt.trigger)
		w, err := store.watch(ctx, tt.key, "0", filter, recursive)
		if err != nil {
			t.Fatalf("Watch failed: %v", err)
		}
		var prevObj *api.Pod
		for _, watchTest := range tt.watchTests {
			out := &api.Pod{}
			key := tt.key
			if recursive {
				key = key + "/item"
			}
			err := store.GuaranteedUpdate(ctx, key, out, true, nil, storage.SimpleUpdate(
				func(runtime.Object) (runtime.Object, error) {
					return watchTest.obj, nil
				}))
			if err != nil {
				t.Fatalf("GuaranteedUpdate failed: %v", err)
			}
			if watchTest.expectEvent {
				expectObj := out
				if watchTest.watchType == watch.Deleted {
					expectObj = prevObj
					expectObj.ResourceVersion = out.ResourceVersion
				}
				testCheckResult(t, i, watchTest.watchType, w, expectObj)
			}
			prevObj = out
		}
		w.Stop()
		testCheckStop(t, i, w)
		cluster.Terminate(t)
	}
}

func TestDeleteTriggerWatch(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})
	w, err := store.Watch(ctx, key, storedObj.ResourceVersion, storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	if err := store.Delete(ctx, key, &api.Pod{}, nil); err != nil {
		t.Fatalf("Delete failed: %v", err)
	}
	testCheckEventType(t, watch.Deleted, w)
}

// TestWatchFromZero tests that
// - watch from 0 should sync up and grab the object added before
// - watch from non-0 should just watch changes after given version
func TestWatchFromZero(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})

	w, err := store.Watch(ctx, key, "0", storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	testCheckResult(t, 0, watch.Added, w, storedObj)
}

// TestWatchFromNoneZero tests that
// - watch from non-0 should just watch changes after given version
func TestWatchFromNoneZero(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})

	w, err := store.Watch(ctx, key, storedObj.ResourceVersion, storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	out := &api.Pod{}
	store.GuaranteedUpdate(ctx, key, out, true, nil, storage.SimpleUpdate(
		func(runtime.Object) (runtime.Object, error) {
			return &api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}}, err
		}))
	testCheckResult(t, 0, watch.Modified, w, out)
}

func TestWatchError(t *testing.T) {
	cluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer cluster.Terminate(t)
	invalidStore := newStore(cluster.RandClient(), &testCodec{testapi.Default.Codec()}, "")
	ctx := context.Background()
	w, err := invalidStore.Watch(ctx, "/abc", "0", storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	validStore := newStore(cluster.RandClient(), testapi.Default.Codec(), "")
	validStore.GuaranteedUpdate(ctx, "/abc", &api.Pod{}, true, nil, storage.SimpleUpdate(
		func(runtime.Object) (runtime.Object, error) {
			return &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}, nil
		}))
	testCheckEventType(t, watch.Error, w)
}

func TestWatchContextCancel(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	canceledCtx, cancel := context.WithCancel(ctx)
	cancel()
	w := store.watcher.createWatchChan(canceledCtx, "/abc", 0, false, storage.Everything)
	// When we do a client.Get with a canceled context, it will return error.
	// Nonetheless, when we try to send it over internal errChan, we should detect
	// it's context canceled and not send it.
	err := w.sync()
	w.ctx = ctx
	w.sendError(err)
	select {
	case err := <-w.errChan:
		t.Errorf("cancelling context shouldn't return any error. Err: %v", err)
	default:
	}
}

func TestWatchErrResultNotBlockAfterCancel(t *testing.T) {
	origCtx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	ctx, cancel := context.WithCancel(origCtx)
	w := store.watcher.createWatchChan(ctx, "/abc", 0, false, storage.Everything)
	// make resutlChan and errChan blocking to ensure ordering.
	w.resultChan = make(chan watch.Event)
	w.errChan = make(chan error)
	// The event flow goes like:
	// - first we send an error, it should block on resultChan.
	// - Then we cancel ctx. The blocking on resultChan should be freed up
	//   and run() goroutine should return.
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		w.run()
		wg.Done()
	}()
	w.errChan <- fmt.Errorf("some error")
	cancel()
	wg.Wait()
}

func TestWatchDeleteEventObjectHaveLatestRV(t *testing.T) {
	ctx, store, cluster := testSetup(t)
	defer cluster.Terminate(t)
	key, storedObj := testPropogateStore(t, store, ctx, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}})

	w, err := store.Watch(ctx, key, storedObj.ResourceVersion, storage.Everything)
	if err != nil {
		t.Fatalf("Watch failed: %v", err)
	}
	etcdW := cluster.RandClient().Watch(ctx, "/", clientv3.WithPrefix())

	if err := store.Delete(ctx, key, &api.Pod{}, &storage.Preconditions{}); err != nil {
		t.Fatalf("Delete failed: %v", err)
	}

	e := <-w.ResultChan()
	watchedDeleteObj := e.Object.(*api.Pod)
	var wres clientv3.WatchResponse
	wres = <-etcdW

	watchedDeleteRev, err := storage.ParseWatchResourceVersion(watchedDeleteObj.ResourceVersion)
	if err != nil {
		t.Fatalf("ParseWatchResourceVersion failed: %v", err)
	}
	if int64(watchedDeleteRev) != wres.Events[0].Kv.ModRevision {
		t.Errorf("Object from delete event have version: %v, should be the same as etcd delete's mod rev: %d",
			watchedDeleteRev, wres.Events[0].Kv.ModRevision)
	}
}

type testWatchStruct struct {
	obj         *api.Pod
	expectEvent bool
	watchType   watch.EventType
}

type testCodec struct {
	runtime.Codec
}

func (c *testCodec) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
	return nil, nil, errors.New("Expected decoding failure")
}

func testCheckEventType(t *testing.T, expectEventType watch.EventType, w watch.Interface) {
	select {
	case res := <-w.ResultChan():
		if res.Type != expectEventType {
			t.Errorf("event type want=%v, get=%v", expectEventType, res.Type)
		}
	case <-time.After(wait.ForeverTestTimeout):
		t.Errorf("time out after waiting %v on ResultChan", wait.ForeverTestTimeout)
	}
}

func testCheckResult(t *testing.T, i int, expectEventType watch.EventType, w watch.Interface, expectObj *api.Pod) {
	select {
	case res := <-w.ResultChan():
		if res.Type != expectEventType {
			t.Errorf("#%d: event type want=%v, get=%v", i, expectEventType, res.Type)
			return
		}
		if !reflect.DeepEqual(expectObj, res.Object) {
			t.Errorf("#%d: obj want=\n%#v\nget=\n%#v", i, expectObj, res.Object)
		}
	case <-time.After(wait.ForeverTestTimeout):
		t.Errorf("#%d: time out after waiting %v on ResultChan", i, wait.ForeverTestTimeout)
	}
}

func testCheckStop(t *testing.T, i int, w watch.Interface) {
	select {
	case e, ok := <-w.ResultChan():
		if ok {
			var obj string
			switch e.Object.(type) {
			case *api.Pod:
				obj = e.Object.(*api.Pod).Name
			case *unversioned.Status:
				obj = e.Object.(*unversioned.Status).Message
			}
			t.Errorf("#%d: ResultChan should have been closed. Event: %s. Object: %s", i, e.Type, obj)
		}
	case <-time.After(wait.ForeverTestTimeout):
		t.Errorf("#%d: time out after waiting 1s on ResultChan", i)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Epracom Advies.
//
// 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 service

import (
	"crypto/x509"
	"net/http"

	"github.com/hashicorp/vault/api"
	"github.com/op/go-logging"
)

type VaultServiceConfig struct {
	VaultAddr   string // URL of the vault
	VaultCACert string //  	Path to a PEM-encoded CA cert file to use to verify the Vault server SSL certificate
	VaultCAPath string // Path to a directory of PEM-encoded CA cert files to verify the Vault server SSL certificate
	TokenPath   string // Path of a file containing the login token
}

type VaultService struct {
	log         *logging.Logger
	vaultClient *api.Client
}

func NewVaultService(log *logging.Logger, srvCfg VaultServiceConfig) (*VaultService, error) {
	// Create a vault client
	config := api.DefaultConfig()
	if err := config.ReadEnvironment(); err != nil {
		return nil, maskAny(err)
	}
	if srvCfg.VaultAddr != "" {
		log.Debug("Setting vault address to %s", srvCfg.VaultAddr)
		config.Address = srvCfg.VaultAddr
	}
	client, err := api.NewClient(config)
	if err != nil {
		return nil, maskAny(err)
	}
	if srvCfg.TokenPath != "" {
		log.Debug("Loading token from %s", srvCfg.TokenPath)
		token, err := readID(srvCfg.TokenPath)
		if err != nil {
			return nil, maskAny(err)
		}
		client.SetToken(token)
	}
	if srvCfg.VaultCACert != "" || srvCfg.VaultCAPath != "" {
		var newCertPool *x509.CertPool
		if srvCfg.VaultCACert != "" {
			log.Debug("Loading CA cert: %s", srvCfg.VaultCACert)
			newCertPool, err = api.LoadCACert(srvCfg.VaultCACert)
		} else {
			log.Debug("Loading CA certs from: %s", srvCfg.VaultCAPath)
			newCertPool, err = api.LoadCAPath(srvCfg.VaultCAPath)
		}
		if err != nil {
			return nil, maskAny(err)
		}
		clientTLSConfig := config.HttpClient.Transport.(*http.Transport).TLSClientConfig
		clientTLSConfig.RootCAs = newCertPool
	}

	return &VaultService{
		log:         log,
		vaultClient: client,
	}, nil
}
<commit_msg>Load CACert at correct time<commit_after>// Copyright (c) 2016 Epracom Advies.
//
// 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 service

import (
	"crypto/x509"
	"net/http"

	"github.com/hashicorp/vault/api"
	"github.com/op/go-logging"
)

type VaultServiceConfig struct {
	VaultAddr   string // URL of the vault
	VaultCACert string //  	Path to a PEM-encoded CA cert file to use to verify the Vault server SSL certificate
	VaultCAPath string // Path to a directory of PEM-encoded CA cert files to verify the Vault server SSL certificate
	TokenPath   string // Path of a file containing the login token
}

type VaultService struct {
	log         *logging.Logger
	vaultClient *api.Client
}

func NewVaultService(log *logging.Logger, srvCfg VaultServiceConfig) (*VaultService, error) {
	// Create a vault client
	config := api.DefaultConfig()
	if err := config.ReadEnvironment(); err != nil {
		return nil, maskAny(err)
	}
	if srvCfg.VaultAddr != "" {
		log.Debug("Setting vault address to %s", srvCfg.VaultAddr)
		config.Address = srvCfg.VaultAddr
	}
	if srvCfg.VaultCACert != "" || srvCfg.VaultCAPath != "" {
		var newCertPool *x509.CertPool
		var err error
		if srvCfg.VaultCACert != "" {
			log.Debug("Loading CA cert: %s", srvCfg.VaultCACert)
			newCertPool, err = api.LoadCACert(srvCfg.VaultCACert)
		} else {
			log.Debug("Loading CA certs from: %s", srvCfg.VaultCAPath)
			newCertPool, err = api.LoadCAPath(srvCfg.VaultCAPath)
		}
		if err != nil {
			return nil, maskAny(err)
		}
		clientTLSConfig := config.HttpClient.Transport.(*http.Transport).TLSClientConfig
		clientTLSConfig.RootCAs = newCertPool
	}
	client, err := api.NewClient(config)
	if err != nil {
		return nil, maskAny(err)
	}
	if srvCfg.TokenPath != "" {
		log.Debug("Loading token from %s", srvCfg.TokenPath)
		token, err := readID(srvCfg.TokenPath)
		if err != nil {
			return nil, maskAny(err)
		}
		client.SetToken(token)
	}

	return &VaultService{
		log:         log,
		vaultClient: client,
	}, nil
}
<|endoftext|>


<commit_before>package i2c

import (
	"time"

	"github.com/hybridgroup/gobot"
)

const (
	REG_RED   = 0x04
	REG_GREEN = 0x03
	REG_BLUE  = 0x02

	LCD_CLEARDISPLAY        = 0x01
	LCD_RETURNHOME          = 0x02
	LCD_ENTRYMODESET        = 0x04
	LCD_DISPLAYCONTROL      = 0x08
	LCD_CURSORSHIFT         = 0x10
	LCD_FUNCTIONSET         = 0x20
	LCD_SETCGRAMADDR        = 0x40
	LCD_SETDDRAMADDR        = 0x80
	LCD_ENTRYRIGHT          = 0x00
	LCD_ENTRYLEFT           = 0x02
	LCD_ENTRYSHIFTINCREMENT = 0x01
	LCD_ENTRYSHIFTDECREMENT = 0x00
	LCD_DISPLAYON           = 0x04
	LCD_DISPLAYOFF          = 0x00
	LCD_CURSORON            = 0x02
	LCD_CURSOROFF           = 0x00
	LCD_BLINKON             = 0x01
	LCD_BLINKOFF            = 0x00
	LCD_DISPLAYMOVE         = 0x08
	LCD_CURSORMOVE          = 0x00
	LCD_MOVERIGHT           = 0x04
	LCD_MOVELEFT            = 0x00
	LCD_2LINE               = 0x08
	LCD_CMD                 = 0x80
	LCD_DATA                = 0x40

	LCD_2NDLINEOFFSET = 0x40
)

var _ gobot.Driver = (*JHD1313M1Driver)(nil)

// JHD1313M1Driver is a driver for the Jhd1313m1 LCD display which has two i2c addreses,
// one belongs to a controller and the other controls solely the backlight.
// This module was tested with the Seed Grove LCD RGB Backlight v2.0 display which requires 5V to operate.
// http://www.seeedstudio.com/wiki/Grove_-_LCD_RGB_Backlight
type JHD1313M1Driver struct {
	name       string
	connection I2c
	lcdAddress int
	rgbAddress int
}

// NewJHD1313M1Driver creates a new driver with specified name and i2c interface.
func NewJHD1313M1Driver(a I2c, name string) *JHD1313M1Driver {
	return &JHD1313M1Driver{
		name:       name,
		connection: a,
		lcdAddress: 0x3E,
		rgbAddress: 0x62,
	}
}

// Name returns the name the JHD1313M1 Driver was given when created.
func (h *JHD1313M1Driver) Name() string { return h.name }

// Connection returns the driver connection to the device.
func (h *JHD1313M1Driver) Connection() gobot.Connection {
	return h.connection.(gobot.Connection)
}

// Start starts the backlit and the screen and initializes the states.
func (h *JHD1313M1Driver) Start() []error {
	if err := h.connection.I2cStart(h.lcdAddress); err != nil {
		return []error{err}
	}

	if err := h.connection.I2cStart(h.rgbAddress); err != nil {
		return []error{err}
	}

	<-time.After(50000 * time.Microsecond)
	payload := []byte{LCD_CMD, LCD_FUNCTIONSET | LCD_2LINE}
	if err := h.connection.I2cWrite(h.lcdAddress, payload); err != nil {
		if err := h.connection.I2cWrite(h.lcdAddress, payload); err != nil {
			return []error{err}
		}
	}

	<-time.After(100 * time.Microsecond)
	if err := h.connection.I2cWrite(h.lcdAddress, []byte{LCD_CMD, LCD_DISPLAYCONTROL | LCD_DISPLAYON}); err != nil {
		return []error{err}
	}

	<-time.After(100 * time.Microsecond)
	if err := h.Clear(); err != nil {
		return []error{err}
	}

	if err := h.connection.I2cWrite(h.lcdAddress, []byte{LCD_CMD, LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT}); err != nil {
		return []error{err}
	}

	if err := h.setReg(0, 0); err != nil {
		return []error{err}
	}
	if err := h.setReg(1, 0); err != nil {
		return []error{err}
	}
	if err := h.setReg(0x08, 0xAA); err != nil {
		return []error{err}
	}

	if err := h.SetRGB(255, 255, 255); err != nil {
		return []error{err}
	}

	return nil
}

// SetRGB sets the Red Green Blue value of backlit.
func (h *JHD1313M1Driver) SetRGB(r, g, b int) error {
	if err := h.setReg(REG_RED, r); err != nil {
		return err
	}
	if err := h.setReg(REG_GREEN, g); err != nil {
		return err
	}
	return h.setReg(REG_BLUE, b)
}

// Clear clears the text on the lCD display.
func (h *JHD1313M1Driver) Clear() error {
	err := h.command([]byte{LCD_CLEARDISPLAY})
	return err
}

// Home sets the cursor to the origin position on the display.
func (h *JHD1313M1Driver) Home() error {
	err := h.command([]byte{LCD_RETURNHOME})
	// This wait fixes a race condition when calling home and clear back to back.
	<-time.After(2 * time.Millisecond)
	return err
}

// Write displays the passed message on the screen.
func (h *JHD1313M1Driver) Write(message string) error {
	// This wait fixes an odd bug where the clear function doesn't always work properly.
	<-time.After(1 * time.Millisecond)
	for _, val := range message {
		if val == '\n' {
			if err := h.SetPosition(16); err != nil {
				return err
			}
		}
		if err = h.connection.I2cWrite(h.lcdAddress, []byte{LCD_DATA, byte(val)}); err != nil {
			break
		}
	}
	return nil
}

// SetPosition sets the cursor and the data display to pos.
// 0..15 are the positions in the first display line.
// 16..32 are the positions in the second display line.
func (h *JHD1313M1Driver) SetPosition(pos int) (err error) {
	if pos < 0 || pos > 31 {
		err = ErrInvalidPosition
		return
	}
	offset := byte(pos)
	if pos >= 16 {
		offset -= 16
		offset |= LCD_2NDLINEOFFSET
	}
	err = h.command([]byte{LCD_SETDDRAMADDR | offset})
	return
}

func (h *JHD1313M1Driver) Halt() (errs []error) { return }

	if leftToRight {
		return h.connection.I2cWrite(h.rgbAddress, []byte{LCD_CMD, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT})
	}

	return h.connection.I2cWrite(h.rgbAddress, []byte{LCD_CMD, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT})
}

// Halt is a noop function.
func (h *JHD1313M1Driver) Halt() []error { return nil }

func (h *JHD1313M1Driver) setReg(command int, data int) error {
	if err := h.connection.I2cWrite(h.rgbAddress, []byte{byte(command), byte(data)}); err != nil {
		return err
	}
	return nil
}

func (h *JHD1313M1Driver) command(buf []byte) error {
	return h.connection.I2cWrite(h.lcdAddress, append([]byte{LCD_CMD}, buf...))
}
<commit_msg>fix the bad merge<commit_after>package i2c

import (
	"time"

	"github.com/hybridgroup/gobot"
)

const (
	REG_RED   = 0x04
	REG_GREEN = 0x03
	REG_BLUE  = 0x02

	LCD_CLEARDISPLAY        = 0x01
	LCD_RETURNHOME          = 0x02
	LCD_ENTRYMODESET        = 0x04
	LCD_DISPLAYCONTROL      = 0x08
	LCD_CURSORSHIFT         = 0x10
	LCD_FUNCTIONSET         = 0x20
	LCD_SETCGRAMADDR        = 0x40
	LCD_SETDDRAMADDR        = 0x80
	LCD_ENTRYRIGHT          = 0x00
	LCD_ENTRYLEFT           = 0x02
	LCD_ENTRYSHIFTINCREMENT = 0x01
	LCD_ENTRYSHIFTDECREMENT = 0x00
	LCD_DISPLAYON           = 0x04
	LCD_DISPLAYOFF          = 0x00
	LCD_CURSORON            = 0x02
	LCD_CURSOROFF           = 0x00
	LCD_BLINKON             = 0x01
	LCD_BLINKOFF            = 0x00
	LCD_DISPLAYMOVE         = 0x08
	LCD_CURSORMOVE          = 0x00
	LCD_MOVERIGHT           = 0x04
	LCD_MOVELEFT            = 0x00
	LCD_2LINE               = 0x08
	LCD_CMD                 = 0x80
	LCD_DATA                = 0x40

	LCD_2NDLINEOFFSET = 0x40
)

var _ gobot.Driver = (*JHD1313M1Driver)(nil)

// JHD1313M1Driver is a driver for the Jhd1313m1 LCD display which has two i2c addreses,
// one belongs to a controller and the other controls solely the backlight.
// This module was tested with the Seed Grove LCD RGB Backlight v2.0 display which requires 5V to operate.
// http://www.seeedstudio.com/wiki/Grove_-_LCD_RGB_Backlight
type JHD1313M1Driver struct {
	name       string
	connection I2c
	lcdAddress int
	rgbAddress int
}

// NewJHD1313M1Driver creates a new driver with specified name and i2c interface.
func NewJHD1313M1Driver(a I2c, name string) *JHD1313M1Driver {
	return &JHD1313M1Driver{
		name:       name,
		connection: a,
		lcdAddress: 0x3E,
		rgbAddress: 0x62,
	}
}

// Name returns the name the JHD1313M1 Driver was given when created.
func (h *JHD1313M1Driver) Name() string { return h.name }

// Connection returns the driver connection to the device.
func (h *JHD1313M1Driver) Connection() gobot.Connection {
	return h.connection.(gobot.Connection)
}

// Start starts the backlit and the screen and initializes the states.
func (h *JHD1313M1Driver) Start() []error {
	if err := h.connection.I2cStart(h.lcdAddress); err != nil {
		return []error{err}
	}

	if err := h.connection.I2cStart(h.rgbAddress); err != nil {
		return []error{err}
	}

	<-time.After(50000 * time.Microsecond)
	payload := []byte{LCD_CMD, LCD_FUNCTIONSET | LCD_2LINE}
	if err := h.connection.I2cWrite(h.lcdAddress, payload); err != nil {
		if err := h.connection.I2cWrite(h.lcdAddress, payload); err != nil {
			return []error{err}
		}
	}

	<-time.After(100 * time.Microsecond)
	if err := h.connection.I2cWrite(h.lcdAddress, []byte{LCD_CMD, LCD_DISPLAYCONTROL | LCD_DISPLAYON}); err != nil {
		return []error{err}
	}

	<-time.After(100 * time.Microsecond)
	if err := h.Clear(); err != nil {
		return []error{err}
	}

	if err := h.connection.I2cWrite(h.lcdAddress, []byte{LCD_CMD, LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT}); err != nil {
		return []error{err}
	}

	if err := h.setReg(0, 0); err != nil {
		return []error{err}
	}
	if err := h.setReg(1, 0); err != nil {
		return []error{err}
	}
	if err := h.setReg(0x08, 0xAA); err != nil {
		return []error{err}
	}

	if err := h.SetRGB(255, 255, 255); err != nil {
		return []error{err}
	}

	return nil
}

// SetRGB sets the Red Green Blue value of backlit.
func (h *JHD1313M1Driver) SetRGB(r, g, b int) error {
	if err := h.setReg(REG_RED, r); err != nil {
		return err
	}
	if err := h.setReg(REG_GREEN, g); err != nil {
		return err
	}
	return h.setReg(REG_BLUE, b)
}

// Clear clears the text on the lCD display.
func (h *JHD1313M1Driver) Clear() error {
	err := h.command([]byte{LCD_CLEARDISPLAY})
	return err
}

// Home sets the cursor to the origin position on the display.
func (h *JHD1313M1Driver) Home() error {
	err := h.command([]byte{LCD_RETURNHOME})
	// This wait fixes a race condition when calling home and clear back to back.
	<-time.After(2 * time.Millisecond)
	return err
}

// Write displays the passed message on the screen.
func (h *JHD1313M1Driver) Write(message string) error {
	// This wait fixes an odd bug where the clear function doesn't always work properly.
	<-time.After(1 * time.Millisecond)
	for _, val := range message {
		if val == '\n' {
			if err := h.SetPosition(16); err != nil {
				return err
			}
			continue
		}
		if err := h.connection.I2cWrite(h.lcdAddress, []byte{LCD_DATA, byte(val)}); err != nil {
			return err
		}
	}
	return nil
}

// SetPosition sets the cursor and the data display to pos.
// 0..15 are the positions in the first display line.
// 16..32 are the positions in the second display line.
func (h *JHD1313M1Driver) SetPosition(pos int) (err error) {
	if pos < 0 || pos > 31 {
		err = ErrInvalidPosition
		return
	}
	offset := byte(pos)
	if pos >= 16 {
		offset -= 16
		offset |= LCD_2NDLINEOFFSET
	}
	err = h.command([]byte{LCD_SETDDRAMADDR | offset})
	return
}

func (h *JHD1313M1Driver) Scroll(leftToRight bool) error {
	if leftToRight {
		return h.connection.I2cWrite(h.rgbAddress, []byte{LCD_CMD, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT})
	}

	return h.connection.I2cWrite(h.rgbAddress, []byte{LCD_CMD, LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT})
}

// Halt is a noop function.
func (h *JHD1313M1Driver) Halt() []error { return nil }

func (h *JHD1313M1Driver) setReg(command int, data int) error {
	if err := h.connection.I2cWrite(h.rgbAddress, []byte{byte(command), byte(data)}); err != nil {
		return err
	}
	return nil
}

func (h *JHD1313M1Driver) command(buf []byte) error {
	return h.connection.I2cWrite(h.lcdAddress, append([]byte{LCD_CMD}, buf...))
}
<|endoftext|>


<commit_before>package secret

import (
	"html/template"
	"os"

	"github.com/urfave/cli"

	"github.com/drone/drone-cli/drone/internal"
)

var secretInfoCmd = cli.Command{
	Name:      "info",
	Usage:     "display secret info",
	ArgsUsage: "[repo/name]",
	Action:    secretInfo,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "repository",
			Usage: "repository name (e.g. octocat/hello-world)",
		},
		cli.StringFlag{
			Name:  "name",
			Usage: "secret name",
		},
		cli.StringFlag{
			Name:   "format",
			Usage:  "format output",
			Value:  tmplSecretList,
			Hidden: true,
		},
	},
}

func secretInfo(c *cli.Context) error {
	var (
		secretName = c.String("name")
		repoName   = c.String("repository")
		format     = c.String("format") + "\n"
	)
	if repoName == "" {
		repoName = c.Args().First()
	}
	owner, name, err := internal.ParseRepo(repoName)
	if err != nil {
		return err
	}
	client, err := internal.NewClient(c)
	if err != nil {
		return err
	}
	secret, err := client.Secret(owner, name, secretName)
	if err != nil {
		return err
	}
	tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
	if err != nil {
		return err
	}
	return tmpl.Execute(os.Stdout, secret)
}
<commit_msg>fix annoying secret info bug<commit_after>package secret

import (
	"errors"
	"html/template"
	"os"

	"github.com/urfave/cli"

	"github.com/drone/drone-cli/drone/internal"
)

var secretInfoCmd = cli.Command{
	Name:      "info",
	Usage:     "display secret info",
	ArgsUsage: "[repo/name]",
	Action:    secretInfo,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "repository",
			Usage: "repository name (e.g. octocat/hello-world)",
		},
		cli.StringFlag{
			Name:  "name",
			Usage: "secret name",
		},
		cli.StringFlag{
			Name:   "format",
			Usage:  "format output",
			Value:  tmplSecretList,
			Hidden: true,
		},
	},
}

func secretInfo(c *cli.Context) error {
	var (
		secretName = c.String("name")
		repoName   = c.String("repository")
		format     = c.String("format") + "\n"
	)
	if secretName == "" {
		return errors.New("Missing secret name")
	}
	if repoName == "" {
		repoName = c.Args().First()
	}
	owner, name, err := internal.ParseRepo(repoName)
	if err != nil {
		return err
	}
	client, err := internal.NewClient(c)
	if err != nil {
		return err
	}
	secret, err := client.Secret(owner, name, secretName)
	if err != nil {
		return err
	}
	tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
	if err != nil {
		return err
	}
	return tmpl.Execute(os.Stdout, secret)
}
<|endoftext|>


<commit_before>package session

import (
	"net/http"
	"time"
)

// ContextDataName changes the value of the (string) key used to store the session
// information in Request.Context. You should only need to change this if there is
// a naming clash.
var ContextName = "scs.session"

// CookieName changes the name of the session cookie issued to clients. Note that
// cookie names should not contain whitespace, commas, semicolons, backslashes
// or control characters as per RFC6265.
var CookieName = "scs.session.cookie"

var defaultOptions = &options{
	domain:      "",
	errorFunc:   defaultErrorFunc,
	httpOnly:    true,
	idleTimeout: 0,
	lifetime:    24 * time.Hour,
	path:        "/",
	persist:     false,
	secure:      false,
}

type options struct {
	domain      string
	errorFunc   func(http.ResponseWriter, *http.Request, error)
	httpOnly    bool
	idleTimeout time.Duration
	lifetime    time.Duration
	path        string
	persist     bool
	secure      bool
}

// Option defines the functional arguments for configuring the session manager.
type Option func(*options)

// Domain sets the 'Domain' attribute on the session cookie. By default it will
// be set to the domain name that the cookie was issued from.
func Domain(s string) Option {
	return func(opts *options) {
		opts.domain = s
	}
}

// ErrorFunc allows you to control behavior when an error is encountered loading
// or writing a session. The default behavior is for a HTTP 500 status code to
// be written to the ResponseWriter along with the plain-text error string. If
// a custom error function is set, then control will be passed to this instead.
// A typical use would be to provide a function which logs the error and returns
// a customized HTML error page.
func ErrorFunc(f func(http.ResponseWriter, *http.Request, error)) Option {
	return func(opts *options) {
		opts.errorFunc = f
	}
}

// HttpOnly sets the 'HttpOnly' attribute on the session cookie. The default value
// is true.
func HttpOnly(b bool) Option {
	return func(opts *options) {
		opts.httpOnly = b
	}
}

// IdleTimeout sets the maximum length of time a session can be inactive before it
// expires. For example, some applications may wish to set this so there is a timeout after
// 20 minutes of inactivity. Any client request which includes the
// session cookie and is handled by the session middleware is classed as activity.s
//
// By default IdleTimeout is not set and there is no inactivity timeout.
func IdleTimeout(t time.Duration) Option {
	return func(opts *options) {
		opts.idleTimeout = t
	}
}

// Lifetime sets the maximum length of time that a session is valid for before
// it expires. The default value is 24 hours. This is an 'absolute expiry' which
// is set when the session is first created and does not change.
func Lifetime(t time.Duration) Option {
	return func(opts *options) {
		opts.lifetime = t
	}
}

// Path sets the 'Path' attribute on the session cookie. The default value is "/".
// Passing the empty string "" will result in it being set to the path that the
// cookie was issued from.
func Path(s string) Option {
	return func(opts *options) {
		opts.path = s
	}
}

// Persist sets whether the session cookie should be persistent or not (i.e. whether
// it should be retained after a user closes their browser).
//
// The default value is false, which means that the session cookie will be destroyed
// when the user closes their browser. If set to true, explicit 'Expires' and
// 'MaxAge' values will be added to the cookie and it will be retained by the
// user's browser until the given expiry time is reached.
func Persist(b bool) Option {
	return func(opts *options) {
		opts.persist = b
	}
}

// Secure sets the 'Secure' attribute on the session cookie. The default value
// is false. It's recommended that you set this to true and serve all requests
// over HTTPS in production environments.
func Secure(b bool) Option {
	return func(opts *options) {
		opts.secure = b
	}
}
<commit_msg>[refactor] Change default CookieName<commit_after>package session

import (
	"net/http"
	"time"
)

// ContextDataName changes the value of the (string) key used to store the session
// information in Request.Context. You should only need to change this if there is
// a naming clash.
var ContextName = "scs.session"

// CookieName changes the name of the session cookie issued to clients. Note that
// cookie names should not contain whitespace, commas, semicolons, backslashes
// or control characters as per RFC6265.
var CookieName = "scs.session.token"

var defaultOptions = &options{
	domain:      "",
	errorFunc:   defaultErrorFunc,
	httpOnly:    true,
	idleTimeout: 0,
	lifetime:    24 * time.Hour,
	path:        "/",
	persist:     false,
	secure:      false,
}

type options struct {
	domain      string
	errorFunc   func(http.ResponseWriter, *http.Request, error)
	httpOnly    bool
	idleTimeout time.Duration
	lifetime    time.Duration
	path        string
	persist     bool
	secure      bool
}

// Option defines the functional arguments for configuring the session manager.
type Option func(*options)

// Domain sets the 'Domain' attribute on the session cookie. By default it will
// be set to the domain name that the cookie was issued from.
func Domain(s string) Option {
	return func(opts *options) {
		opts.domain = s
	}
}

// ErrorFunc allows you to control behavior when an error is encountered loading
// or writing a session. The default behavior is for a HTTP 500 status code to
// be written to the ResponseWriter along with the plain-text error string. If
// a custom error function is set, then control will be passed to this instead.
// A typical use would be to provide a function which logs the error and returns
// a customized HTML error page.
func ErrorFunc(f func(http.ResponseWriter, *http.Request, error)) Option {
	return func(opts *options) {
		opts.errorFunc = f
	}
}

// HttpOnly sets the 'HttpOnly' attribute on the session cookie. The default value
// is true.
func HttpOnly(b bool) Option {
	return func(opts *options) {
		opts.httpOnly = b
	}
}

// IdleTimeout sets the maximum length of time a session can be inactive before it
// expires. For example, some applications may wish to set this so there is a timeout after
// 20 minutes of inactivity. Any client request which includes the
// session cookie and is handled by the session middleware is classed as activity.s
//
// By default IdleTimeout is not set and there is no inactivity timeout.
func IdleTimeout(t time.Duration) Option {
	return func(opts *options) {
		opts.idleTimeout = t
	}
}

// Lifetime sets the maximum length of time that a session is valid for before
// it expires. The default value is 24 hours. This is an 'absolute expiry' which
// is set when the session is first created and does not change.
func Lifetime(t time.Duration) Option {
	return func(opts *options) {
		opts.lifetime = t
	}
}

// Path sets the 'Path' attribute on the session cookie. The default value is "/".
// Passing the empty string "" will result in it being set to the path that the
// cookie was issued from.
func Path(s string) Option {
	return func(opts *options) {
		opts.path = s
	}
}

// Persist sets whether the session cookie should be persistent or not (i.e. whether
// it should be retained after a user closes their browser).
//
// The default value is false, which means that the session cookie will be destroyed
// when the user closes their browser. If set to true, explicit 'Expires' and
// 'MaxAge' values will be added to the cookie and it will be retained by the
// user's browser until the given expiry time is reached.
func Persist(b bool) Option {
	return func(opts *options) {
		opts.persist = b
	}
}

// Secure sets the 'Secure' attribute on the session cookie. The default value
// is false. It's recommended that you set this to true and serve all requests
// over HTTPS in production environments.
func Secure(b bool) Option {
	return func(opts *options) {
		opts.secure = b
	}
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found
// in the LICENSE file.

// Package cacher provides a uniform interface for different caching strategies.
package cacher

// Cacher is the Caching interface that uniforms all the different strategies.
type Cacher interface {
	Add(key string, value []byte, ttl int64) bool
	CompareAndReplace(token, key string, value []byte, ttl int64) bool
	Set(key string, value []byte, ttl int64) bool
	SetMulti(keys map[string][]byte, ttl int64) map[string]bool
	Replace(key string, value []byte, ttl int64) bool
	Increment(key string, initial, offset, ttl int64) bool
	Decrement(key string, initial, offset, ttl int64) bool
	Delete(key string) bool
	DeleteMulti(keys []string) map[string]bool
	Get(key string) ([]byte, string, bool)
	GetMulti(keys []string) (map[string][]byte, map[string]string, map[string]bool)
	Flush() bool
	Touch(key string, ttl int64) bool
}
<commit_msg>Cacher: add package level functions.<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found
// in the LICENSE file.

// Package cacher provides a uniform interface for different caching strategies.
package cacher

import "github.com/jelmersnoeck/cacher/memory"

// Cacher is the Caching interface that uniforms all the different strategies.
type Cacher interface {
	Add(key string, value []byte, ttl int64) bool
	CompareAndReplace(token, key string, value []byte, ttl int64) bool
	Set(key string, value []byte, ttl int64) bool
	SetMulti(keys map[string][]byte, ttl int64) map[string]bool
	Replace(key string, value []byte, ttl int64) bool
	Increment(key string, initial, offset, ttl int64) bool
	Decrement(key string, initial, offset, ttl int64) bool
	Delete(key string) bool
	DeleteMulti(keys []string) map[string]bool
	Get(key string) ([]byte, string, bool)
	GetMulti(keys []string) (map[string][]byte, map[string]string, map[string]bool)
	Flush() bool
	Touch(key string, ttl int64) bool
}

// The default cache which will be used for package level functions.
var DefaultCache Cacher = memory.New(500)

// Add adds a value to the cache under the specified key with a given TTL.
func Add(key string, value []byte, ttl int64) bool {
	return DefaultCache.Add(key, value, ttl)
}

// CompareAndReplace validates the token with the token in the store. If the
// tokens match, we will replace the value and return true. If it doesn't, we
// will not replace the value and return false.
func CompareAndReplace(token, key string, value []byte, ttl int64) bool {
	return DefaultCache.CompareAndReplace(token, key, value, ttl)
}

// Set sets the value of an item, regardless of wether or not the value is
// already cached.
//
// ttl defines the number of seconds the value should be cached. If ttl is 0,
// the item will be cached infinitely.
func Set(key string, value []byte, ttl int64) bool {
	return DefaultCache.Set(key, value, ttl)
}

// SetMulti sets multiple values for their respective keys. This is a shorthand
// to use `Set` multiple times.
func SetMulti(keys map[string][]byte, ttl int64) map[string]bool {
	return DefaultCache.SetMulty(keys, ttl)
}

// Replace will update and only update the value of a cache key. If the key is
// not previously used, we will return false.
func Replace(key string, value []byte, ttl int64) bool {
	return DefaultCache.Replace(key, value, ttl)
}

// Increment adds a value of offset to the initial value. If the initial value
// is already set, it will be added to the value currently stored in the cache.
func Increment(key string, initial, offset, ttl int64) bool {
	return DefaultCache.Increment(key, value, ttl)
}

// Decrement subtracts a value of offset to the initial value. If the initial
// value is already set, it will be added to the value currently stored in the
// cache.
func Decrement(key string, initial, offset, ttl int64) bool {
	return DefaultCache.Set(key, value, ttl)
}

// Delete will validate if the key actually is stored in the cache. If it is
// stored, it will remove the item from the cache. If it is not stored, it will
// return false.
func Delete(key string) bool {
	return DefaultCache.Set(key, value, ttl)
}

// DeleteMulti will delete multiple values at a time. It uses the `Delete`
// method internally to do so. It will return a map of results to see if the
// deletion is successful.
func DeleteMulti(keys []string) map[string]bool {
	return DefaultCache.Set(key, value, ttl)
}

// Get gets the value out of the map associated with the provided key.
func Get(key string) ([]byte, string, bool) {
	return DefaultCache.Set(key, value, ttl)
}

// GetMulti gets multiple values from the cache and returns them as a map. It
// uses `Get` internally to retrieve the data.
func GetMulti(keys []string) (map[string][]byte, map[string]string, map[string]bool) {
	return DefaultCache.Set(key, value, ttl)
}

// Flush will remove all the items from the storage.
func Flush() bool {
	return DefaultCache.Set(key, value, ttl)
}

// Touch will update the key's ttl to the given ttl value without altering the
// value.
func Touch(key string, ttl int64) bool {
	return DefaultCache.Set(key, value, ttl)
}
<|endoftext|>


<commit_before>package main

var settingsTpl = `import (
	"sync"

	"gir/gio-2.0"
	"gir/glib-2.0"
	"pkg.deepin.io/lib/dbus"
)

type SettingHook interface {
	WillSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{}) bool // return true to continue setting.
	DidSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{})
	WillChange(gs *gio.Settings, key string) bool // return true to continue handleing change.
	DidChange(gs *gio.Settings, key string)
}

type DefaultSettingHook struct {
}

func (DefaultSettingHook) WillSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{}) bool {
	return true
}

func (DefaultSettingHook) DidSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{}) {
}

func (DefaultSettingHook) WillChange(*gio.Settings, string) bool {
	return true
}

func (DefaultSettingHook) DidChange(*gio.Settings, string) {
}

var _defaultHook = DefaultSettingHook{}

{{ $schemas := . }}
{{ range $_, $schema := .Schemas }}{{ if $schema.Keys }}{{ $TypeName := ExportName $schema.Id }}{{ if $schema.Keys }}
const (
{{ range $_, $key := $schema.Keys }}
	// {{ $key.Summary }}
	{{$result :=  GetDefaultValue $schemas $key }}{{ if $result.Err }}panic({{ $result.Err }}){{ else }}// default: {{ $result.Value }}{{ end }}
	{{$TypeName}}{{ ExportName $key.Name }} string = "{{ $key.Name }}"
{{ end }}
){{ end }}
{{/* generate setting structure */}}
type {{ $TypeName }} struct {
	finializeOnce sync.Once
	settings *gio.Settings
	hook SettingHook

{{ range $_, $key := $schema.Keys }}{{ $PropName :=  ExportName $key.Name }}
	{{ $PropName }}Changed func({{ if $key.IsEnum }}int32{{ else }}{{ if $key.IsFlags }}uint32{{ else }}{{ MapType $key.Type }}{{ end }}{{ end }})
{{ end }}
}

func (s *{{ $TypeName}}) GetDBusInfo() dbus.DBusInfo {
	return dbus.DBusInfo{
		Dest:       "{{ DBusName }}",
		ObjectPath: "{{ DBusPath }}",
		Interface:  "{{ ConvertToDBusInterface $schema.Id }}",
	}
}

func New{{ $TypeName }}() *{{ $TypeName }} {
	return New{{ $TypeName }}WithHook(nil)
}

func New{{ $TypeName }}WithHook(hook SettingHook) *{{ $TypeName }} {
	if hook == nil {
		hook = _defaultHook
	}
	s := &{{ $TypeName }} {
		hook: hook,
		settings: gio.NewSettings("{{$schema.Id}}"),
	}
	s.listenSignal()
	return s
}

func (s *{{ $TypeName }}) Finialize() {
	s.finializeOnce.Do(func() {
		s.settings.Unref()
	})
}

func (s *{{ $TypeName }}) listenSignal() {
	s.settings.Connect("changed", func(gs *gio.Settings, key string){
		if !s.hook.WillChange(gs, key) {
			return
		}
		switch key {
		{{ range $_, $key := $schema.Keys }}{{ $PropName :=  ExportName $key.Name }}
		case "{{ $key.Name }}":
			dbus.Emit(s, "{{ $PropName }}Changed", s.{{ $PropName }}())
		{{ end }}
		}
		s.hook.DidChange(gs, key)
	})
}

{{ range $_, $key := $schema.Keys }}{{ $PropName :=  ExportName $key.Name }}
{{/* not generated GetRangeOfXX for "type", "enum", "flags" */}}
{{ if $key.Range.Min }}
{{ $rangeType := GetRangeType $key }}
// GetRangeOf{{ $PropName }} gets the value range of {{ $PropName }}.
func (s *{{ $TypeName }}) GetRangeOf{{ $PropName }}(key string) {{ $rangeType }} {
	return {{ $rangeType }}{Min: {{ $key.Range.Min }}, Max: {{ $key.Range.Max }}}
}
{{ end }}

// {{ $PropName }} gets {{ $PropName }}'s value.
func (s *{{ $TypeName }}) {{$PropName}}() {{ GetKeyType $key }} {
	{{ if $key.IsEnum }}value := s.settings.GetEnum("{{$key.Name}}")
	{{ else }}{{ if $key.IsFlags }}value := s.settings.GetFlags("{{$key.Name}}")
	{{ else }}value := s.settings.GetValue("{{ $key.Name }}").Get{{ MapTypeGetter $key.Type }}()
	{{ end }}{{ end }}
	return value
}

// set{{ $PropName }} used internal.
func (s *{{ $TypeName }}) set{{ $PropName }}(newValue {{ GetKeyType $key }}) bool {
	oldValue := s.{{ $PropName }}()
	if oldValue == newValue {
		return false
	}

	gs := s.settings
	if !s.hook.WillSet(gs, "{{ $key.Name }}", oldValue, newValue) {
		return false
	}
	defer s.hook.DidSet(gs, "{{ $key.Name }}", oldValue, newValue)

	{{ if $key.IsEnum }}return gs.SetEnum("{{ $key.Name }}", newValue)
	{{ else }}{{ if $key.IsFlags }}return gs.SetFlags("{{ $key.Name }}", newValue)
	{{ else }}return gs.SetValue("{{ $key.Name }}", glib.NewVariant{{ MapTypeSetter $key.Type }}(newValue)){{ end }}{{ end }}
}

// Set{{ $PropName }} sets value of {{ $PropName }} and emit {{$PropName}}Changed signal.
func (s *{{ $TypeName }}) Set{{ $PropName }}(newValue {{ GetKeyType $key }}) {
	s.set{{$PropName}}(newValue)
	dbus.Emit(s, "{{ $PropName }}Changed", newValue)
}
{{ end }}
{{ end }}

{{ end }}

`
<commit_msg>make sure signal work.<commit_after>package main

var settingsTpl = `import (
	"sync"

	"gir/gio-2.0"
	"gir/glib-2.0"
	"pkg.deepin.io/lib/dbus"
)

type SettingHook interface {
	WillSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{}) bool // return true to continue setting.
	DidSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{})
	WillChange(gs *gio.Settings, key string) bool // return true to continue handleing change.
	DidChange(gs *gio.Settings, key string)
}

type DefaultSettingHook struct {
}

func (DefaultSettingHook) WillSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{}) bool {
	return true
}

func (DefaultSettingHook) DidSet(gs *gio.Settings, key string, oldValue interface{}, newValue interface{}) {
}

func (DefaultSettingHook) WillChange(*gio.Settings, string) bool {
	return true
}

func (DefaultSettingHook) DidChange(*gio.Settings, string) {
}

var _defaultHook = DefaultSettingHook{}

{{ $schemas := . }}
{{ range $_, $schema := .Schemas }}{{ if $schema.Keys }}{{ $TypeName := ExportName $schema.Id }}{{ if $schema.Keys }}
const (
{{ range $_, $key := $schema.Keys }}
	// {{ $key.Summary }}
	{{$result :=  GetDefaultValue $schemas $key }}{{ if $result.Err }}panic({{ $result.Err }}){{ else }}// default: {{ $result.Value }}{{ end }}
	{{$TypeName}}{{ ExportName $key.Name }} string = "{{ $key.Name }}"
{{ end }}
){{ end }}
{{/* generate setting structure */}}
type {{ $TypeName }} struct {
	finializeOnce sync.Once
	settings *gio.Settings
	hook SettingHook

{{ range $_, $key := $schema.Keys }}{{ $PropName :=  ExportName $key.Name }}
	{{ $PropName }}Changed func({{ if $key.IsEnum }}int32{{ else }}{{ if $key.IsFlags }}uint32{{ else }}{{ MapType $key.Type }}{{ end }}{{ end }})
{{ end }}
}

func (s *{{ $TypeName}}) GetDBusInfo() dbus.DBusInfo {
	return dbus.DBusInfo{
		Dest:       "{{ DBusName }}",
		ObjectPath: "{{ DBusPath }}",
		Interface:  "{{ ConvertToDBusInterface $schema.Id }}",
	}
}

func New{{ $TypeName }}() *{{ $TypeName }} {
	return New{{ $TypeName }}WithHook(nil)
}

func New{{ $TypeName }}WithHook(hook SettingHook) *{{ $TypeName }} {
	if hook == nil {
		hook = _defaultHook
	}
	s := &{{ $TypeName }} {
		hook: hook,
		settings: gio.NewSettings("{{$schema.Id}}"),
	}
	s.listenSignal()
	return s
}

func (s *{{ $TypeName }}) Finialize() {
	s.finializeOnce.Do(func() {
		s.settings.Unref()
	})
}

func (s *{{ $TypeName }}) listenSignal() {
	s.settings.Connect("changed", func(gs *gio.Settings, key string){
		if !s.hook.WillChange(gs, key) {
			return
		}
		switch key {
		{{ range $_, $key := $schema.Keys }}{{ $PropName :=  ExportName $key.Name }}
		case "{{ $key.Name }}":
			dbus.Emit(s, "{{ $PropName }}Changed", s.{{ $PropName }}())
		{{ end }}
		}
		s.hook.DidChange(gs, key)
	})
	{{ $sample := index $schema.Keys 0 }}
	// make sure signal work
	// detail: https://github.com/GNOME/glib/commit/8ff5668a458344da22d30491e3ce726d861b3619
	s.{{ ExportName $sample.Name }}()
}

{{ range $_, $key := $schema.Keys }}{{ $PropName :=  ExportName $key.Name }}
{{/* not generated GetRangeOfXX for "type", "enum", "flags" */}}
{{ if $key.Range.Min }}
{{ $rangeType := GetRangeType $key }}
// GetRangeOf{{ $PropName }} gets the value range of {{ $PropName }}.
func (s *{{ $TypeName }}) GetRangeOf{{ $PropName }}(key string) {{ $rangeType }} {
	return {{ $rangeType }}{Min: {{ $key.Range.Min }}, Max: {{ $key.Range.Max }}}
}
{{ end }}

// {{ $PropName }} gets {{ $PropName }}'s value.
func (s *{{ $TypeName }}) {{$PropName}}() {{ GetKeyType $key }} {
	{{ if $key.IsEnum }}value := s.settings.GetEnum("{{$key.Name}}")
	{{ else }}{{ if $key.IsFlags }}value := s.settings.GetFlags("{{$key.Name}}")
	{{ else }}value := s.settings.GetValue("{{ $key.Name }}").Get{{ MapTypeGetter $key.Type }}()
	{{ end }}{{ end }}
	return value
}

// set{{ $PropName }} used internal.
func (s *{{ $TypeName }}) set{{ $PropName }}(newValue {{ GetKeyType $key }}) bool {
	oldValue := s.{{ $PropName }}()
	if oldValue == newValue {
		return false
	}

	gs := s.settings
	if !s.hook.WillSet(gs, "{{ $key.Name }}", oldValue, newValue) {
		return false
	}
	defer s.hook.DidSet(gs, "{{ $key.Name }}", oldValue, newValue)

	{{ if $key.IsEnum }}return gs.SetEnum("{{ $key.Name }}", newValue)
	{{ else }}{{ if $key.IsFlags }}return gs.SetFlags("{{ $key.Name }}", newValue)
	{{ else }}return gs.SetValue("{{ $key.Name }}", glib.NewVariant{{ MapTypeSetter $key.Type }}(newValue)){{ end }}{{ end }}
}

// Set{{ $PropName }} sets value of {{ $PropName }} and emit {{$PropName}}Changed signal.
func (s *{{ $TypeName }}) Set{{ $PropName }}(newValue {{ GetKeyType $key }}) {
	s.set{{$PropName}}(newValue)
	dbus.Emit(s, "{{ $PropName }}Changed", newValue)
}
{{ end }}
{{ end }}

{{ end }}

`
<|endoftext|>


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

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"runtime"

	"github.com/vishvananda/netlink"

	"net"

	log "github.com/Sirupsen/logrus"
	"github.com/containernetworking/cni/pkg/ip"
	"github.com/containernetworking/cni/pkg/ipam"
	"github.com/containernetworking/cni/pkg/ns"
	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/projectcalico/calico-cni/k8s"
	. "github.com/projectcalico/calico-cni/utils"
	"github.com/tigera/libcalico-go/lib/api"
	"github.com/tigera/libcalico-go/lib/errors"
	cnet "github.com/tigera/libcalico-go/lib/net"
)

var hostname string

func init() {
	// This ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()

	hostname, _ = os.Hostname()
}

func cmdAdd(args *skel.CmdArgs) error {
	// Unmarshall the network config, and perform validation
	conf := NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("failed to load netconf: %v", err)
	}

	ConfigureLogging(conf.LogLevel)

	workloadID, orchestratorID, err := GetIdentifiers(args)
	if err != nil {
		return err
	}

	logger := CreateContextLogger(workloadID)

	// Allow the hostname to be overridden by the network config
	if conf.Hostname != "" {
		hostname = conf.Hostname
	}

	logger.WithFields(log.Fields{
		"OrchestratorID": orchestratorID,
		"Hostname":       hostname,
	}).Info("Extracted identifiers")

	calicoClient, err := CreateClient(conf)
	if err != nil {
		return err
	}
	// Always check if there's an existing endpoint.
	endpoints, err := calicoClient.WorkloadEndpoints().List(api.WorkloadEndpointMetadata{
		Hostname:       hostname,
		OrchestratorID: orchestratorID,
		WorkloadID:     workloadID})
	if err != nil {
		return err
	}

	logger.Debug("Retrieved endpoints: %v", endpoints)

	var endpoint *api.WorkloadEndpoint
	if len(endpoints.Items) == 1 {
		endpoint = &endpoints.Items[0]
	}

	fmt.Fprintf(os.Stderr, "Calico CNI checking for existing endpoint: %v\n", endpoint)

	// Collect the result in this variable - this is ultimately what gets "returned" by this function by printing
	// it to stdout.
	var result *types.Result

	// If running under Kubernetes then branch off into the kubernetes code, otherwise handle everything in this
	// function.
	if orchestratorID == "k8s" {
		if result, err = k8s.CmdAddK8s(args, conf, hostname, calicoClient, endpoint); err != nil {
			return err
		}
	} else {
		// Default CNI behavior - use the CNI network name as the Calico profile.
		profileID := conf.Name

		if endpoint != nil {
			// There is an existing endpoint - no need to create another.
			// This occurs when adding an existing container to a new CNI network
			// Find the IP address from the endpoint and use that in the response.
			// Don't create the veth or do any networking.
			// Just update the profile on the endpoint. The profile will be created if needed during the
			// profile processing step.
			fmt.Fprintf(os.Stderr, "Calico CNI appending profile: %s\n", profileID)
			endpoint.Spec.Profiles = append(endpoint.Spec.Profiles, profileID)
			result, err = CreateResultFromEndpoint(endpoint)
			logger.WithField("result", result).Debug("Created result from endpoint")
			if err != nil {
				return err
			}
		} else {
			// There's no existing endpoint, so we need to do the following:
			// 1) Call the configured IPAM plugin to get IP address(es)
			// 2) Configure the Calico endpoint
			// 3) Create the veth, configuring it on both the host and container namespace.

			// 1) Run the IPAM plugin and make sure there's an IP address returned.
			result, err = ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
			logger.WithField("result", result).Info("Got result from IPAM plugin")
			if err != nil {
				return err
			}

			// Parse endpoint labels passed in by Mesos, and store in a map.
			labels := map[string]string{}
			for _, label := range conf.Args.Mesos.NetworkInfo.Labels.Labels {
				labels[label.Key] = label.Value
			}

			// 2) Create the endpoint object
			endpoint = api.NewWorkloadEndpoint()
			endpoint.Metadata.Name = args.IfName
			endpoint.Metadata.Hostname = hostname
			endpoint.Metadata.OrchestratorID = orchestratorID
			endpoint.Metadata.WorkloadID = workloadID
			endpoint.Metadata.Labels = labels
			endpoint.Spec.Profiles = []string{profileID}

			logger.WithField("endpoint", endpoint).Debug("Populated endpoint (without nets)")
			if err = PopulateEndpointNets(endpoint, result); err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}
			logger.WithField("endpoint", endpoint).Info("Populated endpoint (with nets)")

			fmt.Fprintf(os.Stderr, "Calico CNI using IPs: %s\n", endpoint.Spec.IPNetworks)

			// 3) Set up the veth
			hostVethName, contVethMac, err := DoNetworking(args, conf, result)
			if err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}

			logger.WithFields(log.Fields{
				"HostVethName":     hostVethName,
				"ContainerVethMac": contVethMac,
			}).Info("Networked namespace")

			mac, err := net.ParseMAC(contVethMac)
			if err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}

			endpoint.Spec.MAC = cnet.MAC{HardwareAddr: mac}
			endpoint.Spec.InterfaceName = hostVethName
		}

		// Write the endpoint object (either the newly created one, or the updated one with a new ProfileIDs).
		if _, err := calicoClient.WorkloadEndpoints().Apply(endpoint); err != nil {
			// Cleanup IP allocation and return the error.
			ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
			return err
		}

		logger.WithField("endpoint", endpoint).Info("Wrote endpoint to datastore")
	}

	// Handle profile creation - this is only done if there isn't a specific policy handler.
	if conf.Policy.PolicyType == "" {
		logger.Debug("Handling profiles")
		// Start by checking if the profile already exists. If it already exists then there is no work to do.
		// The CNI plugin never updates a profile.
		exists := true
		_, err = calicoClient.Profiles().Get(api.ProfileMetadata{Name: conf.Name})
		if err != nil {
			_, ok := err.(errors.ErrorResourceDoesNotExist)
			if ok {
				exists = false
			} else {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}
		}

		if !exists {
			// The profile doesn't exist so needs to be created. The rules vary depending on whether k8s is being used.
			// Under k8s (without full policy support) the rule is permissive and allows all traffic.
			// Otherwise, incoming traffic is only allowed from profiles with the same tag.
			fmt.Fprintf(os.Stderr, "Calico CNI creating profile: %s\n", conf.Name)
			var inboundRules []api.Rule
			if orchestratorID == "k8s" {
				inboundRules = []api.Rule{{Action: "allow"}}
			} else {
				inboundRules = []api.Rule{{Action: "allow", Source: api.EntityRule{Tag: conf.Name}}}
			}

			profile := api.NewProfile()
			profile.Metadata.Name = conf.Name
			profile.Spec.Tags = []string{conf.Name}
			profile.Spec.EgressRules = []api.Rule{{Action: "allow"}}
			profile.Spec.IngressRules = inboundRules

			logger.WithField("profile", profile).Info("Creating profile")

			if _, err := calicoClient.Profiles().Create(profile); err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}
		}
	}

	return result.Print()
}

func cmdDel(args *skel.CmdArgs) error {
	conf := NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("failed to load netconf: %v", err)
	}

	ConfigureLogging(conf.LogLevel)

	workloadID, orchestratorID, err := GetIdentifiers(args)
	if err != nil {
		return err
	}

	logger := CreateContextLogger(workloadID)

	// Allow the hostname to be overridden by the network config
	if conf.Hostname != "" {
		hostname = conf.Hostname
	}

	logger.WithFields(log.Fields{
		"WorkloadID":     workloadID,
		"OrchestratorID": orchestratorID,
		"Hostname":       hostname,
	}).Info("Extracted identifiers")

	// Always try to release the address. Don't deal with any errors till the endpoints are cleaned up.
	fmt.Fprintf(os.Stderr, "Calico CNI releasing IP address\n")
	ipamErr := ipam.ExecDel(conf.IPAM.Type, args.StdinData)

	if ipamErr != nil {
		logger.Error(ipamErr)
	}

	calicoClient, err := CreateClient(conf)
	if err != nil {
		return err
	}

	if err := calicoClient.WorkloadEndpoints().Delete(api.WorkloadEndpointMetadata{
		Hostname:       hostname,
		OrchestratorID: orchestratorID,
		WorkloadID:     workloadID}); err != nil {
		return err
	}

	// Only try to delete the device if a namespace was passed in.
	if args.Netns != "" {
		fmt.Fprintf(os.Stderr, "Calico CNI deleting device in netns %s\n", args.Netns)
		err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
			_, err = ip.DelLinkByNameAddr(args.IfName, netlink.FAMILY_V4)
			return err
		})

		if err != nil {
			return err
		}
	}

	// Return the IPAM error if there was one. The IPAM error will be lost if there was also an error in cleaning up
	// the device or endpoint, but crucially, the user will know the overall operation failed.
	return ipamErr
}

// VERSION is filled out during the build process (using git describe output)
var VERSION string

func main() {
	// Display the version on "-v", otherwise just delegate to the skel code.
	// Use a new flag set so as not to conflict with existing libraries which use "flag"
	flagSet := flag.NewFlagSet("Calico", flag.ExitOnError)

	version := flagSet.Bool("v", false, "Display version")
	err := flagSet.Parse(os.Args[1:])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	if err := AddIgnoreUnknownArgs(); err != nil {
		os.Exit(1)
	}

	skel.PluginMain(cmdAdd, cmdDel)
}
<commit_msg>Add logs showing the IPAM plugin path<commit_after>// Copyright 2015 Tigera Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"runtime"

	"github.com/vishvananda/netlink"

	"net"

	log "github.com/Sirupsen/logrus"
	"github.com/containernetworking/cni/pkg/ip"
	"github.com/containernetworking/cni/pkg/ipam"
	"github.com/containernetworking/cni/pkg/ns"
	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/projectcalico/calico-cni/k8s"
	. "github.com/projectcalico/calico-cni/utils"
	"github.com/tigera/libcalico-go/lib/api"
	"github.com/tigera/libcalico-go/lib/errors"
	cnet "github.com/tigera/libcalico-go/lib/net"
)

var hostname string

func init() {
	// This ensures that main runs only on main thread (thread group leader).
	// since namespace ops (unshare, setns) are done for a single thread, we
	// must ensure that the goroutine does not jump from OS thread to thread
	runtime.LockOSThread()

	hostname, _ = os.Hostname()
}

func cmdAdd(args *skel.CmdArgs) error {
	// Unmarshall the network config, and perform validation
	conf := NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("failed to load netconf: %v", err)
	}

	ConfigureLogging(conf.LogLevel)

	workloadID, orchestratorID, err := GetIdentifiers(args)
	if err != nil {
		return err
	}

	logger := CreateContextLogger(workloadID)

	// Allow the hostname to be overridden by the network config
	if conf.Hostname != "" {
		hostname = conf.Hostname
	}

	logger.WithFields(log.Fields{
		"OrchestratorID": orchestratorID,
		"Hostname":       hostname,
	}).Info("Extracted identifiers")

	calicoClient, err := CreateClient(conf)
	if err != nil {
		return err
	}
	// Always check if there's an existing endpoint.
	endpoints, err := calicoClient.WorkloadEndpoints().List(api.WorkloadEndpointMetadata{
		Hostname:       hostname,
		OrchestratorID: orchestratorID,
		WorkloadID:     workloadID})
	if err != nil {
		return err
	}

	logger.Debug("Retrieved endpoints: %v", endpoints)

	var endpoint *api.WorkloadEndpoint
	if len(endpoints.Items) == 1 {
		endpoint = &endpoints.Items[0]
	}

	fmt.Fprintf(os.Stderr, "Calico CNI checking for existing endpoint: %v\n", endpoint)

	// Collect the result in this variable - this is ultimately what gets "returned" by this function by printing
	// it to stdout.
	var result *types.Result

	// If running under Kubernetes then branch off into the kubernetes code, otherwise handle everything in this
	// function.
	if orchestratorID == "k8s" {
		if result, err = k8s.CmdAddK8s(args, conf, hostname, calicoClient, endpoint); err != nil {
			return err
		}
	} else {
		// Default CNI behavior - use the CNI network name as the Calico profile.
		profileID := conf.Name

		if endpoint != nil {
			// There is an existing endpoint - no need to create another.
			// This occurs when adding an existing container to a new CNI network
			// Find the IP address from the endpoint and use that in the response.
			// Don't create the veth or do any networking.
			// Just update the profile on the endpoint. The profile will be created if needed during the
			// profile processing step.
			fmt.Fprintf(os.Stderr, "Calico CNI appending profile: %s\n", profileID)
			endpoint.Spec.Profiles = append(endpoint.Spec.Profiles, profileID)
			result, err = CreateResultFromEndpoint(endpoint)
			logger.WithField("result", result).Debug("Created result from endpoint")
			if err != nil {
				return err
			}
		} else {
			// There's no existing endpoint, so we need to do the following:
			// 1) Call the configured IPAM plugin to get IP address(es)
			// 2) Configure the Calico endpoint
			// 3) Create the veth, configuring it on both the host and container namespace.

			// 1) Run the IPAM plugin and make sure there's an IP address returned.
			logger.WithFields(log.Fields{"paths": os.Getenv("CNI_PATH"),
				"type": conf.IPAM.Type}).Debug("Looking for IPAM plugin in paths")
			result, err = ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
			logger.WithField("result", result).Info("Got result from IPAM plugin")
			if err != nil {
				return err
			}

			// Parse endpoint labels passed in by Mesos, and store in a map.
			labels := map[string]string{}
			for _, label := range conf.Args.Mesos.NetworkInfo.Labels.Labels {
				labels[label.Key] = label.Value
			}

			// 2) Create the endpoint object
			endpoint = api.NewWorkloadEndpoint()
			endpoint.Metadata.Name = args.IfName
			endpoint.Metadata.Hostname = hostname
			endpoint.Metadata.OrchestratorID = orchestratorID
			endpoint.Metadata.WorkloadID = workloadID
			endpoint.Metadata.Labels = labels
			endpoint.Spec.Profiles = []string{profileID}

			logger.WithField("endpoint", endpoint).Debug("Populated endpoint (without nets)")
			if err = PopulateEndpointNets(endpoint, result); err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}
			logger.WithField("endpoint", endpoint).Info("Populated endpoint (with nets)")

			fmt.Fprintf(os.Stderr, "Calico CNI using IPs: %s\n", endpoint.Spec.IPNetworks)

			// 3) Set up the veth
			hostVethName, contVethMac, err := DoNetworking(args, conf, result)
			if err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}

			logger.WithFields(log.Fields{
				"HostVethName":     hostVethName,
				"ContainerVethMac": contVethMac,
			}).Info("Networked namespace")

			mac, err := net.ParseMAC(contVethMac)
			if err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}

			endpoint.Spec.MAC = cnet.MAC{HardwareAddr: mac}
			endpoint.Spec.InterfaceName = hostVethName
		}

		// Write the endpoint object (either the newly created one, or the updated one with a new ProfileIDs).
		if _, err := calicoClient.WorkloadEndpoints().Apply(endpoint); err != nil {
			// Cleanup IP allocation and return the error.
			ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
			return err
		}

		logger.WithField("endpoint", endpoint).Info("Wrote endpoint to datastore")
	}

	// Handle profile creation - this is only done if there isn't a specific policy handler.
	if conf.Policy.PolicyType == "" {
		logger.Debug("Handling profiles")
		// Start by checking if the profile already exists. If it already exists then there is no work to do.
		// The CNI plugin never updates a profile.
		exists := true
		_, err = calicoClient.Profiles().Get(api.ProfileMetadata{Name: conf.Name})
		if err != nil {
			_, ok := err.(errors.ErrorResourceDoesNotExist)
			if ok {
				exists = false
			} else {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}
		}

		if !exists {
			// The profile doesn't exist so needs to be created. The rules vary depending on whether k8s is being used.
			// Under k8s (without full policy support) the rule is permissive and allows all traffic.
			// Otherwise, incoming traffic is only allowed from profiles with the same tag.
			fmt.Fprintf(os.Stderr, "Calico CNI creating profile: %s\n", conf.Name)
			var inboundRules []api.Rule
			if orchestratorID == "k8s" {
				inboundRules = []api.Rule{{Action: "allow"}}
			} else {
				inboundRules = []api.Rule{{Action: "allow", Source: api.EntityRule{Tag: conf.Name}}}
			}

			profile := api.NewProfile()
			profile.Metadata.Name = conf.Name
			profile.Spec.Tags = []string{conf.Name}
			profile.Spec.EgressRules = []api.Rule{{Action: "allow"}}
			profile.Spec.IngressRules = inboundRules

			logger.WithField("profile", profile).Info("Creating profile")

			if _, err := calicoClient.Profiles().Create(profile); err != nil {
				// Cleanup IP allocation and return the error.
				ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
				return err
			}
		}
	}

	return result.Print()
}

func cmdDel(args *skel.CmdArgs) error {
	conf := NetConf{}
	if err := json.Unmarshal(args.StdinData, &conf); err != nil {
		return fmt.Errorf("failed to load netconf: %v", err)
	}

	ConfigureLogging(conf.LogLevel)

	workloadID, orchestratorID, err := GetIdentifiers(args)
	if err != nil {
		return err
	}

	logger := CreateContextLogger(workloadID)

	// Allow the hostname to be overridden by the network config
	if conf.Hostname != "" {
		hostname = conf.Hostname
	}

	logger.WithFields(log.Fields{
		"WorkloadID":     workloadID,
		"OrchestratorID": orchestratorID,
		"Hostname":       hostname,
	}).Info("Extracted identifiers")

	// Always try to release the address. Don't deal with any errors till the endpoints are cleaned up.
	fmt.Fprintf(os.Stderr, "Calico CNI releasing IP address\n")
	logger.WithFields(log.Fields{"paths": os.Getenv("CNI_PATH"),
		"type": conf.IPAM.Type}).Debug("Looking for IPAM plugin in paths")
	ipamErr := ipam.ExecDel(conf.IPAM.Type, args.StdinData)

	if ipamErr != nil {
		logger.Error(ipamErr)
	}

	calicoClient, err := CreateClient(conf)
	if err != nil {
		return err
	}

	if err := calicoClient.WorkloadEndpoints().Delete(api.WorkloadEndpointMetadata{
		Hostname:       hostname,
		OrchestratorID: orchestratorID,
		WorkloadID:     workloadID}); err != nil {
		return err
	}

	// Only try to delete the device if a namespace was passed in.
	if args.Netns != "" {
		fmt.Fprintf(os.Stderr, "Calico CNI deleting device in netns %s\n", args.Netns)
		err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
			_, err = ip.DelLinkByNameAddr(args.IfName, netlink.FAMILY_V4)
			return err
		})

		if err != nil {
			return err
		}
	}

	// Return the IPAM error if there was one. The IPAM error will be lost if there was also an error in cleaning up
	// the device or endpoint, but crucially, the user will know the overall operation failed.
	return ipamErr
}

// VERSION is filled out during the build process (using git describe output)
var VERSION string

func main() {
	// Display the version on "-v", otherwise just delegate to the skel code.
	// Use a new flag set so as not to conflict with existing libraries which use "flag"
	flagSet := flag.NewFlagSet("Calico", flag.ExitOnError)

	version := flagSet.Bool("v", false, "Display version")
	err := flagSet.Parse(os.Args[1:])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	if err := AddIgnoreUnknownArgs(); err != nil {
		os.Exit(1)
	}

	skel.PluginMain(cmdAdd, cmdDel)
}
<|endoftext|>


<commit_before>package gumble

import (
	"github.com/layeh/gumble/gumble/MumbleProto"
)

// TargetLoopback is a special voice target which causes any audio sent to the
// server to be returned to the client.
//
// Its ID should not be modified, and it does not have to to be sent to the
// server before use.
var TargetLoopback *VoiceTarget

func init() {
	TargetLoopback = &VoiceTarget{
		ID: 31,
	}
}

type voiceTargetChannel struct {
	channel          *Channel
	links, recursive bool
}

// VoiceTarget represents a set of users and/or channels that the client can
// whisper to.
type VoiceTarget struct {
	// The voice target ID. This value must be in the range [1, 30].
	ID       uint32
	users    []*User
	channels []*voiceTargetChannel
}

// Clear removes all users and channels from the voice target.
func (vt *VoiceTarget) Clear() {
	vt.users = nil
	vt.channels = nil
}

// AddUser adds a user to the voice target.
func (vt *VoiceTarget) AddUser(user *User) {
	vt.users = append(vt.users, user)
}

// AddChannel adds a user to the voice target.
func (vt *VoiceTarget) AddChannel(channel *Channel, recursive, links bool) {
	vt.channels = append(vt.channels, &voiceTargetChannel{
		channel:   channel,
		links:     links,
		recursive: recursive,
	})
}

func (vt *VoiceTarget) writeMessage(client *Client) error {
	packet := MumbleProto.VoiceTarget{
		Id:      &vt.ID,
		Targets: make([]*MumbleProto.VoiceTarget_Target, 0, len(vt.users)+len(vt.channels)),
	}
	for _, user := range vt.users {
		packet.Targets = append(packet.Targets, &MumbleProto.VoiceTarget_Target{
			Session: []uint32{user.Session},
		})
	}
	for _, vtChannel := range vt.channels {
		packet.Targets = append(packet.Targets, &MumbleProto.VoiceTarget_Target{
			ChannelId: &vtChannel.channel.ID,
			Links:     &vtChannel.links,
			Children:  &vtChannel.recursive,
		})
	}

	proto := protoMessage{&packet}
	return proto.writeMessage(client)
}
<commit_msg>add group support to VoiceTarget (fixes #12)<commit_after>package gumble

import (
	"github.com/layeh/gumble/gumble/MumbleProto"
)

// TargetLoopback is a special voice target which causes any audio sent to the
// server to be returned to the client.
//
// Its ID should not be modified, and it does not have to to be sent to the
// server before use.
var TargetLoopback *VoiceTarget

func init() {
	TargetLoopback = &VoiceTarget{
		ID: 31,
	}
}

type voiceTargetChannel struct {
	channel          *Channel
	links, recursive bool
	group            string
}

// VoiceTarget represents a set of users and/or channels that the client can
// whisper to.
type VoiceTarget struct {
	// The voice target ID. This value must be in the range [1, 30].
	ID       uint32
	users    []*User
	channels []*voiceTargetChannel
}

// Clear removes all users and channels from the voice target.
func (vt *VoiceTarget) Clear() {
	vt.users = nil
	vt.channels = nil
}

// AddUser adds a user to the voice target.
func (vt *VoiceTarget) AddUser(user *User) {
	vt.users = append(vt.users, user)
}

// AddChannel adds a user to the voice target. If group is non-empty, only
// users belonging to that ACL group will be targeted.
func (vt *VoiceTarget) AddChannel(channel *Channel, recursive, links bool, group string) {
	vt.channels = append(vt.channels, &voiceTargetChannel{
		channel:   channel,
		links:     links,
		recursive: recursive,
		group:     group,
	})
}

func (vt *VoiceTarget) writeMessage(client *Client) error {
	packet := MumbleProto.VoiceTarget{
		Id:      &vt.ID,
		Targets: make([]*MumbleProto.VoiceTarget_Target, 0, len(vt.users)+len(vt.channels)),
	}
	for _, user := range vt.users {
		packet.Targets = append(packet.Targets, &MumbleProto.VoiceTarget_Target{
			Session: []uint32{user.Session},
		})
	}
	for _, vtChannel := range vt.channels {
		target := &MumbleProto.VoiceTarget_Target{
			ChannelId: &vtChannel.channel.ID,
			Links:     &vtChannel.links,
			Children:  &vtChannel.recursive,
		}
		if vtChannel.group != "" {
			target.Group = &vtChannel.group
		}
		packet.Targets = append(packet.Targets, target)
	}

	proto := protoMessage{&packet}
	return proto.writeMessage(client)
}
<|endoftext|>