<commit_before>//  Copyright (c) 2012 Couchbase, 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 rest

import (
	"encoding/json"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/couchbaselabs/sync_gateway/auth"
	"github.com/couchbaselabs/sync_gateway/base"
	"github.com/couchbaselabs/sync_gateway/db"
)

//////// DATABASE MAINTENANCE:

// "Create" a database (actually just register an existing bucket)
func (h *handler) handleCreateDB() error {
	h.assertAdminOnly()
	dbName := h.PathVar("newdb")
	var config *DbConfig
	if err := h.readJSONInto(&config); err != nil {
		return err
	}
	if err := config.setup(dbName); err != nil {
		return err
	}
	if _, err := h.server.AddDatabaseFromConfig(config); err != nil {
		return err
	}
	return base.HTTPErrorf(http.StatusCreated, "created")
}

// Get admin database info
func (h *handler) handleGetDbConfig() error {
	h.writeJSON(h.server.GetDatabaseConfig(h.db.Name))
	return nil
}

// "Delete" a database (it doesn't actually do anything to the underlying bucket)
func (h *handler) handleDeleteDB() error {
	h.assertAdminOnly()
	if !h.server.RemoveDatabase(h.db.Name) {
		return base.HTTPErrorf(http.StatusNotFound, "missing")
	}
	return nil
}

// raw document access for admin api

func (h *handler) handleGetRawDoc() error {
	h.assertAdminOnly()
	docid := h.PathVar("docid")
	doc, err := h.db.GetDoc(docid)
	if doc != nil {
		h.writeJSON(doc)
	}
	return err
}

func (h *handler) handleGetLogging() error {
	h.writeJSON(base.GetLogKeys())
	return nil
}

func (h *handler) handleSetLogging() error {
	body, err := h.readBody()
	if err != nil {
		return nil
	}
	if h.getQuery("level") != "" {
		base.SetLogLevel(int(h.getRestrictedIntQuery("level", uint64(base.LogLevel()), 1, 3)))
		if len(body) == 0 {
			return nil // empty body is OK if request is just setting the log level
		}
	}
	var keys map[string]bool
	if err := json.Unmarshal(body, &keys); err != nil {
		return base.HTTPErrorf(http.StatusBadRequest, "Invalid JSON or non-boolean values")
	}
	base.UpdateLogKeys(keys, h.rq.Method == "PUT")
	return nil
}

//////// USERS & ROLES:

func internalUserName(name string) string {
	if name == "GUEST" {
		return ""
	}
	return name
}

func externalUserName(name string) string {
	if name == "" {
		return "GUEST"
	}
	return name
}

func marshalPrincipal(princ auth.Principal) ([]byte, error) {
	name := externalUserName(princ.Name())
	info := db.PrincipalConfig{
		Name:             &name,
		ExplicitChannels: princ.ExplicitChannels().AsSet(),
	}
	if user, ok := princ.(auth.User); ok {
		info.Channels = user.InheritedChannels().AsSet()
		info.Email = user.Email()
		info.Disabled = user.Disabled()
		info.ExplicitRoleNames = user.ExplicitRoles().AllChannels()
		info.RoleNames = user.RoleNames().AllChannels()
	} else {
		info.Channels = princ.Channels().AsSet()
	}
	return json.Marshal(info)
}

// Handles PUT and POST for a user or a role.
func (h *handler) updatePrincipal(name string, isUser bool) error {
	h.assertAdminOnly()
	// Unmarshal the request body into a PrincipalConfig struct:
	body, _ := h.readBody()
	var newInfo db.PrincipalConfig
	var err error
	if err = json.Unmarshal(body, &newInfo); err != nil {
		return err
	}

	if h.rq.Method == "POST" {
		// On POST, take the name from the "name" property in the request body:
		if newInfo.Name == nil {
			return base.HTTPErrorf(http.StatusBadRequest, "Missing name property")
		}
	} else {
		// ON PUT, verify the name matches, if given:
		if newInfo.Name == nil {
			newInfo.Name = &name
		} else if *newInfo.Name != name {
			return base.HTTPErrorf(http.StatusBadRequest, "Name mismatch (can't change name)")
		}
	}

	internalName := internalUserName(*newInfo.Name)
	newInfo.Name = &internalName
	replaced, err := h.db.UpdatePrincipal(newInfo, isUser, h.rq.Method != "POST")
	if err != nil {
		return err
	} else if replaced {
		// on update with a new password, remove previous user sessions
		if newInfo.Password != nil {
			err = h.db.DeleteUserSessions(*newInfo.Name)
			if err != nil {
				return err
			}
		}
		h.writeStatus(http.StatusOK, "OK")
	} else {
		h.writeStatus(http.StatusCreated, "Created")
	}
	return nil
}

// Handles PUT or POST to /_user/*
func (h *handler) putUser() error {
	username := mux.Vars(h.rq)["name"]
	return h.updatePrincipal(username, true)
}

// Handles PUT or POST to /_role/*
func (h *handler) putRole() error {
	rolename := mux.Vars(h.rq)["name"]
	return h.updatePrincipal(rolename, false)
}

func (h *handler) deleteUser() error {
	h.assertAdminOnly()
	user, err := h.db.Authenticator().GetUser(mux.Vars(h.rq)["name"])
	if user == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}
	return h.db.Authenticator().Delete(user)
}

func (h *handler) deleteRole() error {
	h.assertAdminOnly()
	role, err := h.db.Authenticator().GetRole(mux.Vars(h.rq)["name"])
	if role == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}
	return h.db.Authenticator().Delete(role)
}

func (h *handler) getUserInfo() error {
	h.assertAdminOnly()
	user, err := h.db.Authenticator().GetUser(internalUserName(mux.Vars(h.rq)["name"]))
	if user == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}

	bytes, err := marshalPrincipal(user)
	h.response.Write(bytes)
	return err
}

func (h *handler) getRoleInfo() error {
	h.assertAdminOnly()
	role, err := h.db.Authenticator().GetRole(mux.Vars(h.rq)["name"])
	if role == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}
	bytes, err := marshalPrincipal(role)
	h.response.Write(bytes)
	return err
}

func (h *handler) getUsers() error {
	users, _, err := h.db.AllPrincipalIDs()
	if err != nil {
		return err
	}
	bytes, err := json.Marshal(users)
	h.response.Write(bytes)
	return err
}

func (h *handler) getRoles() error {
	_, roles, err := h.db.AllPrincipalIDs()
	if err != nil {
		return err
	}
	bytes, err := json.Marshal(roles)
	h.response.Write(bytes)
	return err
}
<commit_msg>return JSON on delete<commit_after>//  Copyright (c) 2012 Couchbase, 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 rest

import (
	"encoding/json"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/couchbaselabs/sync_gateway/auth"
	"github.com/couchbaselabs/sync_gateway/base"
	"github.com/couchbaselabs/sync_gateway/db"
)

//////// DATABASE MAINTENANCE:

// "Create" a database (actually just register an existing bucket)
func (h *handler) handleCreateDB() error {
	h.assertAdminOnly()
	dbName := h.PathVar("newdb")
	var config *DbConfig
	if err := h.readJSONInto(&config); err != nil {
		return err
	}
	if err := config.setup(dbName); err != nil {
		return err
	}
	if _, err := h.server.AddDatabaseFromConfig(config); err != nil {
		return err
	}
	return base.HTTPErrorf(http.StatusCreated, "created")
}

// Get admin database info
func (h *handler) handleGetDbConfig() error {
	h.writeJSON(h.server.GetDatabaseConfig(h.db.Name))
	return nil
}

// "Delete" a database (it doesn't actually do anything to the underlying bucket)
func (h *handler) handleDeleteDB() error {
	h.assertAdminOnly()
	if !h.server.RemoveDatabase(h.db.Name) {
		return base.HTTPErrorf(http.StatusNotFound, "missing")
	}
	h.response.Write([]byte("{}"))
	return nil
}

// raw document access for admin api

func (h *handler) handleGetRawDoc() error {
	h.assertAdminOnly()
	docid := h.PathVar("docid")
	doc, err := h.db.GetDoc(docid)
	if doc != nil {
		h.writeJSON(doc)
	}
	return err
}

func (h *handler) handleGetLogging() error {
	h.writeJSON(base.GetLogKeys())
	return nil
}

func (h *handler) handleSetLogging() error {
	body, err := h.readBody()
	if err != nil {
		return nil
	}
	if h.getQuery("level") != "" {
		base.SetLogLevel(int(h.getRestrictedIntQuery("level", uint64(base.LogLevel()), 1, 3)))
		if len(body) == 0 {
			return nil // empty body is OK if request is just setting the log level
		}
	}
	var keys map[string]bool
	if err := json.Unmarshal(body, &keys); err != nil {
		return base.HTTPErrorf(http.StatusBadRequest, "Invalid JSON or non-boolean values")
	}
	base.UpdateLogKeys(keys, h.rq.Method == "PUT")
	return nil
}

//////// USERS & ROLES:

func internalUserName(name string) string {
	if name == "GUEST" {
		return ""
	}
	return name
}

func externalUserName(name string) string {
	if name == "" {
		return "GUEST"
	}
	return name
}

func marshalPrincipal(princ auth.Principal) ([]byte, error) {
	name := externalUserName(princ.Name())
	info := db.PrincipalConfig{
		Name:             &name,
		ExplicitChannels: princ.ExplicitChannels().AsSet(),
	}
	if user, ok := princ.(auth.User); ok {
		info.Channels = user.InheritedChannels().AsSet()
		info.Email = user.Email()
		info.Disabled = user.Disabled()
		info.ExplicitRoleNames = user.ExplicitRoles().AllChannels()
		info.RoleNames = user.RoleNames().AllChannels()
	} else {
		info.Channels = princ.Channels().AsSet()
	}
	return json.Marshal(info)
}

// Handles PUT and POST for a user or a role.
func (h *handler) updatePrincipal(name string, isUser bool) error {
	h.assertAdminOnly()
	// Unmarshal the request body into a PrincipalConfig struct:
	body, _ := h.readBody()
	var newInfo db.PrincipalConfig
	var err error
	if err = json.Unmarshal(body, &newInfo); err != nil {
		return err
	}

	if h.rq.Method == "POST" {
		// On POST, take the name from the "name" property in the request body:
		if newInfo.Name == nil {
			return base.HTTPErrorf(http.StatusBadRequest, "Missing name property")
		}
	} else {
		// ON PUT, verify the name matches, if given:
		if newInfo.Name == nil {
			newInfo.Name = &name
		} else if *newInfo.Name != name {
			return base.HTTPErrorf(http.StatusBadRequest, "Name mismatch (can't change name)")
		}
	}

	internalName := internalUserName(*newInfo.Name)
	newInfo.Name = &internalName
	replaced, err := h.db.UpdatePrincipal(newInfo, isUser, h.rq.Method != "POST")
	if err != nil {
		return err
	} else if replaced {
		// on update with a new password, remove previous user sessions
		if newInfo.Password != nil {
			err = h.db.DeleteUserSessions(*newInfo.Name)
			if err != nil {
				return err
			}
		}
		h.writeStatus(http.StatusOK, "OK")
	} else {
		h.writeStatus(http.StatusCreated, "Created")
	}
	return nil
}

// Handles PUT or POST to /_user/*
func (h *handler) putUser() error {
	username := mux.Vars(h.rq)["name"]
	return h.updatePrincipal(username, true)
}

// Handles PUT or POST to /_role/*
func (h *handler) putRole() error {
	rolename := mux.Vars(h.rq)["name"]
	return h.updatePrincipal(rolename, false)
}

func (h *handler) deleteUser() error {
	h.assertAdminOnly()
	user, err := h.db.Authenticator().GetUser(mux.Vars(h.rq)["name"])
	if user == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}
	return h.db.Authenticator().Delete(user)
}

func (h *handler) deleteRole() error {
	h.assertAdminOnly()
	role, err := h.db.Authenticator().GetRole(mux.Vars(h.rq)["name"])
	if role == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}
	return h.db.Authenticator().Delete(role)
}

func (h *handler) getUserInfo() error {
	h.assertAdminOnly()
	user, err := h.db.Authenticator().GetUser(internalUserName(mux.Vars(h.rq)["name"]))
	if user == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}

	bytes, err := marshalPrincipal(user)
	h.response.Write(bytes)
	return err
}

func (h *handler) getRoleInfo() error {
	h.assertAdminOnly()
	role, err := h.db.Authenticator().GetRole(mux.Vars(h.rq)["name"])
	if role == nil {
		if err == nil {
			err = kNotFoundError
		}
		return err
	}
	bytes, err := marshalPrincipal(role)
	h.response.Write(bytes)
	return err
}

func (h *handler) getUsers() error {
	users, _, err := h.db.AllPrincipalIDs()
	if err != nil {
		return err
	}
	bytes, err := json.Marshal(users)
	h.response.Write(bytes)
	return err
}

func (h *handler) getRoles() error {
	_, roles, err := h.db.AllPrincipalIDs()
	if err != nil {
		return err
	}
	bytes, err := json.Marshal(roles)
	h.response.Write(bytes)
	return err
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2015-present  Laszlo Csontos
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>. */
//

package appengine

import (
	"appengine"
	"appengine/datastore"

	"net/http"
	"strconv"
	"strings"

	"github.com/lcsontos/uwatch/catalog"
	"github.com/lcsontos/uwatch/registry"
	"github.com/lcsontos/uwatch/store"
)

type Store struct {
	context *appengine.Context
}

type StoreFactory struct {
}

const _KIND = "LongVideoUrl"

func (store Store) FindLongVideoUrlByID(id int64) (*catalog.LongVideoUrl, error) {
	key := datastore.NewKey(*store.context, _KIND, "", id, nil)

	return store.getLongVideoUrl(key)
}

func (store Store) FindLongVideoUrlByVideoKey(videoKey *catalog.VideoKey) (*catalog.LongVideoUrl, error) {
	key := datastore.NewKey(*store.context, _KIND, videoKey.String(), 0, nil)

	return store.getLongVideoUrl(key)
}

func (storeFactory StoreFactory) NewStore(args interface{}) store.VideoStore {
	req := args.(*http.Request)

	context := appengine.NewContext(req)

	return Store{context: &context}
}

func (store Store) SaveLongVideoUrl(longVideoUrl *catalog.LongVideoUrl) error {
	videoKey := longVideoUrl.VideoKey

	key := datastore.NewKey(*store.context, _KIND, videoKey.String(), 0, nil)

	key, err := datastore.Put(*store.context, key, longVideoUrl)

	if err != nil {
		return err
	}

	longVideoUrl.Id = key.IntID()

	return nil
}

func (s Store) getLongVideoUrl(key *datastore.Key) (*catalog.LongVideoUrl, error) {
	var longVideoUrl catalog.LongVideoUrl

	err := datastore.Get(*s.context, key, &longVideoUrl)

	switch {
	case err == nil:
		return &longVideoUrl, nil
	case err == datastore.ErrNoSuchEntity:
		parts := strings.Split(key.StringID(), "@")

		var videoKey *catalog.VideoKey = nil

		if len(parts) == 2 {
			videoType, _ := strconv.Atoi(parts[0])

			videoKey = &catalog.VideoKey{
				VideoType: catalog.VideoType(videoType),
				VideoId:   parts[1],
			}
		}

		return nil, &store.NoSuchLongVideoUrl{
			Id: key.IntID(), VideoKey: videoKey,
		}
	default:
		return nil, err
	}
}

func init() {
	registry.RegisterVideoStore(&StoreFactory{})
}
<commit_msg>Issue #3: Separate LongVideoUrl and VideoKey into two entities<commit_after>//
// Copyright (C) 2015-present  Laszlo Csontos
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>. */
//

package appengine

import (
	"appengine"
	"appengine/datastore"

	"net/http"
	"strconv"
	"strings"

	"github.com/lcsontos/uwatch/catalog"
	"github.com/lcsontos/uwatch/registry"
	"github.com/lcsontos/uwatch/store"
)

type Store struct {
	context *appengine.Context
}

type StoreFactory struct {
}

const _KIND_LONG_VIDEO_URL = "LongVideoUrl"
const _KIND_VIDEO_KEY = "VideoKey"

func (store Store) FindLongVideoUrlByID(id int64) (*catalog.LongVideoUrl, error) {
	key := datastore.NewKey(*store.context, _KIND_VIDEO_KEY, "", id, nil)

	videoKey, err := store.getVideoKey(key)

	if err != nil {
		return nil, err
	}

	return store.FindLongVideoUrlByVideoKey(videoKey)
}

func (store Store) FindLongVideoUrlByVideoKey(videoKey *catalog.VideoKey) (*catalog.LongVideoUrl, error) {
	key := datastore.NewKey(*store.context, _KIND_LONG_VIDEO_URL, videoKey.String(), 0, nil)

	return store.getLongVideoUrl(key)
}

func (storeFactory StoreFactory) NewStore(args interface{}) store.VideoStore {
	req := args.(*http.Request)

	context := appengine.NewContext(req)

	return Store{context: &context}
}

func (store Store) SaveLongVideoUrl(longVideoUrl *catalog.LongVideoUrl) error {
	videoKey := longVideoUrl.VideoKey

	videoKeyKey := datastore.NewIncompleteKey(*store.context, _KIND_VIDEO_KEY, nil)
	videoKeyKey, err := datastore.Put(*store.context, videoKeyKey, videoKey)

	if err != nil {
		return err
	}

	longVideoUrlKey := datastore.NewKey(*store.context, _KIND_LONG_VIDEO_URL, videoKey.String(), 0, nil)
	longVideoUrlKey, err = datastore.Put(*store.context, longVideoUrlKey, longVideoUrl)

	longVideoUrl.Id = videoKeyKey.IntID()

	return nil
}

func (s Store) getLongVideoUrl(key *datastore.Key) (*catalog.LongVideoUrl, error) {
	var longVideoUrl catalog.LongVideoUrl

	err := datastore.Get(*s.context, key, &longVideoUrl)

	switch {
	case err == nil:
		return &longVideoUrl, nil
	case err == datastore.ErrNoSuchEntity:
		parts := strings.Split(key.StringID(), "@")

		var videoKey *catalog.VideoKey = nil

		if len(parts) == 2 {
			videoType, _ := strconv.Atoi(parts[0])

			videoKey = &catalog.VideoKey{
				VideoType: catalog.VideoType(videoType),
				VideoId:   parts[1],
			}
		}

		return nil, &store.NoSuchLongVideoUrl{
			Id: key.IntID(), VideoKey: videoKey,
		}
	default:
		return nil, err
	}
}

func (s Store) getVideoKey(key *datastore.Key) (*catalog.VideoKey, error) {
	var videoKey catalog.VideoKey

	err := datastore.Get(*s.context, key, &videoKey)

	switch {
	case err == nil:
		return &videoKey, nil
	case err == datastore.ErrNoSuchEntity:
		return nil, &store.NoSuchLongVideoUrl{Id: key.IntID()}
	default:
		return nil, err
	}
}

func init() {
	registry.RegisterVideoStore(&StoreFactory{})
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd 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 integration

import (
	"testing"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	"github.com/coreos/etcd/integration"
	"github.com/coreos/etcd/pkg/testutil"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func TestLeaseNotFoundError(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	kv := clientv3.NewKV(clus.RandClient())

	_, err := kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(clientv3.LeaseID(500)))
	if err != rpctypes.ErrLeaseNotFound {
		t.Fatalf("expected %v, got %v", rpctypes.ErrLeaseNotFound, err)
	}
}

func TestLeaseGrant(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	kv := clientv3.NewKV(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	_, err = kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(resp.ID))
	if err != nil {
		t.Fatalf("failed to create key with lease %v", err)
	}
}

func TestLeaseRevoke(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	kv := clientv3.NewKV(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	_, err = lapi.Revoke(context.Background(), clientv3.LeaseID(resp.ID))
	if err != nil {
		t.Errorf("failed to revoke lease %v", err)
	}

	_, err = kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(resp.ID))
	if err != rpctypes.ErrLeaseNotFound {
		t.Fatalf("err = %v, want %v", err, rpctypes.ErrLeaseNotFound)
	}
}

func TestLeaseKeepAliveOnce(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	_, err = lapi.KeepAliveOnce(context.Background(), resp.ID)
	if err != nil {
		t.Errorf("failed to keepalive lease %v", err)
	}

	_, err = lapi.KeepAliveOnce(context.Background(), clientv3.LeaseID(0))
	if err != rpctypes.ErrLeaseNotFound {
		t.Errorf("expected %v, got %v", rpctypes.ErrLeaseNotFound, err)
	}
}

func TestLeaseKeepAlive(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	rc, kerr := lapi.KeepAlive(context.Background(), resp.ID)
	if kerr != nil {
		t.Errorf("failed to keepalive lease %v", kerr)
	}

	kresp, ok := <-rc
	if !ok {
		t.Errorf("chan is closed, want not closed")
	}

	if kresp.ID != resp.ID {
		t.Errorf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	lapi.Close()

	_, ok = <-rc
	if ok {
		t.Errorf("chan is not closed, want lease Close() closes chan")
	}
}

// TODO: add a client that can connect to all the members of cluster via unix sock.
// TODO: test handle more complicated failures.
func TestLeaseKeepAliveHandleFailure(t *testing.T) {
	t.Skip("test it when we have a cluster client")

	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	// TODO: change this line to get a cluster client
	lapi := clientv3.NewLease(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	rc, kerr := lapi.KeepAlive(context.Background(), resp.ID)
	if kerr != nil {
		t.Errorf("failed to keepalive lease %v", kerr)
	}

	kresp := <-rc
	if kresp.ID != resp.ID {
		t.Errorf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	// restart the connected member.
	clus.Members[0].Stop(t)

	select {
	case <-rc:
		t.Fatalf("unexpected keepalive")
	case <-time.After(10*time.Second/3 + 1):
	}

	// recover the member.
	clus.Members[0].Restart(t)

	kresp = <-rc
	if kresp.ID != resp.ID {
		t.Errorf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	lapi.Close()

	_, ok := <-rc
	if ok {
		t.Errorf("chan is not closed, want lease Close() closes chan")
	}
}

type leaseCh struct {
	lid clientv3.LeaseID
	ch  <-chan *clientv3.LeaseKeepAliveResponse
}

// TestLeaseKeepAliveNotFound ensures a revoked lease won't stop other keep alives
func TestLeaseKeepAliveNotFound(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.RandClient()
	lchs := []leaseCh{}
	for i := 0; i < 3; i++ {
		resp, rerr := cli.Grant(context.TODO(), 5)
		if rerr != nil {
			t.Fatal(rerr)
		}
		kach, kaerr := cli.KeepAlive(context.Background(), resp.ID)
		if kaerr != nil {
			t.Fatal(kaerr)
		}
		lchs = append(lchs, leaseCh{resp.ID, kach})
	}

	if _, err := cli.Revoke(context.TODO(), lchs[1].lid); err != nil {
		t.Fatal(err)
	}

	<-lchs[0].ch
	if _, ok := <-lchs[0].ch; !ok {
		t.Fatalf("closed keepalive on wrong lease")
	}

	timec := time.After(5 * time.Second)
	for range lchs[1].ch {
		select {
		case <-timec:
			t.Fatalf("revoke did not close keep alive")
		default:
		}
	}
}

func TestLeaseGrantErrConnClosed(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)
	le := clientv3.NewLease(cli)

	donec := make(chan struct{})
	go func() {
		defer close(donec)
		_, err := le.Grant(context.TODO(), 5)
		if err != nil && err != grpc.ErrClientConnClosing {
			t.Fatalf("expected %v, got %v", grpc.ErrClientConnClosing, err)
		}
	}()

	if err := cli.Close(); err != nil {
		t.Fatal(err)
	}
	clus.TakeClient(0)

	select {
	case <-time.After(3 * time.Second):
		t.Fatal("le.Grant took too long")
	case <-donec:
	}
}

func TestLeaseGrantNewAfterClose(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)
	clus.TakeClient(0)
	if err := cli.Close(); err != nil {
		t.Fatal(err)
	}

	donec := make(chan struct{})
	go func() {
		le := clientv3.NewLease(cli)
		if _, err := le.Grant(context.TODO(), 5); err != grpc.ErrClientConnClosing {
			t.Fatalf("expected %v, got %v", grpc.ErrClientConnClosing, err)
		}
		close(donec)
	}()
	select {
	case <-time.After(3 * time.Second):
		t.Fatal("le.Grant took too long")
	case <-donec:
	}
}

func TestLeaseRevokeNewAfterClose(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)
	le := clientv3.NewLease(cli)
	resp, err := le.Grant(context.TODO(), 5)
	if err != nil {
		t.Fatal(err)
	}
	leaseID := resp.ID

	clus.TakeClient(0)
	if err := cli.Close(); err != nil {
		t.Fatal(err)
	}

	donec := make(chan struct{})
	go func() {
		if _, err := le.Revoke(context.TODO(), leaseID); err != grpc.ErrClientConnClosing {
			t.Fatalf("expected %v, got %v", grpc.ErrClientConnClosing, err)
		}
		close(donec)
	}()
	select {
	case <-time.After(3 * time.Second):
		t.Fatal("le.Revoke took too long")
	case <-donec:
	}
}
<commit_msg>clientv3/integration: tests for closing lease channel<commit_after>// Copyright 2016 The etcd 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 integration

import (
	"testing"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	"github.com/coreos/etcd/integration"
	"github.com/coreos/etcd/pkg/testutil"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func TestLeaseNotFoundError(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	kv := clientv3.NewKV(clus.RandClient())

	_, err := kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(clientv3.LeaseID(500)))
	if err != rpctypes.ErrLeaseNotFound {
		t.Fatalf("expected %v, got %v", rpctypes.ErrLeaseNotFound, err)
	}
}

func TestLeaseGrant(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	kv := clientv3.NewKV(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	_, err = kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(resp.ID))
	if err != nil {
		t.Fatalf("failed to create key with lease %v", err)
	}
}

func TestLeaseRevoke(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	kv := clientv3.NewKV(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	_, err = lapi.Revoke(context.Background(), clientv3.LeaseID(resp.ID))
	if err != nil {
		t.Errorf("failed to revoke lease %v", err)
	}

	_, err = kv.Put(context.TODO(), "foo", "bar", clientv3.WithLease(resp.ID))
	if err != rpctypes.ErrLeaseNotFound {
		t.Fatalf("err = %v, want %v", err, rpctypes.ErrLeaseNotFound)
	}
}

func TestLeaseKeepAliveOnce(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())
	defer lapi.Close()

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	_, err = lapi.KeepAliveOnce(context.Background(), resp.ID)
	if err != nil {
		t.Errorf("failed to keepalive lease %v", err)
	}

	_, err = lapi.KeepAliveOnce(context.Background(), clientv3.LeaseID(0))
	if err != rpctypes.ErrLeaseNotFound {
		t.Errorf("expected %v, got %v", rpctypes.ErrLeaseNotFound, err)
	}
}

func TestLeaseKeepAlive(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	lapi := clientv3.NewLease(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	rc, kerr := lapi.KeepAlive(context.Background(), resp.ID)
	if kerr != nil {
		t.Errorf("failed to keepalive lease %v", kerr)
	}

	kresp, ok := <-rc
	if !ok {
		t.Errorf("chan is closed, want not closed")
	}

	if kresp.ID != resp.ID {
		t.Errorf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	lapi.Close()

	_, ok = <-rc
	if ok {
		t.Errorf("chan is not closed, want lease Close() closes chan")
	}
}

// TODO: add a client that can connect to all the members of cluster via unix sock.
// TODO: test handle more complicated failures.
func TestLeaseKeepAliveHandleFailure(t *testing.T) {
	t.Skip("test it when we have a cluster client")

	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	// TODO: change this line to get a cluster client
	lapi := clientv3.NewLease(clus.RandClient())

	resp, err := lapi.Grant(context.Background(), 10)
	if err != nil {
		t.Errorf("failed to create lease %v", err)
	}

	rc, kerr := lapi.KeepAlive(context.Background(), resp.ID)
	if kerr != nil {
		t.Errorf("failed to keepalive lease %v", kerr)
	}

	kresp := <-rc
	if kresp.ID != resp.ID {
		t.Errorf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	// restart the connected member.
	clus.Members[0].Stop(t)

	select {
	case <-rc:
		t.Fatalf("unexpected keepalive")
	case <-time.After(10*time.Second/3 + 1):
	}

	// recover the member.
	clus.Members[0].Restart(t)

	kresp = <-rc
	if kresp.ID != resp.ID {
		t.Errorf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	lapi.Close()

	_, ok := <-rc
	if ok {
		t.Errorf("chan is not closed, want lease Close() closes chan")
	}
}

type leaseCh struct {
	lid clientv3.LeaseID
	ch  <-chan *clientv3.LeaseKeepAliveResponse
}

// TestLeaseKeepAliveNotFound ensures a revoked lease won't stop other keep alives
func TestLeaseKeepAliveNotFound(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.RandClient()
	lchs := []leaseCh{}
	for i := 0; i < 3; i++ {
		resp, rerr := cli.Grant(context.TODO(), 5)
		if rerr != nil {
			t.Fatal(rerr)
		}
		kach, kaerr := cli.KeepAlive(context.Background(), resp.ID)
		if kaerr != nil {
			t.Fatal(kaerr)
		}
		lchs = append(lchs, leaseCh{resp.ID, kach})
	}

	if _, err := cli.Revoke(context.TODO(), lchs[1].lid); err != nil {
		t.Fatal(err)
	}

	<-lchs[0].ch
	if _, ok := <-lchs[0].ch; !ok {
		t.Fatalf("closed keepalive on wrong lease")
	}

	timec := time.After(5 * time.Second)
	for range lchs[1].ch {
		select {
		case <-timec:
			t.Fatalf("revoke did not close keep alive")
		default:
		}
	}
}

func TestLeaseGrantErrConnClosed(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)
	le := clientv3.NewLease(cli)

	donec := make(chan struct{})
	go func() {
		defer close(donec)
		_, err := le.Grant(context.TODO(), 5)
		if err != nil && err != grpc.ErrClientConnClosing {
			t.Fatalf("expected %v, got %v", grpc.ErrClientConnClosing, err)
		}
	}()

	if err := cli.Close(); err != nil {
		t.Fatal(err)
	}
	clus.TakeClient(0)

	select {
	case <-time.After(3 * time.Second):
		t.Fatal("le.Grant took too long")
	case <-donec:
	}
}

func TestLeaseGrantNewAfterClose(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)
	clus.TakeClient(0)
	if err := cli.Close(); err != nil {
		t.Fatal(err)
	}

	donec := make(chan struct{})
	go func() {
		le := clientv3.NewLease(cli)
		if _, err := le.Grant(context.TODO(), 5); err != grpc.ErrClientConnClosing {
			t.Fatalf("expected %v, got %v", grpc.ErrClientConnClosing, err)
		}
		close(donec)
	}()
	select {
	case <-time.After(3 * time.Second):
		t.Fatal("le.Grant took too long")
	case <-donec:
	}
}

func TestLeaseRevokeNewAfterClose(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)
	le := clientv3.NewLease(cli)
	resp, err := le.Grant(context.TODO(), 5)
	if err != nil {
		t.Fatal(err)
	}
	leaseID := resp.ID

	clus.TakeClient(0)
	if err := cli.Close(); err != nil {
		t.Fatal(err)
	}

	donec := make(chan struct{})
	go func() {
		if _, err := le.Revoke(context.TODO(), leaseID); err != grpc.ErrClientConnClosing {
			t.Fatalf("expected %v, got %v", grpc.ErrClientConnClosing, err)
		}
		close(donec)
	}()
	select {
	case <-time.After(3 * time.Second):
		t.Fatal("le.Revoke took too long")
	case <-donec:
	}
}

// TestLeaseKeepAliveCloseAfterDisconnectExpire ensures the keep alive channel is closed
// following a disconnection, lease revoke, then reconnect.
func TestLeaseKeepAliveCloseAfterDisconnectRevoke(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	cli := clus.Client(0)

	// setup lease and do a keepalive
	resp, err := cli.Grant(context.Background(), 10)
	if err != nil {
		t.Fatal(err)
	}
	rc, kerr := cli.KeepAlive(context.Background(), resp.ID)
	if kerr != nil {
		t.Fatal(kerr)
	}
	if kresp := <-rc; kresp.ID != resp.ID {
		t.Fatalf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	// keep client disconnected
	clus.Members[0].Stop(t)
	time.Sleep(time.Second)
	clus.WaitLeader(t)

	if _, err := clus.Client(1).Revoke(context.TODO(), resp.ID); err != nil {
		t.Fatal(err)
	}

	clus.Members[0].Restart(t)

	select {
	case ka, ok := <-rc:
		if ok {
			t.Fatalf("unexpected keepalive %v", ka)
		}
	case <-time.After(5 * time.Second):
		t.Fatalf("keepalive channel did not close")
	}
}

// TestLeaseKeepAliveInitTimeout ensures the keep alive channel closes if
// the initial keep alive request never gets a response.
func TestLeaseKeepAliveInitTimeout(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)

	// setup lease and do a keepalive
	resp, err := cli.Grant(context.Background(), 5)
	if err != nil {
		t.Fatal(err)
	}
	rc, kerr := cli.KeepAlive(context.Background(), resp.ID)
	if kerr != nil {
		t.Fatal(kerr)
	}
	// keep client disconnected
	clus.Members[0].Stop(t)
	select {
	case ka, ok := <-rc:
		if ok {
			t.Fatalf("unexpected keepalive %v, expected closed channel", ka)
		}
	case <-time.After(10 * time.Second):
		t.Fatalf("keepalive channel did not close")
	}

	clus.Members[0].Restart(t)
}

// TestLeaseKeepAliveInitTimeout ensures the keep alive channel closes if
// a keep alive request after the first never gets a response.
func TestLeaseKeepAliveTTLTimeout(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	cli := clus.Client(0)

	// setup lease and do a keepalive
	resp, err := cli.Grant(context.Background(), 5)
	if err != nil {
		t.Fatal(err)
	}
	rc, kerr := cli.KeepAlive(context.Background(), resp.ID)
	if kerr != nil {
		t.Fatal(kerr)
	}
	if kresp := <-rc; kresp.ID != resp.ID {
		t.Fatalf("ID = %x, want %x", kresp.ID, resp.ID)
	}

	// keep client disconnected
	clus.Members[0].Stop(t)
	select {
	case ka, ok := <-rc:
		if ok {
			t.Fatalf("unexpected keepalive %v, expected closed channel", ka)
		}
	case <-time.After(10 * time.Second):
		t.Fatalf("keepalive channel did not close")
	}

	clus.Members[0].Restart(t)
}
<|endoftext|>


<commit_before>// Copyright © 2017 The Kubicorn 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 googleSDK

import (
	"os"
	"testing"
)

func TestSdkHappy(t *testing.T) {
	err := os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "../../../test/resources/google_application_credentials_example.json")
	if err != nil {
		t.Fatalf("Unable to set env var: %v", err)
	}

	_, err = NewSdk()
	if err != nil {
		t.Fatalf("Unable to get Google compute SDK: %v", err)
	}
}

func TestSdkSad(t *testing.T) {
	err := os.Unsetenv("GOOGLE_APPLICATION_CREDENTIALS")
	if err != nil {
		t.Fatalf("Unable to set env var: %v", err)
	}

	_, err = NewSdk()
	if err == nil {
		t.Fatalf("Able to get Google compute SDK with empty variables")
	}
}
<commit_msg>Try with invalid file name.<commit_after>// Copyright © 2017 The Kubicorn 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 googleSDK

import (
	"os"
	"testing"
)

func TestSdkHappy(t *testing.T) {
	err := os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "../../../test/resources/google_application_credentials_example.json")
	if err != nil {
		t.Fatalf("Unable to set env var: %v", err)
	}

	_, err = NewSdk()
	if err != nil {
		t.Fatalf("Unable to get Google compute SDK: %v", err)
	}
}

func TestSdkSad(t *testing.T) {
	err := os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "file_that_does_not_exist.json")
	if err != nil {
		t.Fatalf("Unable to set env var: %v", err)
	}

	_, err = NewSdk()
	if err == nil {
		t.Fatalf("Able to get Google compute SDK with empty variables")
	}
}
<|endoftext|>


<commit_before>package debug

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/moby/buildkit/util/appdefaults"
	"github.com/urfave/cli"
	bolt "go.etcd.io/bbolt"
)

var DumpMetadataCommand = cli.Command{
	Name:  "dump-metadata",
	Usage: "dump the meta in human-readable format.  This command requires the daemon NOT to be running.",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "root",
			Usage: "path to state directory",
			Value: appdefaults.Root,
		},
	},
	Action: func(clicontext *cli.Context) error {
		dbFiles, err := findMetadataDBFiles(clicontext.String("root"))
		if err != nil {
			return err
		}
		for _, dbFile := range dbFiles {
			fmt.Printf("===== %s =====\n", dbFile)
			if err := dumpBolt(dbFile, func(k, v []byte) string {
				return fmt.Sprintf("%q: %s", string(k), string(v))
			}); err != nil {
				return err
			}
		}
		return nil
	},
}

func findMetadataDBFiles(root string) ([]string, error) {
	dirs, err := ioutil.ReadDir(root)
	if err != nil {
		return nil, err
	}
	var files []string
	for _, dir := range dirs {
		if !dir.IsDir() {
			continue
		}
		p := filepath.Join(root, dir.Name(), "metadata.db")
		_, err := os.Stat(p)
		if err == nil {
			files = append(files, p)
		} else if !os.IsNotExist(err) {
			return nil, err
		}
	}
	return files, nil
}

func dumpBolt(dbFile string, stringifier func(k, v []byte) string) error {
	if dbFile == "" {
		return errors.New("dbfile not specified")
	}
	if dbFile == "-" {
		// user could still specify "/dev/stdin" but unlikely to work
		return errors.New("stdin unsupported")
	}
	db, err := bolt.Open(dbFile, 0400, &bolt.Options{ReadOnly: true, Timeout: 3 * time.Second})
	if err != nil {
		return err
	}
	defer db.Close()
	return db.View(func(tx *bolt.Tx) error {
		// TODO: JSON format?
		return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
			return dumpBucket(name, b, "", stringifier)
		})
	})
}

func dumpBucket(name []byte, b *bolt.Bucket, indent string, stringifier func(k, v []byte) string) error {
	fmt.Printf("%sbucket %q:\n", indent, string(name))
	childrenIndent := indent + "  "
	return b.ForEach(func(k, v []byte) error {
		if bb := b.Bucket(k); bb != nil {
			return dumpBucket(k, bb, childrenIndent, stringifier)
		}
		fmt.Printf("%s%s\n", childrenIndent, stringifier(k, v))
		return nil
	})
}
<commit_msg>cmd/buildctl: dump metadata from metadata_v2.db<commit_after>package debug

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/moby/buildkit/util/appdefaults"
	"github.com/urfave/cli"
	bolt "go.etcd.io/bbolt"
)

var DumpMetadataCommand = cli.Command{
	Name:  "dump-metadata",
	Usage: "dump the meta in human-readable format.  This command requires the daemon NOT to be running.",
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "root",
			Usage: "path to state directory",
			Value: appdefaults.Root,
		},
	},
	Action: func(clicontext *cli.Context) error {
		dbFiles, err := findMetadataDBFiles(clicontext.String("root"))
		if err != nil {
			return err
		}
		for _, dbFile := range dbFiles {
			fmt.Printf("===== %s =====\n", dbFile)
			if err := dumpBolt(dbFile, func(k, v []byte) string {
				return fmt.Sprintf("%q: %s", string(k), string(v))
			}); err != nil {
				return err
			}
		}
		return nil
	},
}

func findMetadataDBFiles(root string) ([]string, error) {
	dirs, err := ioutil.ReadDir(root)
	if err != nil {
		return nil, err
	}
	var files []string
	for _, dir := range dirs {
		if !dir.IsDir() {
			continue
		}
		p := filepath.Join(root, dir.Name(), "metadata_v2.db")
		_, err := os.Stat(p)
		if err == nil {
			files = append(files, p)
		} else if !os.IsNotExist(err) {
			return nil, err
		}
	}
	return files, nil
}

func dumpBolt(dbFile string, stringifier func(k, v []byte) string) error {
	if dbFile == "" {
		return errors.New("dbfile not specified")
	}
	if dbFile == "-" {
		// user could still specify "/dev/stdin" but unlikely to work
		return errors.New("stdin unsupported")
	}
	db, err := bolt.Open(dbFile, 0400, &bolt.Options{ReadOnly: true, Timeout: 3 * time.Second})
	if err != nil {
		return err
	}
	defer db.Close()
	return db.View(func(tx *bolt.Tx) error {
		// TODO: JSON format?
		return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
			return dumpBucket(name, b, "", stringifier)
		})
	})
}

func dumpBucket(name []byte, b *bolt.Bucket, indent string, stringifier func(k, v []byte) string) error {
	fmt.Printf("%sbucket %q:\n", indent, string(name))
	childrenIndent := indent + "  "
	return b.ForEach(func(k, v []byte) error {
		if bb := b.Bucket(k); bb != nil {
			return dumpBucket(k, bb, childrenIndent, stringifier)
		}
		fmt.Printf("%s%s\n", childrenIndent, stringifier(k, v))
		return nil
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2022 The cert-manager 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 uninstall

import (
	"context"
	"errors"
	"fmt"
	"helm.sh/helm/v3/pkg/storage/driver"
	"log"
	"os"
	"time"

	"github.com/cert-manager/cert-manager/cmd/ctl/pkg/build"
	"github.com/spf13/cobra"
	"helm.sh/helm/v3/pkg/action"
	"helm.sh/helm/v3/pkg/cli"
	"helm.sh/helm/v3/pkg/release"
	"k8s.io/cli-runtime/pkg/genericclioptions"
)

type options struct {
	settings *cli.EnvSettings
	client   *action.Uninstall
	cfg      *action.Configuration

	DisableHooks bool
	DryRun       bool
	Wait         bool

	genericclioptions.IOStreams
}

const (
	defaultCertManagerNamespace = "cert-manager"
	releaseName                 = "cert-manager"
)

func description() string {
	return build.WithTemplate(`This command uninstalls cert-manager. It uses the Helm libraries to do so.

It assumes cert-manager has been installed with this CLI.

Most of the features supported by 'helm uninstall' are also supported by this command.

Some example uses:
	$ {{.BuildName}} x uninstall
or
	$ {{.BuildName}} x uninstall --namespace my-cert-manager
or
	$ {{.BuildName}} x uninstall --dry-run
or
	$ {{.BuildName}} x uninstall --no-hooks
`)
}

func NewCmd(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command {
	settings := cli.New()
	cfg := new(action.Configuration)

	options := options{
		settings: settings,
		cfg:      cfg,
		client:   action.NewUninstall(cfg),

		IOStreams: ioStreams,
	}

	cmd := &cobra.Command{
		Use:   "uninstall",
		Short: "Uninstall cert-manager",
		Long:  description(),
		RunE: func(cmd *cobra.Command, args []string) error {
			res, err := run(ctx, options)
			if err != nil {
				return fmt.Errorf("run: %v", err)
			}

			if options.DryRun {
				fmt.Fprintf(ioStreams.Out, "%s", res.Release.Manifest)
				return nil
			}

			return nil
		},
		SilenceUsage:  true,
		SilenceErrors: true,
	}

	settings.AddFlags(cmd.Flags())

	// The Helm cli.New function does not provide an easy way to
	// override the default of the namespace flag.
	// See https://github.com/helm/helm/issues/9790
	//
	// set the default value shown in the usage message.
	cmd.Flag("namespace").DefValue = defaultCertManagerNamespace

	// The returned error is ignored because
	// pflag.stringValue.Set always returns a nil.
	cmd.Flag("namespace").Value.Set(defaultCertManagerNamespace)

	cmd.Flags().DurationVar(&options.client.Timeout, "timeout", 5*time.Minute, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
	cmd.Flags().BoolVar(&options.Wait, "wait", true, "if set, will wait until all the resources are deleted before returning. It will wait for as long as --timeout")
	cmd.Flags().BoolVar(&options.DryRun, "dry-run", false, "simulate uninstall and output manifests to be deleted")
	cmd.Flags().BoolVar(&options.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation (pre- and post-uninstall hooks)")

	return cmd
}

// run assumes cert-manager was installed as a Helm release named cert-manager.
// this is not configurable to avoid uninstalling non-cert-manager releases.
func run(ctx context.Context, o options) (*release.UninstallReleaseResponse, error) {
	log.SetFlags(0) // disable prefixing logs with timestamps.

	if err := o.cfg.Init(o.settings.RESTClientGetter(), o.settings.Namespace(), os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
		return nil, fmt.Errorf("o.cfg.Init: %v", err)
	}

	o.client.DisableHooks = o.DisableHooks
	o.client.DryRun = o.DryRun
	o.client.Wait = o.Wait

	res, err := o.client.Run(releaseName)

	if errors.Is(err, driver.ErrReleaseNotFound) {
		log.Fatalf("release %v not found in namespace %v, did you use the correct namespace?", releaseName, o.settings.Namespace())
	}

	return res, nil
}
<commit_msg>goimports<commit_after>/*
Copyright 2022 The cert-manager 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 uninstall

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/spf13/cobra"
	"helm.sh/helm/v3/pkg/action"
	"helm.sh/helm/v3/pkg/cli"
	"helm.sh/helm/v3/pkg/release"
	"helm.sh/helm/v3/pkg/storage/driver"
	"k8s.io/cli-runtime/pkg/genericclioptions"

	"github.com/cert-manager/cert-manager/cmd/ctl/pkg/build"
)

type options struct {
	settings *cli.EnvSettings
	client   *action.Uninstall
	cfg      *action.Configuration

	DisableHooks bool
	DryRun       bool
	Wait         bool

	genericclioptions.IOStreams
}

const (
	defaultCertManagerNamespace = "cert-manager"
	releaseName                 = "cert-manager"
)

func description() string {
	return build.WithTemplate(`This command uninstalls cert-manager. It uses the Helm libraries to do so.

It assumes cert-manager has been installed with this CLI.

Most of the features supported by 'helm uninstall' are also supported by this command.

Some example uses:
	$ {{.BuildName}} x uninstall
or
	$ {{.BuildName}} x uninstall --namespace my-cert-manager
or
	$ {{.BuildName}} x uninstall --dry-run
or
	$ {{.BuildName}} x uninstall --no-hooks
`)
}

func NewCmd(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command {
	settings := cli.New()
	cfg := new(action.Configuration)

	options := options{
		settings: settings,
		cfg:      cfg,
		client:   action.NewUninstall(cfg),

		IOStreams: ioStreams,
	}

	cmd := &cobra.Command{
		Use:   "uninstall",
		Short: "Uninstall cert-manager",
		Long:  description(),
		RunE: func(cmd *cobra.Command, args []string) error {
			res, err := run(ctx, options)
			if err != nil {
				return fmt.Errorf("run: %v", err)
			}

			if options.DryRun {
				fmt.Fprintf(ioStreams.Out, "%s", res.Release.Manifest)
				return nil
			}

			return nil
		},
		SilenceUsage:  true,
		SilenceErrors: true,
	}

	settings.AddFlags(cmd.Flags())

	// The Helm cli.New function does not provide an easy way to
	// override the default of the namespace flag.
	// See https://github.com/helm/helm/issues/9790
	//
	// set the default value shown in the usage message.
	cmd.Flag("namespace").DefValue = defaultCertManagerNamespace

	// The returned error is ignored because
	// pflag.stringValue.Set always returns a nil.
	cmd.Flag("namespace").Value.Set(defaultCertManagerNamespace)

	cmd.Flags().DurationVar(&options.client.Timeout, "timeout", 5*time.Minute, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
	cmd.Flags().BoolVar(&options.Wait, "wait", true, "if set, will wait until all the resources are deleted before returning. It will wait for as long as --timeout")
	cmd.Flags().BoolVar(&options.DryRun, "dry-run", false, "simulate uninstall and output manifests to be deleted")
	cmd.Flags().BoolVar(&options.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation (pre- and post-uninstall hooks)")

	return cmd
}

// run assumes cert-manager was installed as a Helm release named cert-manager.
// this is not configurable to avoid uninstalling non-cert-manager releases.
func run(ctx context.Context, o options) (*release.UninstallReleaseResponse, error) {
	log.SetFlags(0) // disable prefixing logs with timestamps.

	if err := o.cfg.Init(o.settings.RESTClientGetter(), o.settings.Namespace(), os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
		return nil, fmt.Errorf("o.cfg.Init: %v", err)
	}

	o.client.DisableHooks = o.DisableHooks
	o.client.DryRun = o.DryRun
	o.client.Wait = o.Wait

	res, err := o.client.Run(releaseName)

	if errors.Is(err, driver.ErrReleaseNotFound) {
		log.Fatalf("release %v not found in namespace %v, did you use the correct namespace?", releaseName, o.settings.Namespace())
	}

	return res, nil
}
<|endoftext|>


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

import (
	"fmt"
	"os"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
	cmdUtil "k8s.io/minikube/cmd/util"
	"k8s.io/minikube/pkg/minikube/cluster"
	"k8s.io/minikube/pkg/minikube/constants"
	kcfg "k8s.io/minikube/pkg/minikube/kubeconfig"
	"k8s.io/minikube/pkg/minikube/machine"
)

// updateContextCmd represents the update-context command
var updateContextCmd = &cobra.Command{
	Use:   "update-context",
	Short: "Verify the IP address of the running cluster in kubeconfig.",
	Long: `Retrieves the IP address of the running cluster, checks it
			with IP in kubeconfig, and corrects kubeconfig if incorrect.`,
	Run: func(cmd *cobra.Command, args []string) {
		api, err := machine.NewAPIClient(clientType)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error getting client: %s\n", err)
			os.Exit(1)
		}
		defer api.Close()
		ip, err := cluster.GetHostDriverIP(api)
		if err != nil {
			glog.Errorln("Error host driver ip status:", err)
			cmdUtil.MaybeReportErrorAndExit(err)
		}
		kstatus, err := kcfg.UpdateKubeconfigIP(ip, constants.KubeconfigPath)
		if err != nil {
			glog.Errorln("Error kubeconfig status:", err)
			cmdUtil.MaybeReportErrorAndExit(err)
		}
		if kstatus {
			fmt.Println("Reconfigured kubeconfig IP, now pointing at " + ip.String())
		} else {
			fmt.Println("Kubeconfig IP correctly configured, pointing at " + ip.String())
		}

	},
}

func init() {
	RootCmd.AddCommand(updateContextCmd)
}
<commit_msg>Correct NewAPIClient invocation<commit_after>/*
Copyright 2016 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 cmd

import (
	"fmt"
	"os"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
	cmdUtil "k8s.io/minikube/cmd/util"
	"k8s.io/minikube/pkg/minikube/cluster"
	"k8s.io/minikube/pkg/minikube/constants"
	kcfg "k8s.io/minikube/pkg/minikube/kubeconfig"
	"k8s.io/minikube/pkg/minikube/machine"
)

// updateContextCmd represents the update-context command
var updateContextCmd = &cobra.Command{
	Use:   "update-context",
	Short: "Verify the IP address of the running cluster in kubeconfig.",
	Long: `Retrieves the IP address of the running cluster, checks it
			with IP in kubeconfig, and corrects kubeconfig if incorrect.`,
	Run: func(cmd *cobra.Command, args []string) {
		api, err := machine.NewAPIClient()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error getting client: %s\n", err)
			os.Exit(1)
		}
		defer api.Close()
		ip, err := cluster.GetHostDriverIP(api)
		if err != nil {
			glog.Errorln("Error host driver ip status:", err)
			cmdUtil.MaybeReportErrorAndExit(err)
		}
		kstatus, err := kcfg.UpdateKubeconfigIP(ip, constants.KubeconfigPath)
		if err != nil {
			glog.Errorln("Error kubeconfig status:", err)
			cmdUtil.MaybeReportErrorAndExit(err)
		}
		if kstatus {
			fmt.Println("Reconfigured kubeconfig IP, now pointing at " + ip.String())
		} else {
			fmt.Println("Kubeconfig IP correctly configured, pointing at " + ip.String())
		}

	},
}

func init() {
	RootCmd.AddCommand(updateContextCmd)
}
<|endoftext|>


<commit_before>/*
Copyright 2019 Google LLC

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 (
	"flag"
	"fmt"
	"log"
	"time"

	"cloud.google.com/go/compute/metadata"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/client"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml"
	transporthttp "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http"
	"github.com/google/knative-gcp/pkg/pubsub/adapter"
	"github.com/google/knative-gcp/pkg/reconciler/pullsubscription/resources"
	"github.com/kelseyhightower/envconfig"
	"go.opencensus.io/stats/view"
	"go.uber.org/zap"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/metrics"
	"knative.dev/pkg/signals"
)

const (
	component = "PullSubscription::ReceiveAdapter"
)

func main() {
	flag.Parse()

	startable := adapter.Adapter{}
	if err := envconfig.Process("", &startable); err != nil {
		panic(fmt.Sprintf("Failed to process env var: %s", err))
	}

	// Convert base64 encoded json logging.Config to logging.Config.
	loggingConfig, err := resources.Base64ToLoggingConfig(startable.LoggingConfigBase64)
	if err != nil {
		panic(err)
	}

	// Convert base64 encoded json metrics.ExporterOptions to metrics.ExporterOptions.
	metricsConfig, err := resources.Base64ToMetricsOptions(startable.MetricsConfigBase64)
	if err != nil {
		panic(err)
	}

	logger, _ := logging.NewLoggerFromConfig(loggingConfig, component)
	defer flush(logger)
	ctx := logging.WithLogger(signals.NewContext(), logger)

	mainMetrics(logger, metricsConfig)

	if startable.Project == "" {
		project, err := metadata.ProjectID()
		if err != nil {
			logger.Fatal("failed to find project id. ", zap.Error(err))
		}
		startable.Project = project
	}

	logger.Info("using project.", zap.String("project", startable.Project))

	logger.Info("Starting Pub/Sub Receive Adapter.", zap.Any("adapter", startable))
	if err := startable.Start(ctx); err != nil {
		logger.Fatal("failed to start adapter: ", zap.Error(err))
	}
}

func mainMetrics(logger *zap.SugaredLogger, opts *metrics.ExporterOptions) {
	if err := metrics.UpdateExporter(*opts, logger); err != nil {
		log.Fatalf("Failed to create the metrics exporter: %v", err)
	}

	// Register the views
	if err := view.Register(
		client.LatencyView,
		transporthttp.LatencyView,
		json.LatencyView,
		xml.LatencyView,
		datacodec.LatencyView,
		adapter.LatencyView,
	); err != nil {
		log.Fatalf("Failed to register views: %v", err)
	}

	view.SetReportingPeriod(2 * time.Second)
}

func flush(logger *zap.SugaredLogger) {
	_ = logger.Sync()
	metrics.FlushExporter()
}
<commit_msg>remove the panic, nothing to panic here.<commit_after>/*
Copyright 2019 Google LLC

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 (
	"flag"
	"fmt"
	"log"
	"time"

	"cloud.google.com/go/compute/metadata"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/client"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/json"
	"github.com/cloudevents/sdk-go/pkg/cloudevents/datacodec/xml"
	transporthttp "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http"
	"github.com/google/knative-gcp/pkg/pubsub/adapter"
	"github.com/google/knative-gcp/pkg/reconciler/pullsubscription/resources"
	"github.com/kelseyhightower/envconfig"
	"go.opencensus.io/stats/view"
	"go.uber.org/zap"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/metrics"
	"knative.dev/pkg/signals"
)

const (
	component = "PullSubscription::ReceiveAdapter"
)

func main() {
	flag.Parse()

	startable := adapter.Adapter{}
	if err := envconfig.Process("", &startable); err != nil {
		panic(fmt.Sprintf("Failed to process env var: %s", err))
	}

	// Convert base64 encoded json logging.Config to logging.Config.
	loggingConfig, err := resources.Base64ToLoggingConfig(startable.LoggingConfigBase64)
	if err != nil {
		fmt.Printf("[ERROR] filed to process logging config: %s", err.Error())
		// Use default logging config.
		if loggingConfig, err = logging.NewConfigFromMap(map[string]string{}); err != nil {
			// If this fails, there is no recovering.
			panic(err)
		}
	}

	logger, _ := logging.NewLoggerFromConfig(loggingConfig, component)
	defer flush(logger)
	ctx := logging.WithLogger(signals.NewContext(), logger)

	// Convert base64 encoded json metrics.ExporterOptions to metrics.ExporterOptions.
	metricsConfig, err := resources.Base64ToMetricsOptions(startable.MetricsConfigBase64)
	if err != nil {
		logger.Errorf("failed to process metrics options: %s", err.Error())
	}

	mainMetrics(logger, metricsConfig)

	if startable.Project == "" {
		project, err := metadata.ProjectID()
		if err != nil {
			logger.Fatal("failed to find project id. ", zap.Error(err))
		}
		startable.Project = project
	}

	logger.Info("using project.", zap.String("project", startable.Project))

	logger.Info("Starting Pub/Sub Receive Adapter.", zap.Any("adapter", startable))
	if err := startable.Start(ctx); err != nil {
		logger.Fatal("failed to start adapter: ", zap.Error(err))
	}
}

func mainMetrics(logger *zap.SugaredLogger, opts *metrics.ExporterOptions) {
	if opts == nil {
		logger.Info("metrics disabled")
		return
	}

	if err := metrics.UpdateExporter(*opts, logger); err != nil {
		log.Fatalf("Failed to create the metrics exporter: %v", err)
	}

	// Register the views
	if err := view.Register(
		client.LatencyView,
		transporthttp.LatencyView,
		json.LatencyView,
		xml.LatencyView,
		datacodec.LatencyView,
		adapter.LatencyView,
	); err != nil {
		log.Fatalf("Failed to register views: %v", err)
	}

	view.SetReportingPeriod(2 * time.Second)
}

func flush(logger *zap.SugaredLogger) {
	_ = logger.Sync()
	metrics.FlushExporter()
}
<|endoftext|>


<commit_before>package config

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

// func TestLoadConfigFileIfExists(t *testing.T) {
// 	yamlData := []byte(`main:
//   stackname: MyStack
//   spinner: 1
// aws:
//   code_deploy_role: CodeDeployServiceRole
//   region: us-east-1
//   enable_plugin_system: false
//   template_name: mystack.template
//   code_deploy:
//     code_deploy_s3_bucket: furnace_code_bucket
//     code_deploy_s3_key: furnace_deploy_app
//     git_account: Skarlso/furnace-codedeploy-app
//     git_revision: b89451234...`)
// 	location := os.TempDir()
// 	err := ioutil.WriteFile(filepath.Join(location, ".testexists.furnace"), []byte("testexists.yaml"), os.ModePerm)
// 	if err != nil {
// 		t.Fatal("failed to create temporary file for testing: ", err)
// 	}
// 	err = ioutil.WriteFile(filepath.Join(location, "testexists.yaml"), yamlData, os.ModePerm)
// 	if err != nil {
// 		t.Fatal("failed to create temporary file for testing: ", err)
// 	}
// 	err = LoadConfigFileIfExists(location, "testexists")
// 	if err != nil {
// 		t.Fatal("failed to load config file: ", err)
// 	}
// }

func TestLoadConfigFileIfNotExists(t *testing.T) {
	err := LoadConfigFileIfExists(os.TempDir(), "testnotexists")
	if err == nil {
		t.Fatal("loading a non existing config file should have errored out")
	}
}

func TestLoadConfigFileIfExistsOutSideTheCurrentDir(t *testing.T) {
	yamlData := []byte(`main:
  stackname: MyStack
  spinner: 1
aws:
  code_deploy_role: CodeDeployServiceRole
  region: us-east-1
  enable_plugin_system: false
  template_name: mystack.template
  code_deploy:
    code_deploy_s3_bucket: furnace_code_bucket
    code_deploy_s3_key: furnace_deploy_app
    git_account: Skarlso/furnace-codedeploy-app
    git_revision: b89451234...`)
	location := os.TempDir()
	location2 := filepath.Join(location, "temp2")
	os.Mkdir(filepath.Join(location2), os.ModeDir)
	err := ioutil.WriteFile(filepath.Join(location, ".testdiffdir.furnace"), []byte("testdiffdir.yaml"), os.ModePerm)
	if err != nil {
		t.Fatal("failed to create temporary file for testing: ", err)
	}
	err = ioutil.WriteFile(filepath.Join(location, "testdiffdir.yaml"), yamlData, os.ModePerm)
	if err != nil {
		t.Fatal("failed to create temporary file for testing: ", err)
	}
	err = LoadConfigFileIfExists(location2, "testdiffdir")
	if err != nil {
		t.Fatal("failed to load config file: ", err)
	}
}
<commit_msg>Coverage<commit_after>package config

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"

	"github.com/Skarlso/go-furnace/config"
)

// func TestLoadConfigFileIfExists(t *testing.T) {
// 	yamlData := []byte(`main:
//   stackname: MyStack
//   spinner: 1
// aws:
//   code_deploy_role: CodeDeployServiceRole
//   region: us-east-1
//   enable_plugin_system: false
//   template_name: mystack.template
//   code_deploy:
//     code_deploy_s3_bucket: furnace_code_bucket
//     code_deploy_s3_key: furnace_deploy_app
//     git_account: Skarlso/furnace-codedeploy-app
//     git_revision: b89451234...`)
// 	location := os.TempDir()
// 	err := ioutil.WriteFile(filepath.Join(location, ".testexists.furnace"), []byte("testexists.yaml"), os.ModePerm)
// 	if err != nil {
// 		t.Fatal("failed to create temporary file for testing: ", err)
// 	}
// 	err = ioutil.WriteFile(filepath.Join(location, "testexists.yaml"), yamlData, os.ModePerm)
// 	if err != nil {
// 		t.Fatal("failed to create temporary file for testing: ", err)
// 	}
// 	err = LoadConfigFileIfExists(location, "testexists")
// 	if err != nil {
// 		t.Fatal("failed to load config file: ", err)
// 	}
// }

func TestLoadConfigFileIfNotExists(t *testing.T) {
	err := LoadConfigFileIfExists(os.TempDir(), "testnotexists")
	if err == nil {
		t.Fatal("loading a non existing config file should have errored out")
	}
}

func TestLoadConfigFileIfExistsOutSideTheCurrentDir(t *testing.T) {
	yamlData := []byte(`main:
  stackname: MyStack
  spinner: 1
aws:
  code_deploy_role: CodeDeployServiceRole
  region: us-east-1
  enable_plugin_system: false
  template_name: mystack.template
  code_deploy:
    code_deploy_s3_bucket: furnace_code_bucket
    code_deploy_s3_key: furnace_deploy_app
    git_account: Skarlso/furnace-codedeploy-app
    git_revision: b89451234...`)
	location := os.TempDir()
	location2 := filepath.Join(location, "temp2")
	os.Mkdir(filepath.Join(location2), os.ModeDir)
	err := ioutil.WriteFile(filepath.Join(location, ".testdiffdir.furnace"), []byte("testdiffdir.yaml"), os.ModePerm)
	if err != nil {
		t.Fatal("failed to create temporary file for testing: ", err)
	}
	err = ioutil.WriteFile(filepath.Join(location, "testdiffdir.yaml"), yamlData, os.ModePerm)
	if err != nil {
		t.Fatal("failed to create temporary file for testing: ", err)
	}
	err = LoadConfigFileIfExists(location2, "testdiffdir")
	if err != nil {
		t.Fatal("failed to load config file: ", err)
	}
}

func TestLoadCFStackConfigNoError(t *testing.T) {
	tempFile, _ := ioutil.TempFile(os.TempDir(), "test_file")
	templatePath = tempFile.Name()
	LoadCFStackConfig()
}

func TestLoadCFStackConfigError(t *testing.T) {
	failed := false
	config.LogFatalf = func(format string, v ...interface{}) {
		failed = true
	}
	templatePath = ""
	LoadCFStackConfig()
	if !failed {
		t.Fatal("should have failed while trying to load template file which doesn't exists")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"math"
	"math/rand"
	"net"
	"net/url"
	"strconv"
	"time"
)

const (
	connectMinResponseLength = 16
	announceMinResponseLength = 20
	connectBufferSize = 150
	announceBufferSize = 20000
	startPort = 6881
	endPort = 6889
)

type UdpTracker struct {
	*tracker
	connectionId  uint64
	transactionId uint32
	serverAddr    *net.UDPAddr
	conn          *net.UDPConn
}

type connectRequest struct {
	connectionId  uint64
	action        uint32
	transactionId uint32
}

type connectResponse struct {
	action        uint32
	transactionId uint32
	connectionId  uint64
}

type errorResponse struct {
	action        uint32
	transactionId uint32
	message       string
}

type shortString []byte

type announceRequest struct {
	connectionId  uint64
	action        uint32
	transactionId uint32
	infoHash      shortString
	peerId        shortString
	downloaded    uint64
	left          uint64
	uploaded      uint64
	event         uint32
	ipAddr        uint32
	key           uint32
	numWant       int32
	port          uint16
}

type announceResponse struct {
	action        uint32
	transactionId uint32
	interval      uint32
	leechers      uint32
	seeders       uint32
	peers         []PeerTuple
}

func (r *connectRequest) MarshalBinary() ([]byte, error) {
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, r.connectionId)
	err = binary.Write(buf, binary.BigEndian, r.action)
	err = binary.Write(buf, binary.BigEndian, r.transactionId)
	return buf.Bytes(), err
}

func (r *connectResponse) UnmarshalBinary(data []byte) error {
	buf := bytes.NewReader(data[4:])
	actionBytes := append([]byte{0, 0, 0}, data[0])
	err := binary.Read(bytes.NewReader(actionBytes), binary.BigEndian, &r.action)
	err = binary.Read(buf, binary.BigEndian, &r.transactionId)
	err = binary.Read(buf, binary.BigEndian, &r.connectionId)
	return err
}

func (r *connectResponse) MarshalBinary() ([]byte, error) {
	var b bytes.Buffer
	fmt.Fprintln(&b, r.connectionId, r.action, r.transactionId)
	return b.Bytes(), nil
}

func (r *errorResponse) UnmarshalBinary(data []byte) error {
	actionBytes := append([]byte{0, 0, 0}, data[0])
	err := binary.Read(bytes.NewReader(actionBytes), binary.BigEndian, &r.action)
	err = binary.Read(bytes.NewReader(data[4:]), binary.BigEndian, &r.transactionId)
	r.message = string(data[8:])
	return err
}

func (r *announceRequest) MarshalBinary() ([]byte, error) {
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, r.connectionId)
	err = binary.Write(buf, binary.BigEndian, r.action)
	err = binary.Write(buf, binary.BigEndian, r.transactionId)
	err = binary.Write(buf, binary.BigEndian, r.infoHash)
	err = binary.Write(buf, binary.BigEndian, r.peerId)
	err = binary.Write(buf, binary.BigEndian, r.downloaded)
	err = binary.Write(buf, binary.BigEndian, r.left)
	err = binary.Write(buf, binary.BigEndian, r.uploaded)
	err = binary.Write(buf, binary.BigEndian, r.event)
	err = binary.Write(buf, binary.BigEndian, r.ipAddr)
	err = binary.Write(buf, binary.BigEndian, r.key)
	err = binary.Write(buf, binary.BigEndian, r.numWant)
	err = binary.Write(buf, binary.BigEndian, r.port)
	return buf.Bytes(), err
}

func (r *announceResponse) UnmarshalBinary(data []byte) error {
	buf := bytes.NewReader(data[4:])
	actionBytes := append([]byte{0, 0, 0}, data[0])
	err := binary.Read(bytes.NewReader(actionBytes), binary.BigEndian, &r.action)
	err = binary.Read(buf, binary.BigEndian, &r.transactionId)
	err = binary.Read(buf, binary.BigEndian, &r.interval)
	err = binary.Read(buf, binary.BigEndian, &r.leechers)
	err = binary.Read(buf, binary.BigEndian, &r.seeders)

	if len(data) > announceMinResponseLength {
		peerBytes := data[announceMinResponseLength:]
		peers := len(peerBytes) / 6

		ipLen := 4
		portLen := 2
		for i := 0; i < peers; i++ {
			ipOffset := i*6
			portOffset := ipOffset + ipLen
			peer := PeerTuple{}
			ipBytes := peerBytes[ipOffset : ipOffset + ipLen]
			peer.IP = net.IPv4(ipBytes[0], ipBytes[1], ipBytes[2], ipBytes[3])
			binary.Read(bytes.NewReader(peerBytes[portOffset : portOffset + portLen]), binary.BigEndian, &peer.Port)
			r.peers = append(r.peers, peer)
		}
	}

	return err
}

func NewUdpTracker(key string, chans trackerPeerChans, port uint16, infoHash []byte, announce *url.URL) *UdpTracker {
	return &UdpTracker{&tracker{key: key, peerChans: chans, port: port, infoHash: infoHash, announceURL: announce}, 0, 0, &net.UDPAddr{}, &net.UDPConn{}}
}

func (p *PeerTuple) String() string {
	return fmt.Sprintf("%s:%d\n", p.IP.String(), p.Port)
}

func (tr *UdpTracker) Announce(event int) {
	err := tr.connect()
	if err != nil {
		log.Printf("Tracker : Could not connect to tracker %s: \n", tr.announceURL.String(), err)
		return
	}

	key, _ := strconv.ParseUint(tr.key, 16, 4)
	announce := &announceRequest{
		connectionId:  tr.connectionId,
		action:        1,
		transactionId: tr.transactionId,
		infoHash:      tr.infoHash,
		peerId:        PeerID[:],
		downloaded:    uint64(tr.stats.Downloaded),
		left:          uint64(tr.stats.Left),
		uploaded:      uint64(tr.stats.Uploaded),
		event:         uint32(event),
		ipAddr:        0,
		key:           uint32(key),
		numWant:       -1,
		port:          6881,
	}
	announceBytes, _ := announce.MarshalBinary()

	buff := make([]byte, 60000)
	length := tr.request(announceBytes, buff)

	if length >= announceMinResponseLength {
		var response announceResponse
		response.UnmarshalBinary(buff[:length])

		if event != Stopped {
			if response.interval != 0 {
				nextAnnounce := time.Second * 120
				log.Printf("Tracker : Announce : Scheduling next announce in %v\n", nextAnnounce)
				tr.timer = time.After(nextAnnounce)
			}

			for _, peer := range response.peers {
				tr.peerChans.peers <- peer
			}
		}
	}
}

func (tr *UdpTracker) connect() error {
	log.Printf("Tracker : Connect (%v)", tr.announceURL)

	connectReq := connectRequest{connectionId: 0x41727101980, action: 0, transactionId: tr.transactionId}
	connectBytes, _ := connectReq.MarshalBinary()

	buff := make([]byte, 150)
	length := tr.request(connectBytes, buff)

	if length >= connectMinResponseLength {
		var response connectResponse
		response.UnmarshalBinary(buff[:length])

		if response.action == 3 || tr.transactionId != response.transactionId {
			error := errorResponse{}
			error.UnmarshalBinary(buff)
			return errors.New("Response Error: " + error.message)
		}

		tr.connectionId = response.connectionId
		return nil
	}

	return errors.New("Invalid connect response length")
}

func (tr *UdpTracker) Run() {
	log.Printf("Tracker : Run : Started (%s)\n", tr.announceURL)
	defer log.Printf("Tracker : Run : Completed (%s)\n", tr.announceURL)

	rand.Seed(time.Now().UnixNano())

	serverAddr, err := net.ResolveUDPAddr("udp", tr.announceURL.Host)
	if err != nil {
		log.Println("Tracker : Could not resolve tracker host!")
		return
	}

	var conn *net.UDPConn
	for port := startPort; err == nil && port < endPort; port++ {
		conn, err = net.ListenUDP("udp", &net.UDPAddr{Port: port})
	}
	if err != nil {
		log.Printf("Tracker : Could not bind to any port in range %d-%d\n", startPort, endPort)
		return
	}

	tr.transactionId = rand.Uint32()
	tr.serverAddr = serverAddr
	tr.conn = conn
	tr.Announce(Started)

	for {
		select {
		case <-tr.quit:
			log.Println("Tracker : Stop : Stopping")
			tr.Announce(Stopped)
			return
		case <-tr.completedCh:
			go tr.Announce(Completed)
		case <-tr.timer:
			log.Printf("Tracker : Run : Interval Timer Expired (%s)\n", tr.announceURL)
			go tr.Announce(Interval)
		case stats := <-tr.peerChans.stats:
			log.Println("read from stats", stats)
		}
	}
}

// Send a udp packet to the tracker, fill in the dest buffer with the response
func (tr *UdpTracker) request(payload []byte, dest []byte) int {
	n := 0
	totalAttempts := 0

	// notify the sender when a response is recieved
	recvChan := make(chan bool)

	// keep sending the packet and wait for the specifed time
	// before trying again, limit n to 8
	go func() {

		// initial send
		tr.conn.WriteTo(payload, tr.serverAddr)
	Listen:
		for {
			// timeout: 15 * 2 ^ n (0-8)
			timeout := time.Second * time.Duration(15 * int(math.Pow(2.0, float64(n))))
			timer := time.After(timeout)
			select {
			case <-recvChan:
				break Listen
			case <-timer:
				tr.conn.WriteTo(payload, tr.serverAddr)
				totalAttempts++
				if n < 8 { n++ }
			}
		}
	}()

	// read until some data is received
	var err error
	length := 0
	for length == 0 {
		length, _, err = tr.conn.ReadFrom(dest)

		// not sure what to do here?
		if err != nil {
			log.Println("Tracker : udp packet read error")
		}
	}

	recvChan <- true
	return length
}
<commit_msg>Use tracker response interval<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"math"
	"math/rand"
	"net"
	"net/url"
	"strconv"
	"time"
)

const (
	connectMinResponseLength = 16
	announceMinResponseLength = 20
	connectBufferSize = 150
	announceBufferSize = 20000
	startPort = 6881
	endPort = 6889
)

type UdpTracker struct {
	*tracker
	connectionId  uint64
	transactionId uint32
	serverAddr    *net.UDPAddr
	conn          *net.UDPConn
}

type connectRequest struct {
	connectionId  uint64
	action        uint32
	transactionId uint32
}

type connectResponse struct {
	action        uint32
	transactionId uint32
	connectionId  uint64
}

type errorResponse struct {
	action        uint32
	transactionId uint32
	message       string
}

type shortString []byte

type announceRequest struct {
	connectionId  uint64
	action        uint32
	transactionId uint32
	infoHash      shortString
	peerId        shortString
	downloaded    uint64
	left          uint64
	uploaded      uint64
	event         uint32
	ipAddr        uint32
	key           uint32
	numWant       int32
	port          uint16
}

type announceResponse struct {
	action        uint32
	transactionId uint32
	interval      uint32
	leechers      uint32
	seeders       uint32
	peers         []PeerTuple
}

func (r *connectRequest) MarshalBinary() ([]byte, error) {
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, r.connectionId)
	err = binary.Write(buf, binary.BigEndian, r.action)
	err = binary.Write(buf, binary.BigEndian, r.transactionId)
	return buf.Bytes(), err
}

func (r *connectResponse) UnmarshalBinary(data []byte) error {
	buf := bytes.NewReader(data[4:])
	actionBytes := append([]byte{0, 0, 0}, data[0])
	err := binary.Read(bytes.NewReader(actionBytes), binary.BigEndian, &r.action)
	err = binary.Read(buf, binary.BigEndian, &r.transactionId)
	err = binary.Read(buf, binary.BigEndian, &r.connectionId)
	return err
}

func (r *connectResponse) MarshalBinary() ([]byte, error) {
	var b bytes.Buffer
	fmt.Fprintln(&b, r.connectionId, r.action, r.transactionId)
	return b.Bytes(), nil
}

func (r *errorResponse) UnmarshalBinary(data []byte) error {
	actionBytes := append([]byte{0, 0, 0}, data[0])
	err := binary.Read(bytes.NewReader(actionBytes), binary.BigEndian, &r.action)
	err = binary.Read(bytes.NewReader(data[4:]), binary.BigEndian, &r.transactionId)
	r.message = string(data[8:])
	return err
}

func (r *announceRequest) MarshalBinary() ([]byte, error) {
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.BigEndian, r.connectionId)
	err = binary.Write(buf, binary.BigEndian, r.action)
	err = binary.Write(buf, binary.BigEndian, r.transactionId)
	err = binary.Write(buf, binary.BigEndian, r.infoHash)
	err = binary.Write(buf, binary.BigEndian, r.peerId)
	err = binary.Write(buf, binary.BigEndian, r.downloaded)
	err = binary.Write(buf, binary.BigEndian, r.left)
	err = binary.Write(buf, binary.BigEndian, r.uploaded)
	err = binary.Write(buf, binary.BigEndian, r.event)
	err = binary.Write(buf, binary.BigEndian, r.ipAddr)
	err = binary.Write(buf, binary.BigEndian, r.key)
	err = binary.Write(buf, binary.BigEndian, r.numWant)
	err = binary.Write(buf, binary.BigEndian, r.port)
	return buf.Bytes(), err
}

func (r *announceResponse) UnmarshalBinary(data []byte) error {
	buf := bytes.NewReader(data[4:])
	actionBytes := append([]byte{0, 0, 0}, data[0])
	err := binary.Read(bytes.NewReader(actionBytes), binary.BigEndian, &r.action)
	err = binary.Read(buf, binary.BigEndian, &r.transactionId)
	err = binary.Read(buf, binary.BigEndian, &r.interval)
	err = binary.Read(buf, binary.BigEndian, &r.leechers)
	err = binary.Read(buf, binary.BigEndian, &r.seeders)

	if len(data) > announceMinResponseLength {
		peerBytes := data[announceMinResponseLength:]
		peers := len(peerBytes) / 6

		ipLen := 4
		portLen := 2
		for i := 0; i < peers; i++ {
			ipOffset := i*6
			portOffset := ipOffset + ipLen
			peer := PeerTuple{}
			ipBytes := peerBytes[ipOffset : ipOffset + ipLen]
			peer.IP = net.IPv4(ipBytes[0], ipBytes[1], ipBytes[2], ipBytes[3])
			binary.Read(bytes.NewReader(peerBytes[portOffset : portOffset + portLen]), binary.BigEndian, &peer.Port)
			r.peers = append(r.peers, peer)
		}
	}

	return err
}

func NewUdpTracker(key string, chans trackerPeerChans, port uint16, infoHash []byte, announce *url.URL) *UdpTracker {
	return &UdpTracker{&tracker{key: key, peerChans: chans, port: port, infoHash: infoHash, announceURL: announce}, 0, 0, &net.UDPAddr{}, &net.UDPConn{}}
}

func (p *PeerTuple) String() string {
	return fmt.Sprintf("%s:%d\n", p.IP.String(), p.Port)
}

func (tr *UdpTracker) Announce(event int) {
	err := tr.connect()
	if err != nil {
		log.Printf("Tracker : Could not connect to tracker %s: \n", tr.announceURL.String(), err)
		return
	}

	key, _ := strconv.ParseUint(tr.key, 16, 4)
	announce := &announceRequest{
		connectionId:  tr.connectionId,
		action:        1,
		transactionId: tr.transactionId,
		infoHash:      tr.infoHash,
		peerId:        PeerID[:],
		downloaded:    uint64(tr.stats.Downloaded),
		left:          uint64(tr.stats.Left),
		uploaded:      uint64(tr.stats.Uploaded),
		event:         uint32(event),
		ipAddr:        0,
		key:           uint32(key),
		numWant:       -1,
		port:          6881,
	}
	announceBytes, _ := announce.MarshalBinary()

	buff := make([]byte, announceBufferSize)
	length := tr.request(announceBytes, buff)

	if length >= announceMinResponseLength {
		var response announceResponse
		response.UnmarshalBinary(buff[:length])

		if event != Stopped {
			if response.interval != 0 {
				nextAnnounce := time.Second * time.Duration(response.interval)
				log.Println("Tracker : Announce : Scheduling next announce in", nextAnnounce)
				tr.timer = time.After(nextAnnounce)
			}

			for _, peer := range response.peers {
				tr.peerChans.peers <- peer
			}
		}
	}
}

func (tr *UdpTracker) connect() error {
	log.Printf("Tracker : Connect (%v)", tr.announceURL)

	connectReq := connectRequest{connectionId: 0x41727101980, action: 0, transactionId: tr.transactionId}
	connectBytes, _ := connectReq.MarshalBinary()

	buff := make([]byte, connectBufferSize)
	length := tr.request(connectBytes, buff)

	if length >= connectMinResponseLength {
		var response connectResponse
		response.UnmarshalBinary(buff[:length])

		if response.action == 3 || tr.transactionId != response.transactionId {
			error := errorResponse{}
			error.UnmarshalBinary(buff)
			return errors.New("Response Error: " + error.message)
		}

		tr.connectionId = response.connectionId
		return nil
	}

	return errors.New("Invalid connect response length")
}

func (tr *UdpTracker) Run() {
	log.Printf("Tracker : Run : Started (%s)\n", tr.announceURL)
	defer log.Printf("Tracker : Run : Completed (%s)\n", tr.announceURL)

	rand.Seed(time.Now().UnixNano())

	serverAddr, err := net.ResolveUDPAddr("udp", tr.announceURL.Host)
	if err != nil {
		log.Println("Tracker : Could not resolve tracker host!")
		return
	}

	var conn *net.UDPConn
	for port := startPort; err == nil && port < endPort; port++ {
		conn, err = net.ListenUDP("udp", &net.UDPAddr{Port: port})
	}
	if err != nil {
		log.Printf("Tracker : Could not bind to any port in range %d-%d\n", startPort, endPort)
		return
	}

	tr.transactionId = rand.Uint32()
	tr.serverAddr = serverAddr
	tr.conn = conn
	tr.Announce(Started)

	for {
		select {
		case <-tr.quit:
			log.Println("Tracker : Stop : Stopping")
			tr.Announce(Stopped)
			return
		case <-tr.completedCh:
			go tr.Announce(Completed)
		case <-tr.timer:
			log.Printf("Tracker : Run : Interval Timer Expired (%s)\n", tr.announceURL)
			go tr.Announce(Interval)
		case stats := <-tr.peerChans.stats:
			log.Println("read from stats", stats)
		}
	}
}

// Send a udp packet to the tracker, fill in the dest buffer with the response
func (tr *UdpTracker) request(payload []byte, dest []byte) int {
	n := 0
	totalAttempts := 0

	// notify the sender when a response is recieved
	recvChan := make(chan bool)

	// keep sending the packet and wait for the specifed time
	// before trying again, limit n to 8
	go func() {

		// initial send
		tr.conn.WriteTo(payload, tr.serverAddr)
	Listen:
		for {
			// timeout: 15 * 2 ^ n (0-8)
			timeout := time.Second * time.Duration(15 * int(math.Pow(2.0, float64(n))))
			timer := time.After(timeout)
			select {
			case <-recvChan:
				break Listen
			case <-timer:
				tr.conn.WriteTo(payload, tr.serverAddr)
				totalAttempts++
				if n < 8 { n++ }
			}
		}
	}()

	// read until some data is received
	var err error
	length := 0
	for length == 0 {
		length, _, err = tr.conn.ReadFrom(dest)

		// not sure what to do here?
		if err != nil {
			log.Println("Tracker : udp packet read error")
		}
	}

	recvChan <- true
	return length
}
<|endoftext|>


<commit_before>package bleve

import (
	"strconv"
	"time"

	"github.com/blevesearch/bleve"
	"github.com/pedronasser/caddy-search/indexer"
	"github.com/pedronasser/go-piper"
)

type bleveIndexer struct {
	pipeline piper.Handler
	bleve    bleve.Index
}

// Bleve's record data struct
type indexRecord struct {
	Path     string
	Title    string
	Body     string
	Modified string
	Indexed  string
}

// Record method get existent or creates a new Record to be saved/updated in the indexer
func (i *bleveIndexer) Record(path string) indexer.Record {
	record := &Record{
		indexer:  i,
		path:     path,
		title:    "",
		document: nil,
		body:     []byte{},
		loaded:   false,
	}
	return record
}

// Search method lookup for records using a query
func (i *bleveIndexer) Search(q string) (records []indexer.Record) {
	query := bleve.NewQueryStringQuery(q)
	request := bleve.NewSearchRequest(query)
	request.Highlight = bleve.NewHighlight()
	result, err := i.bleve.Search(request)
	if err != nil { // an empty query would cause this
		return
	}

	for _, match := range result.Hits {
		rec := i.Record(match.ID)
		loaded := rec.Load()

		if !loaded {
			continue
		}

		if len(match.Fragments["Body"]) > 0 {
			rec.SetBody([]byte(match.Fragments["Body"][0]))
		}

		records = append(records, rec)
	}

	return
}

// Pipe sends the new record to the pipeline
func (i *bleveIndexer) Pipe(r indexer.Record) {
	i.pipeline.Input() <- r
}

// index is the pipeline step that indexes the document
func (i *bleveIndexer) index(in interface{}) interface{} {
	var rec *Record

	if _, ok := in.(*Record); ok {
		rec = in.(*Record)
	}

	if rec != nil && len(rec.body) > 0 {
		rec.SetIndexed(time.Now())

		r := indexRecord{
			Path:     rec.Path(),
			Title:    rec.Title(),
			Body:     string(rec.body),
			Modified: strconv.Itoa(int(rec.Modified().Unix())),
			Indexed:  strconv.Itoa(int(rec.Indexed().Unix())),
		}

		i.bleve.Index(rec.Path(), r)
	}

	return nil
}
<commit_msg>prevent record.Indexed() to return nil time.Time<commit_after>package bleve

import (
	"strconv"
	"time"

	"github.com/blevesearch/bleve"
	"github.com/pedronasser/caddy-search/indexer"
	"github.com/pedronasser/go-piper"
)

type bleveIndexer struct {
	pipeline piper.Handler
	bleve    bleve.Index
}

// Bleve's record data struct
type indexRecord struct {
	Path     string
	Title    string
	Body     string
	Modified string
	Indexed  string
}

// Record method get existent or creates a new Record to be saved/updated in the indexer
func (i *bleveIndexer) Record(path string) indexer.Record {
	record := &Record{
		indexer:  i,
		path:     path,
		title:    "",
		document: nil,
		body:     []byte{},
		loaded:   false,
		indexed:  time.Time{},
	}
	return record
}

// Search method lookup for records using a query
func (i *bleveIndexer) Search(q string) (records []indexer.Record) {
	query := bleve.NewQueryStringQuery(q)
	request := bleve.NewSearchRequest(query)
	request.Highlight = bleve.NewHighlight()
	result, err := i.bleve.Search(request)
	if err != nil { // an empty query would cause this
		return
	}

	for _, match := range result.Hits {
		rec := i.Record(match.ID)
		loaded := rec.Load()

		if !loaded {
			continue
		}

		if len(match.Fragments["Body"]) > 0 {
			rec.SetBody([]byte(match.Fragments["Body"][0]))
		}

		records = append(records, rec)
	}

	return
}

// Pipe sends the new record to the pipeline
func (i *bleveIndexer) Pipe(r indexer.Record) {
	i.pipeline.Input() <- r
}

// index is the pipeline step that indexes the document
func (i *bleveIndexer) index(in interface{}) interface{} {
	var rec *Record

	if _, ok := in.(*Record); ok {
		rec = in.(*Record)
	}

	if rec != nil && len(rec.body) > 0 {
		rec.SetIndexed(time.Now())

		r := indexRecord{
			Path:     rec.Path(),
			Title:    rec.Title(),
			Body:     string(rec.body),
			Modified: strconv.Itoa(int(rec.Modified().Unix())),
			Indexed:  strconv.Itoa(int(rec.Indexed().Unix())),
		}

		i.bleve.Index(rec.Path(), r)
	}

	return nil
}
<|endoftext|>