<commit_before>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 Weaviate. All rights reserved.
 * LICENSE: https://github.com/weaviate/weaviate/blob/master/LICENSE
 * AUTHOR: Bob van Luijt (bob@weaviate.com)
 * See www.weaviate.com for details
 * Contact: @weaviate_iot / yourfriends@weaviate.com
 */

package memory

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net"

	gouuid "github.com/satori/go.uuid"

	"math"
	"sort"

	"github.com/hashicorp/go-memdb"
	"github.com/weaviate/weaviate/connectors/utils"
)

// Datastore has some basic variables.
type Memory struct {
	client *memdb.MemDB
	kind   string
}

// GetName returns a unique connector name
func (f *Memory) GetName() string {
	return "memory"
}

// SetConfig is used to fill in a struct with config variables
func (f *Memory) SetConfig(interface{}) {
	// NOTHING
}

// Creates connection and tables if not already available (which is never because it is in memory)
func (f *Memory) Connect() error {

	// Create the weaviate DB schema
	schema := &memdb.DBSchema{
		Tables: map[string]*memdb.TableSchema{
			// create `weaviate` DB
			"weaviate": &memdb.TableSchema{
				Name: "weaviate",
				Indexes: map[string]*memdb.IndexSchema{
					"id": &memdb.IndexSchema{
						Name:    "id",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
					"Deleted": &memdb.IndexSchema{
						Name:    "Deleted",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Deleted"},
					},
					"CreateTimeMs": &memdb.IndexSchema{
						Name:    "CreateTimeMs",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "CreateTimeMs"},
					},
					"Object": &memdb.IndexSchema{
						Name:    "Object",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Object"},
					},
					"Owner": &memdb.IndexSchema{
						Name:    "Owner",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Owner"},
					},
					"RefType": &memdb.IndexSchema{
						Name:    "RefType",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "RefType"},
					},
					"Uuid": &memdb.IndexSchema{
						Name:    "Uuid",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
				},
			},
			// create `weaviate` DB
			"weaviate_history": &memdb.TableSchema{
				Name: "weaviate_history",
				Indexes: map[string]*memdb.IndexSchema{
					"id": &memdb.IndexSchema{
						Name:    "id",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},

					"Deleted": &memdb.IndexSchema{
						Name:    "Deleted",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Deleted"},
					},
					"CreateTimeMs": &memdb.IndexSchema{
						Name:    "CreateTimeMs",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "CreateTimeMs"},
					},
					"Object": &memdb.IndexSchema{
						Name:    "Object",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Object"},
					},
					"Owner": &memdb.IndexSchema{
						Name:    "Owner",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "Owner"},
					},
					"RefType": &memdb.IndexSchema{
						Name:    "RefType",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "RefType"},
					},
					"Uuid": &memdb.IndexSchema{
						Name:    "Uuid",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
				},
			},
			// create `weaviate_users` DB
			"weaviate_users": &memdb.TableSchema{
				Name: "weaviate_users",
				Indexes: map[string]*memdb.IndexSchema{
					"id": &memdb.IndexSchema{
						Name:    "id",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
					"KeyExpiresUnix": &memdb.IndexSchema{
						Name:    "KeyExpiresUnix",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "KeyExpiresUnix"},
					},
					"KeyToken": &memdb.IndexSchema{
						Name:    "KeyToken",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "KeyToken"},
					},
					"Object": &memdb.IndexSchema{
						Name:    "Object",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Object"},
					},
					"Parent": &memdb.IndexSchema{
						Name:    "Parent",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "Parent"},
					},
					"Uuid": &memdb.IndexSchema{
						Name:    "Uuid",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
				},
			},
		},
	}

	// Create a new data base
	client, err := memdb.NewMemDB(schema)

	// If error, return it. Otherwise set client.
	if err != nil {
		return err
	}

	f.client = client

	log.Println("INFO: In memory database is used for testing / development purposes only")

	return nil

}

// Creates a root key, normally this should be validaded, but because it is an inmemory DB it is created always
func (f *Memory) Init() error {
	dbObject := connector_utils.DatabaseUsersObject{}

	// Create key token
	dbObject.KeyToken = fmt.Sprintf("%v", gouuid.NewV4())

	// Uuid + name
	uuid := fmt.Sprintf("%v", gouuid.NewV4())

	// Auto set the parent ID to root *
	dbObject.Parent = "*"

	// Set Uuid
	dbObject.Uuid = uuid

	// Set expiry to unlimited
	dbObject.KeyExpiresUnix = -1

	// Set chmod variables
	dbObjectObject := connector_utils.DatabaseUsersObjectsObject{}
	dbObjectObject.Read = true
	dbObjectObject.Write = true
	dbObjectObject.Delete = true
	dbObjectObject.Execute = true

	// Get ips as v6
	var ips []string
	ifaces, _ := net.Interfaces()
	for _, i := range ifaces {
		addrs, _ := i.Addrs()
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}

			ipv6 := ip.To16()
			ips = append(ips, ipv6.String())
		}
	}

	dbObjectObject.IPOrigin = ips

	// Marshall and add to object
	dbObjectObjectJSON, _ := json.Marshal(dbObjectObject)
	dbObject.Object = string(dbObjectObjectJSON)

	// Create a write transaction
	txn := f.client.Txn(true)

	// Saves the new entity.
	if err := txn.Insert("weaviate_users", dbObject); err != nil {
		return err
	}

	// commit transaction
	txn.Commit()

	// Print the key
	log.Println("INFO: A new root key is created. More info: https://github.com/weaviate/weaviate/blob/develop/README.md#authentication")
	log.Println("INFO: Auto set allowed IPs to: ", ips)
	log.Println("ROOTKEY=" + dbObject.KeyToken)

	return nil
}

func (f *Memory) Add(dbObject connector_utils.DatabaseObject) (string, error) {

	// Create a write transaction
	txn := f.client.Txn(true)

	// Saves the new entity.
	if err := txn.Insert("weaviate", dbObject); err != nil {
		return "Error", err
	}

	// commit transaction
	txn.Commit()

	// Return the ID that is used to create.
	return dbObject.Uuid, nil

}

func (f *Memory) Get(Uuid string) (connector_utils.DatabaseObject, error) {

	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup by Uuid
	result, err := txn.First("weaviate", "Uuid", Uuid)
	if err != nil {
		return connector_utils.DatabaseObject{}, err
	}

	// Return 'not found'
	if result == nil {
		notFoundErr := errors.New("no object with such UUID found")
		return connector_utils.DatabaseObject{}, notFoundErr
	}

	// Return found object
	return result.(connector_utils.DatabaseObject), nil

}

// return a list
func (f *Memory) List(refType string, limit int, page int, referenceFilter *connector_utils.ObjectReferences) (connector_utils.DatabaseObjects, int64, error) {
	dataObjs := connector_utils.DatabaseObjects{}

	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup by Uuid
	result, err := txn.Get("weaviate", "id")

	// return the error
	if err != nil {
		return dataObjs, 0, err
	}

	if result != nil {

		// loop through the results
		singleResult := result.Next()
		for singleResult != nil {
			// only store if refType is correct
			if singleResult.(connector_utils.DatabaseObject).RefType == refType &&
				!singleResult.(connector_utils.DatabaseObject).Deleted {

				if referenceFilter != nil {
					// check for extra filters
					if referenceFilter.ThingID != "" &&
						singleResult.(connector_utils.DatabaseObject).RelatedObjects.ThingID == referenceFilter.ThingID {
						dataObjs = append(dataObjs, singleResult.(connector_utils.DatabaseObject))
					}
				} else {
					dataObjs = append(dataObjs, singleResult.(connector_utils.DatabaseObject))
				}
			}
			singleResult = result.Next()
		}

		// Sorting on CreateTimeMs
		sort.Sort(dataObjs)

		// count total
		totalResults := len(dataObjs)

		// calculate the amount to chop off totalResults-limit
		offset := (limit * (page - 1))
		end := int(math.Min(float64(limit*(page)), float64(totalResults)))
		dataObjs := dataObjs[offset:end]

		// return found set
		return dataObjs, int64(totalResults), err
	}

	// nothing found
	return dataObjs, 0, nil
}

// Validate if a user has access, returns permissions object
func (f *Memory) ValidateKey(token string) ([]connector_utils.DatabaseUsersObject, error) {

	dbUsersObjects := []connector_utils.DatabaseUsersObject{}

	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Filter on timestamp, deleted and token itself
	result, err := txn.First("weaviate_users", "KeyToken", token)
	if err != nil || result == nil {
		return []connector_utils.DatabaseUsersObject{}, err
	}

	// Add to results
	userObject := result.(connector_utils.DatabaseUsersObject)
	dbUsersObjects = append(dbUsersObjects, userObject)

	// keys are found, return true
	return dbUsersObjects, nil
}

// GetKey returns user object by ID
func (f *Memory) GetKey(Uuid string) (connector_utils.DatabaseUsersObject, error) {
	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup by Uuid
	result, err := txn.First("weaviate_users", "Uuid", Uuid)
	if err != nil {
		return connector_utils.DatabaseUsersObject{}, err
	}

	// Return 'not found'
	if result == nil {
		notFoundErr := errors.New("No object with such UUID found")
		return connector_utils.DatabaseUsersObject{}, notFoundErr
	}

	// Return found object
	return result.(connector_utils.DatabaseUsersObject), nil

}

// AddUser to DB
func (f *Memory) AddKey(parentUuid string, dbObject connector_utils.DatabaseUsersObject) (connector_utils.DatabaseUsersObject, error) {

	// Create a write transaction
	txn := f.client.Txn(true)

	// Auto set the parent ID
	dbObject.Parent = parentUuid

	// Saves the new entity.
	if err := txn.Insert("weaviate_users", dbObject); err != nil {
		return dbObject, err
	}

	// commit transaction
	txn.Commit()

	// Return the ID that is used to create.
	return dbObject, nil

}

// DeleteKey removes a key from the database
func (f *Memory) DeleteKey(UUID string) error {
	// Create a read transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup all Children
	result, err := txn.First("weaviate_users", "Uuid", UUID)

	// Return the error
	if err != nil {
		return err
	}

	childUserObject := result.(connector_utils.DatabaseUsersObject)
	childUserObject.Deleted = true

	txn2 := f.client.Txn(true)
	// Delete item(s) with given Uuid
	_, errDel := txn2.DeleteAll("weaviate_users", "Uuid", childUserObject.Uuid)
	txn2.Insert("weaviate_users", childUserObject)

	// Commit transaction
	txn2.Commit()

	return errDel
}

// GetChildKeys returns all the child keys
func (f *Memory) GetChildObjects(UUID string, filterOutDeleted bool) ([]connector_utils.DatabaseUsersObject, error) {
	// Create a read transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// // Fill children array
	childUserObjects := []connector_utils.DatabaseUsersObject{}

	// Lookup by Uuid
	result, err := txn.Get("weaviate_users", "Parent", UUID)

	println("Komt hier: ", UUID)

	// return the error
	if err != nil {
		return childUserObjects, err
	}

	if result != nil {
		// loop through the results
		singleResult := result.Next()
		for singleResult != nil {
			// only store if refType is correct
			if filterOutDeleted {
				if !singleResult.(connector_utils.DatabaseUsersObject).Deleted {
					childUserObjects = append(childUserObjects, singleResult.(connector_utils.DatabaseUsersObject))
				}
			} else {
				childUserObjects = append(childUserObjects, singleResult.(connector_utils.DatabaseUsersObject))
			}

			singleResult = result.Next()
		}
	}

	return childUserObjects, nil
}
<commit_msg>gh-62: Remove println.<commit_after>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 Weaviate. All rights reserved.
 * LICENSE: https://github.com/weaviate/weaviate/blob/master/LICENSE
 * AUTHOR: Bob van Luijt (bob@weaviate.com)
 * See www.weaviate.com for details
 * Contact: @weaviate_iot / yourfriends@weaviate.com
 */

package memory

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net"

	gouuid "github.com/satori/go.uuid"

	"math"
	"sort"

	"github.com/hashicorp/go-memdb"
	"github.com/weaviate/weaviate/connectors/utils"
)

// Datastore has some basic variables.
type Memory struct {
	client *memdb.MemDB
	kind   string
}

// GetName returns a unique connector name
func (f *Memory) GetName() string {
	return "memory"
}

// SetConfig is used to fill in a struct with config variables
func (f *Memory) SetConfig(interface{}) {
	// NOTHING
}

// Creates connection and tables if not already available (which is never because it is in memory)
func (f *Memory) Connect() error {

	// Create the weaviate DB schema
	schema := &memdb.DBSchema{
		Tables: map[string]*memdb.TableSchema{
			// create `weaviate` DB
			"weaviate": &memdb.TableSchema{
				Name: "weaviate",
				Indexes: map[string]*memdb.IndexSchema{
					"id": &memdb.IndexSchema{
						Name:    "id",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
					"Deleted": &memdb.IndexSchema{
						Name:    "Deleted",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Deleted"},
					},
					"CreateTimeMs": &memdb.IndexSchema{
						Name:    "CreateTimeMs",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "CreateTimeMs"},
					},
					"Object": &memdb.IndexSchema{
						Name:    "Object",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Object"},
					},
					"Owner": &memdb.IndexSchema{
						Name:    "Owner",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Owner"},
					},
					"RefType": &memdb.IndexSchema{
						Name:    "RefType",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "RefType"},
					},
					"Uuid": &memdb.IndexSchema{
						Name:    "Uuid",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
				},
			},
			// create `weaviate` DB
			"weaviate_history": &memdb.TableSchema{
				Name: "weaviate_history",
				Indexes: map[string]*memdb.IndexSchema{
					"id": &memdb.IndexSchema{
						Name:    "id",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},

					"Deleted": &memdb.IndexSchema{
						Name:    "Deleted",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Deleted"},
					},
					"CreateTimeMs": &memdb.IndexSchema{
						Name:    "CreateTimeMs",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "CreateTimeMs"},
					},
					"Object": &memdb.IndexSchema{
						Name:    "Object",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Object"},
					},
					"Owner": &memdb.IndexSchema{
						Name:    "Owner",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "Owner"},
					},
					"RefType": &memdb.IndexSchema{
						Name:    "RefType",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "RefType"},
					},
					"Uuid": &memdb.IndexSchema{
						Name:    "Uuid",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
				},
			},
			// create `weaviate_users` DB
			"weaviate_users": &memdb.TableSchema{
				Name: "weaviate_users",
				Indexes: map[string]*memdb.IndexSchema{
					"id": &memdb.IndexSchema{
						Name:    "id",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
					"KeyExpiresUnix": &memdb.IndexSchema{
						Name:    "KeyExpiresUnix",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "KeyExpiresUnix"},
					},
					"KeyToken": &memdb.IndexSchema{
						Name:    "KeyToken",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "KeyToken"},
					},
					"Object": &memdb.IndexSchema{
						Name:    "Object",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Object"},
					},
					"Parent": &memdb.IndexSchema{
						Name:    "Parent",
						Unique:  false,
						Indexer: &memdb.StringFieldIndex{Field: "Parent"},
					},
					"Uuid": &memdb.IndexSchema{
						Name:    "Uuid",
						Unique:  true,
						Indexer: &memdb.StringFieldIndex{Field: "Uuid"},
					},
				},
			},
		},
	}

	// Create a new data base
	client, err := memdb.NewMemDB(schema)

	// If error, return it. Otherwise set client.
	if err != nil {
		return err
	}

	f.client = client

	log.Println("INFO: In memory database is used for testing / development purposes only")

	return nil

}

// Creates a root key, normally this should be validaded, but because it is an inmemory DB it is created always
func (f *Memory) Init() error {
	dbObject := connector_utils.DatabaseUsersObject{}

	// Create key token
	dbObject.KeyToken = fmt.Sprintf("%v", gouuid.NewV4())

	// Uuid + name
	uuid := fmt.Sprintf("%v", gouuid.NewV4())

	// Auto set the parent ID to root *
	dbObject.Parent = "*"

	// Set Uuid
	dbObject.Uuid = uuid

	// Set expiry to unlimited
	dbObject.KeyExpiresUnix = -1

	// Set chmod variables
	dbObjectObject := connector_utils.DatabaseUsersObjectsObject{}
	dbObjectObject.Read = true
	dbObjectObject.Write = true
	dbObjectObject.Delete = true
	dbObjectObject.Execute = true

	// Get ips as v6
	var ips []string
	ifaces, _ := net.Interfaces()
	for _, i := range ifaces {
		addrs, _ := i.Addrs()
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}

			ipv6 := ip.To16()
			ips = append(ips, ipv6.String())
		}
	}

	dbObjectObject.IPOrigin = ips

	// Marshall and add to object
	dbObjectObjectJSON, _ := json.Marshal(dbObjectObject)
	dbObject.Object = string(dbObjectObjectJSON)

	// Create a write transaction
	txn := f.client.Txn(true)

	// Saves the new entity.
	if err := txn.Insert("weaviate_users", dbObject); err != nil {
		return err
	}

	// commit transaction
	txn.Commit()

	// Print the key
	log.Println("INFO: A new root key is created. More info: https://github.com/weaviate/weaviate/blob/develop/README.md#authentication")
	log.Println("INFO: Auto set allowed IPs to: ", ips)
	log.Println("ROOTKEY=" + dbObject.KeyToken)

	return nil
}

func (f *Memory) Add(dbObject connector_utils.DatabaseObject) (string, error) {

	// Create a write transaction
	txn := f.client.Txn(true)

	// Saves the new entity.
	if err := txn.Insert("weaviate", dbObject); err != nil {
		return "Error", err
	}

	// commit transaction
	txn.Commit()

	// Return the ID that is used to create.
	return dbObject.Uuid, nil

}

func (f *Memory) Get(Uuid string) (connector_utils.DatabaseObject, error) {

	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup by Uuid
	result, err := txn.First("weaviate", "Uuid", Uuid)
	if err != nil {
		return connector_utils.DatabaseObject{}, err
	}

	// Return 'not found'
	if result == nil {
		notFoundErr := errors.New("no object with such UUID found")
		return connector_utils.DatabaseObject{}, notFoundErr
	}

	// Return found object
	return result.(connector_utils.DatabaseObject), nil

}

// return a list
func (f *Memory) List(refType string, limit int, page int, referenceFilter *connector_utils.ObjectReferences) (connector_utils.DatabaseObjects, int64, error) {
	dataObjs := connector_utils.DatabaseObjects{}

	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup by Uuid
	result, err := txn.Get("weaviate", "id")

	// return the error
	if err != nil {
		return dataObjs, 0, err
	}

	if result != nil {

		// loop through the results
		singleResult := result.Next()
		for singleResult != nil {
			// only store if refType is correct
			if singleResult.(connector_utils.DatabaseObject).RefType == refType &&
				!singleResult.(connector_utils.DatabaseObject).Deleted {

				if referenceFilter != nil {
					// check for extra filters
					if referenceFilter.ThingID != "" &&
						singleResult.(connector_utils.DatabaseObject).RelatedObjects.ThingID == referenceFilter.ThingID {
						dataObjs = append(dataObjs, singleResult.(connector_utils.DatabaseObject))
					}
				} else {
					dataObjs = append(dataObjs, singleResult.(connector_utils.DatabaseObject))
				}
			}
			singleResult = result.Next()
		}

		// Sorting on CreateTimeMs
		sort.Sort(dataObjs)

		// count total
		totalResults := len(dataObjs)

		// calculate the amount to chop off totalResults-limit
		offset := (limit * (page - 1))
		end := int(math.Min(float64(limit*(page)), float64(totalResults)))
		dataObjs := dataObjs[offset:end]

		// return found set
		return dataObjs, int64(totalResults), err
	}

	// nothing found
	return dataObjs, 0, nil
}

// Validate if a user has access, returns permissions object
func (f *Memory) ValidateKey(token string) ([]connector_utils.DatabaseUsersObject, error) {

	dbUsersObjects := []connector_utils.DatabaseUsersObject{}

	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Filter on timestamp, deleted and token itself
	result, err := txn.First("weaviate_users", "KeyToken", token)
	if err != nil || result == nil {
		return []connector_utils.DatabaseUsersObject{}, err
	}

	// Add to results
	userObject := result.(connector_utils.DatabaseUsersObject)
	dbUsersObjects = append(dbUsersObjects, userObject)

	// keys are found, return true
	return dbUsersObjects, nil
}

// GetKey returns user object by ID
func (f *Memory) GetKey(Uuid string) (connector_utils.DatabaseUsersObject, error) {
	// Create read-only transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup by Uuid
	result, err := txn.First("weaviate_users", "Uuid", Uuid)
	if err != nil {
		return connector_utils.DatabaseUsersObject{}, err
	}

	// Return 'not found'
	if result == nil {
		notFoundErr := errors.New("No object with such UUID found")
		return connector_utils.DatabaseUsersObject{}, notFoundErr
	}

	// Return found object
	return result.(connector_utils.DatabaseUsersObject), nil

}

// AddUser to DB
func (f *Memory) AddKey(parentUuid string, dbObject connector_utils.DatabaseUsersObject) (connector_utils.DatabaseUsersObject, error) {

	// Create a write transaction
	txn := f.client.Txn(true)

	// Auto set the parent ID
	dbObject.Parent = parentUuid

	// Saves the new entity.
	if err := txn.Insert("weaviate_users", dbObject); err != nil {
		return dbObject, err
	}

	// commit transaction
	txn.Commit()

	// Return the ID that is used to create.
	return dbObject, nil

}

// DeleteKey removes a key from the database
func (f *Memory) DeleteKey(UUID string) error {
	// Create a read transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// Lookup all Children
	result, err := txn.First("weaviate_users", "Uuid", UUID)

	// Return the error
	if err != nil {
		return err
	}

	childUserObject := result.(connector_utils.DatabaseUsersObject)
	childUserObject.Deleted = true

	txn2 := f.client.Txn(true)
	// Delete item(s) with given Uuid
	_, errDel := txn2.DeleteAll("weaviate_users", "Uuid", childUserObject.Uuid)
	txn2.Insert("weaviate_users", childUserObject)

	// Commit transaction
	txn2.Commit()

	return errDel
}

// GetChildKeys returns all the child keys
func (f *Memory) GetChildObjects(UUID string, filterOutDeleted bool) ([]connector_utils.DatabaseUsersObject, error) {
	// Create a read transaction
	txn := f.client.Txn(false)
	defer txn.Abort()

	// // Fill children array
	childUserObjects := []connector_utils.DatabaseUsersObject{}

	// Lookup by Uuid
	result, err := txn.Get("weaviate_users", "Parent", UUID)

	// return the error
	if err != nil {
		return childUserObjects, err
	}

	if result != nil {
		// loop through the results
		singleResult := result.Next()
		for singleResult != nil {
			// only store if refType is correct
			if filterOutDeleted {
				if !singleResult.(connector_utils.DatabaseUsersObject).Deleted {
					childUserObjects = append(childUserObjects, singleResult.(connector_utils.DatabaseUsersObject))
				}
			} else {
				childUserObjects = append(childUserObjects, singleResult.(connector_utils.DatabaseUsersObject))
			}

			singleResult = result.Next()
		}
	}

	return childUserObjects, nil
}
<|endoftext|>


<commit_before>package consumer

import (
	"flume-log-sdk/config"
	"flume-log-sdk/consumer/pool"
	"log"
)

type FlumeWatcher struct {
	sourcemanger *SourceManager
	business     string
}

func newFlumeWatcher(business string, sourcemanger *SourceManager) *config.Watcher {
	flumeWatcher := &FlumeWatcher{business: business, sourcemanger: sourcemanger}
	return config.NewWatcher(business, flumeWatcher)
}

func (self *FlumeWatcher) BusinessWatcher(business string, eventType config.ZkEvent) {
	//当前节点有发生变更,只关注删除该节点就行
	if eventType == config.Deleted {
		self.sourcemanger.mutex.Lock()
		defer self.sourcemanger.mutex.Unlock()
		val, ok := self.sourcemanger.sourceServers[business]
		if ok {
			//关闭这个业务消费
			val.stop()
			delete(self.sourcemanger.sourceServers, business)
			for e := val.flumeClientPool.Back(); nil != e; e = e.Prev() {
				self.clearPool(business, e.Value.(*pool.FlumePoolLink))
			}
			log.Printf("business:[%s] deleted\n", business)
		} else {
			log.Printf("business:[%s] not exist !\n", business)
		}
	}
}

//清理掉pool
func (self *FlumeWatcher) clearPool(business string, pool *pool.FlumePoolLink) {
	pool.Mutex.Lock()
	if pool.BusinessLink.Len() == 0 {
		//如果已经没有使用的业务了直接关掉该pool
		pool.FlumePool.Destroy()
		hp := pool.FlumePool.GetHostPort()
		delete(self.sourcemanger.hp2flumeClientPool, pool.FlumePool.GetHostPort())
		log.Printf("WATCHER|REMOVE FLUME:%s\n", hp)
	}
	pool.Mutex.Unlock()
	pool = nil
}

func (self *FlumeWatcher) ChildWatcher(business string, childNode []config.HostPort) {
	//当前业务下的flume节点发生了变更会全量推送一次新的节点

	if len(childNode) <= 0 {
		self.BusinessWatcher(business, config.Deleted)
		return
	}

	self.sourcemanger.mutex.Lock()
	defer self.sourcemanger.mutex.Unlock()
	val, ok := self.sourcemanger.sourceServers[business]
	if ok {
		//判断该业务下已经被停掉的节点
		// for _, link := range val.flumeClientPool {
		for e := val.flumeClientPool.Back(); nil != e; e = e.Next() {
			link := e.Value.(*pool.FlumePoolLink)
			hp := link.FlumePool.GetHostPort()
			contain := false
			for _, chp := range childNode {
				//如果当前节点没有变更，即存在在childnode中不变更
				if hp == chp {
					contain = true
				}
			}

			//如果当前的node没有在childnode中则删除该pooL
			if !contain {
				size := val.flumeClientPool.Len()
				link.DetachBusiness(business)
				val.flumeClientPool.Remove(e)
				self.clearPool(business, link)
				//从Business的clientpool中移除该client
				log.Printf("WATCHER|BUSINESS:%s|REMOVE FLUME:%s|SIZE:[%d,%d]\n",
					business, hp, size, val.flumeClientPool.Len())
			}
		}

		//已经存在那么就检查节点变更
		for _, hp := range childNode {
			//先创建该业务节点：
			fpool, ok := self.sourcemanger.hp2flumeClientPool[hp]
			//如果存在Pool直接使用
			if ok {
				//检查该业务已有是否已经该flumepool
				//如果不包含则创建该池子并加入该业务对应的flumeclientpoollink中
				if !fpool.IsAttached(business) {
					val.flumeClientPool.PushFront(fpool)
					fpool.AttachBusiness(business)
					log.Printf("WATCHER|BUSINESS:[%s]|ADD POOL|[%s]\n", business, hp)
				}
				//如果已经包含了，则啥事都不干

			} else {
				//如果不存在该flumepool，直接创建并且添加到该pool种
				err, poollink := pool.NewFlumePoolLink(hp)
				if nil != err {
					self.sourcemanger.hp2flumeClientPool[hp] = poollink
					val.flumeClientPool.PushFront(poollink)
					poollink.AttachBusiness(business)
				}
			}
		}

	} else {
		sourceserver := self.sourcemanger.initSourceServer(business, childNode)
		sourceserver.start()
	}
}
<commit_msg>bugfix:节点变更时无法将新节点加入到服务列表中 	modified:   consumer/flume_node_watcher.go<commit_after>package consumer

import (
	"flume-log-sdk/config"
	"flume-log-sdk/consumer/pool"
	"log"
)

type FlumeWatcher struct {
	sourcemanger *SourceManager
	business     string
}

func newFlumeWatcher(business string, sourcemanger *SourceManager) *config.Watcher {
	flumeWatcher := &FlumeWatcher{business: business, sourcemanger: sourcemanger}
	return config.NewWatcher(business, flumeWatcher)
}

func (self *FlumeWatcher) BusinessWatcher(business string, eventType config.ZkEvent) {
	//当前节点有发生变更,只关注删除该节点就行
	if eventType == config.Deleted {
		self.sourcemanger.mutex.Lock()
		defer self.sourcemanger.mutex.Unlock()
		val, ok := self.sourcemanger.sourceServers[business]
		if ok {
			//关闭这个业务消费
			val.stop()
			delete(self.sourcemanger.sourceServers, business)
			for e := val.flumeClientPool.Back(); nil != e; e = e.Prev() {
				self.clearPool(business, e.Value.(*pool.FlumePoolLink))
			}
			log.Printf("business:[%s] deleted\n", business)
		} else {
			log.Printf("business:[%s] not exist !\n", business)
		}
	}
}

//清理掉pool
func (self *FlumeWatcher) clearPool(business string, pool *pool.FlumePoolLink) {
	pool.Mutex.Lock()
	if pool.BusinessLink.Len() == 0 {
		//如果已经没有使用的业务了直接关掉该pool
		pool.FlumePool.Destroy()
		hp := pool.FlumePool.GetHostPort()
		delete(self.sourcemanger.hp2flumeClientPool, pool.FlumePool.GetHostPort())
		log.Printf("WATCHER|REMOVE FLUME:%s\n", hp)
	}
	pool.Mutex.Unlock()
	pool = nil
}

func (self *FlumeWatcher) ChildWatcher(business string, childNode []config.HostPort) {
	//当前业务下的flume节点发生了变更会全量推送一次新的节点

	if len(childNode) <= 0 {
		self.BusinessWatcher(business, config.Deleted)
		return
	}

	self.sourcemanger.mutex.Lock()
	defer self.sourcemanger.mutex.Unlock()
	val, ok := self.sourcemanger.sourceServers[business]
	if ok {
		//判断该业务下已经被停掉的节点
		// for _, link := range val.flumeClientPool {
		for e := val.flumeClientPool.Back(); nil != e; e = e.Prev() {
			link := e.Value.(*pool.FlumePoolLink)
			hp := link.FlumePool.GetHostPort()
			contain := false
			for _, chp := range childNode {
				//如果当前节点没有变更，即存在在childnode中不变更
				if hp == chp {
					contain = true
				}
			}

			//如果当前的node没有在childnode中则删除该pooL
			if !contain {
				size := val.flumeClientPool.Len()
				link.DetachBusiness(business)
				val.flumeClientPool.Remove(e)
				self.clearPool(business, link)
				//从Business的clientpool中移除该client
				log.Printf("WATCHER|BUSINESS:%s|REMOVE FLUME:%s|SIZE:[%d,%d]\n",
					business, hp, size, val.flumeClientPool.Len())
			}
		}

		//已经存在那么就检查节点变更
		for _, hp := range childNode {
			//先创建该业务节点：
			fpool, ok := self.sourcemanger.hp2flumeClientPool[hp]
			//如果存在Pool直接使用
			if ok {
				//检查该业务已有是否已经该flumepool
				//如果不包含则创建该池子并加入该业务对应的flumeclientpoollink中
				if !fpool.IsAttached(business) {
					val.flumeClientPool.PushFront(fpool)
					fpool.AttachBusiness(business)
					log.Printf("WATCHER|BUSINESS:[%s]|ADD POOL|[%s]\n", business, hp)
				}
				//如果已经包含了，则啥事都不干

			} else {
				//如果不存在该flumepool，直接创建并且添加到该pool种
				err, poollink := pool.NewFlumePoolLink(hp)
				if nil == err || nil != poollink {
					self.sourcemanger.hp2flumeClientPool[hp] = poollink
					val.flumeClientPool.PushFront(poollink)
					poollink.AttachBusiness(business)
				} else if nil != err {
					log.Printf("WATCHER|BUSINESS:[%s]|ADD POOL|FAIL|[%s]|%s\n", business, hp, err.Error())
				}
			}
		}

	} else {
		sourceserver := self.sourcemanger.initSourceServer(business, childNode)
		sourceserver.start()
	}
}
<|endoftext|>


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

// Package secrets provides an easy and portable way to encrypt and decrypt
// messages.
//
// Subpackages contain distinct implementations of secrets for various
// providers, including Cloud and on-prem solutions. For example, "localsecrets"
// supports encryption/decryption using a locally provided key. Your application
// should import one of these provider-specific subpackages and use its exported
// function(s) to create a *Keeper; do not use the NewKeeper function in this
// package. For example:
//
//  keeper := localsecrets.NewKeeper(myKey)
//  encrypted, err := keeper.Encrypt(ctx.Background(), []byte("text"))
//  ...
//
// Then, write your application code using the *Keeper type. You can easily
// reconfigure your initialization code to choose a different provider.
// You can develop your application locally using localsecrets, or deploy it to
// multiple Cloud providers. You may find http://github.com/google/wire useful
// for managing your initialization code.
package secrets // import "gocloud.dev/secrets"

import (
	"context"

	"gocloud.dev/internal/trace"
	"gocloud.dev/secrets/driver"
)

// Keeper does encryption and decryption. To create a Keeper, use constructors
// found in provider-specific subpackages.
type Keeper struct {
	k driver.Keeper
}

// NewKeeper is intended for use by provider implementations.
var NewKeeper = newKeeper

// newKeeper creates a Keeper.
func newKeeper(k driver.Keeper) *Keeper {
	return &Keeper{k: k}
}

// Encrypt encrypts the plaintext and returns the cipher message.
func (k *Keeper) Encrypt(ctx context.Context, plaintext []byte) (ciphertext []byte, err error) {
	ctx = trace.StartSpan(ctx, "gocloud.dev/secrets.Encrypt")
	defer func() { trace.EndSpan(ctx, err) }()

	b, err := k.k.Encrypt(ctx, plaintext)
	if err != nil {
		return nil, wrapError(k, err)
	}
	return b, nil
}

// Decrypt decrypts the ciphertext and returns the plaintext.
func (k *Keeper) Decrypt(ctx context.Context, ciphertext []byte) (plaintext []byte, err error) {
	ctx = trace.StartSpan(ctx, "gocloud.dev/secrets.Decrypt")
	defer func() { trace.EndSpan(ctx, err) }()

	b, err := k.k.Decrypt(ctx, ciphertext)
	if err != nil {
		return nil, wrapError(k, err)
	}
	return b, nil
}

// wrappedError is used to wrap all errors returned by drivers so that users are
// not given access to provider-specific errors.
type wrappedError struct {
	err error
	k   driver.Keeper
}

func wrapError(k driver.Keeper, err error) error {
	if err == nil {
		return nil
	}
	return &wrappedError{k: k, err: err}
}

func (w *wrappedError) Error() string {
	return "secrets: " + w.err.Error()
}
<commit_msg>secrets: delete unused code in wrapError (#1163)<commit_after>// Copyright 2019 The Go Cloud Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package secrets provides an easy and portable way to encrypt and decrypt
// messages.
//
// Subpackages contain distinct implementations of secrets for various
// providers, including Cloud and on-prem solutions. For example, "localsecrets"
// supports encryption/decryption using a locally provided key. Your application
// should import one of these provider-specific subpackages and use its exported
// function(s) to create a *Keeper; do not use the NewKeeper function in this
// package. For example:
//
//  keeper := localsecrets.NewKeeper(myKey)
//  encrypted, err := keeper.Encrypt(ctx.Background(), []byte("text"))
//  ...
//
// Then, write your application code using the *Keeper type. You can easily
// reconfigure your initialization code to choose a different provider.
// You can develop your application locally using localsecrets, or deploy it to
// multiple Cloud providers. You may find http://github.com/google/wire useful
// for managing your initialization code.
package secrets // import "gocloud.dev/secrets"

import (
	"context"

	"gocloud.dev/internal/trace"
	"gocloud.dev/secrets/driver"
)

// Keeper does encryption and decryption. To create a Keeper, use constructors
// found in provider-specific subpackages.
type Keeper struct {
	k driver.Keeper
}

// NewKeeper is intended for use by provider implementations.
var NewKeeper = newKeeper

// newKeeper creates a Keeper.
func newKeeper(k driver.Keeper) *Keeper {
	return &Keeper{k: k}
}

// Encrypt encrypts the plaintext and returns the cipher message.
func (k *Keeper) Encrypt(ctx context.Context, plaintext []byte) (ciphertext []byte, err error) {
	ctx = trace.StartSpan(ctx, "gocloud.dev/secrets.Encrypt")
	defer func() { trace.EndSpan(ctx, err) }()

	b, err := k.k.Encrypt(ctx, plaintext)
	if err != nil {
		return nil, wrapError(k, err)
	}
	return b, nil
}

// Decrypt decrypts the ciphertext and returns the plaintext.
func (k *Keeper) Decrypt(ctx context.Context, ciphertext []byte) (plaintext []byte, err error) {
	ctx = trace.StartSpan(ctx, "gocloud.dev/secrets.Decrypt")
	defer func() { trace.EndSpan(ctx, err) }()

	b, err := k.k.Decrypt(ctx, ciphertext)
	if err != nil {
		return nil, wrapError(k, err)
	}
	return b, nil
}

// wrappedError is used to wrap all errors returned by drivers so that users are
// not given access to provider-specific errors.
type wrappedError struct {
	err error
	k   driver.Keeper
}

func wrapError(k driver.Keeper, err error) error {
	return &wrappedError{k: k, err: err}
}

func (w *wrappedError) Error() string {
	return "secrets: " + w.err.Error()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	//	"log/syslog"
	"log"
	"os"
	"os/exec"
	"syscall"
)

type Syslogger struct {
	//	logger *syslog.Writer
	logger   *Writer
	stream   string
	buffer   *bytes.Buffer
	hostPort string
	//	priority syslog.Priority
	priority Priority
	prefix   string
	logFlags int
}

func (s *Syslogger) Write(p []byte) (n int, err error) {
	if s.logger == nil {
		//		sl, err := syslog.Dial("tcp", s.hostPort, s.priority, s.prefix)
		sl, err := Dial("tcp", s.hostPort, s.priority, s.prefix)
		if err != nil {
			// while syslog is down, dump the output
			return len(p), nil
		}
		s.logger = sl
	}
	for b := range p {
		s.buffer.WriteByte(p[b])
		if p[b] == 10 { // newline
			n, err := s.logger.Write(s.buffer.Bytes())
			log.Printf("n is %d\n", n)
			if err != nil {
				s.logger = nil
				log.Printf("error writing, killing syslogger\n")
			}
			s.buffer = bytes.NewBuffer([]byte{})
		}
	}
	return len(p), nil
}

func (s *Syslogger) Close() error {
	return nil
}

func NewSysLogger(stream, hostPort, prefix string) (*Syslogger, error) {
	//	var priority syslog.Priority
	var priority Priority
	if stream == "stderr" {
		priority = LOG_ERR | LOG_LOCAL0
		//		priority = syslog.LOG_ERR | syslog.LOG_LOCAL0
	} else if stream == "stdout" {
		priority = LOG_INFO | LOG_LOCAL0
		//		priority = syslog.LOG_INFO | syslog.LOG_LOCAL0
	} else {
		return nil, errors.New("cannot create syslogger for stream " + stream)
	}
	logFlags := 0

	return &Syslogger{nil, stream, bytes.NewBuffer([]byte{}), hostPort, priority, prefix, logFlags}, nil
}

func usage() {
	log.Printf("usage: %s -h syslog_host:port -n name -- executable [arg ...]", os.Args[0])
	flag.PrintDefaults()
	os.Exit(1)
}

func main() {
	log.SetFlags(0)

	flHostPort := flag.String("h", "", "Host port of where to connect to the syslog daemon")
	flLogName := flag.String("n", "", "Name to log as")
	flag.Parse()

	if *flHostPort == "" {
		log.Printf("Must set the syslog host:port argument")
		usage()
	}

	if *flLogName == "" {
		log.Printf("Must set the syslog log name argument")
		usage()
	}

	//Example ./syslog-redirector -h 10.0.3.1:6514 -n test-ls-thingy -- \
	//            /bin/bash -c 'while true; do date; echo $SHELL; sleep 1; done'
	if len(os.Args) < 4 {
		log.Printf("at least 3 arguments required")
		usage()
	}
	hostPort := *flHostPort
	name := *flLogName

	if len(flag.Args()) == 0 {
		log.Printf("must supply a command")
		usage()
	}

	cmdName := flag.Args()[0]
	cmdArgs := flag.Args()[1:]

	var err error

	path, err := exec.LookPath(cmdName)
	if err != nil {
		log.Printf("Unable to locate %v", cmdName)
		os.Exit(127)
	}

	cmd := exec.Command(path, cmdArgs...)

	// TODO (dano): tolerate syslog downtime by reconnecting

	cmd.Stdout, err = NewSysLogger("stdout", hostPort, name)
	if err != nil {
		log.Printf("error creating syslog writer for stdout: %v", err)
	}

	cmd.Stderr, err = NewSysLogger("stderr", hostPort, name)
	if err != nil {
		log.Printf("error creating syslog writer for stderr: %v", err)
	}

	err = cmd.Run()
	if err != nil {
		if msg, ok := err.(*exec.ExitError); ok {
			os.Exit(msg.Sys().(syscall.WaitStatus).ExitStatus())
		} else {
			log.Printf("error running command: %v", err)
			os.Exit(1)
		}
	}

	os.Exit(0)
}
<commit_msg>Now default to UDP, but added flag for TCP<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"log"
	"os"
	"os/exec"
	"syscall"
)

type Syslogger struct {
	logger   *Writer
	stream   string
	buffer   *bytes.Buffer
	hostPort string
	priority Priority
	prefix   string
	logFlags int
        protocol string
}

func (s *Syslogger) Write(p []byte) (n int, err error) {
	if s.logger == nil {
		sl, err := Dial(s.protocol, s.hostPort, s.priority, s.prefix)
		if err != nil {
			// while syslog is down, dump the output
			return len(p), nil
		}
		s.logger = sl
	}
	for b := range p {
		s.buffer.WriteByte(p[b])
		if p[b] == 10 { // newline
			_, err := s.logger.Write(s.buffer.Bytes())
			if err != nil {
				s.logger = nil
			}
			s.buffer = bytes.NewBuffer([]byte{})
		}
	}
	return len(p), nil
}

func (s *Syslogger) Close() error {
	return nil
}

func NewSysLogger(stream, hostPort, prefix, protocol string) (*Syslogger, error) {
	var priority Priority
	if stream == "stderr" {
		priority = LOG_ERR | LOG_LOCAL0
	} else if stream == "stdout" {
		priority = LOG_INFO | LOG_LOCAL0
	} else {
		return nil, errors.New("cannot create syslogger for stream " + stream)
	}
	logFlags := 0

	return &Syslogger{nil, stream, bytes.NewBuffer([]byte{}), hostPort, priority, prefix, logFlags, protocol}, nil
}

func usage() {
	log.Printf("usage: %s -h syslog_host:port -n name -- executable [arg ...]", os.Args[0])
	flag.PrintDefaults()
	os.Exit(1)
}

func main() {
	log.SetFlags(0)

	flHostPort := flag.String("h", "", "Host port of where to connect to the syslog daemon")
	flLogName := flag.String("n", "", "Name to log as")
	flProtocol := flag.Bool("t", false, "use TCP instead of UDP (the default) for syslog communication")
	flag.Parse()

	if *flHostPort == "" {
		log.Printf("Must set the syslog host:port argument")
		usage()
	}

	if *flLogName == "" {
		log.Printf("Must set the syslog log name argument")
		usage()
	}

	protocol := "udp"
	if *flProtocol {
		protocol = "tcp"
	}

	//Example ./syslog-redirector -h 10.0.3.1:6514 -n test-ls-thingy -- \
	//            /bin/bash -c 'while true; do date; echo $SHELL; sleep 1; done'
	if len(os.Args) < 4 {
		log.Printf("at least 3 arguments required")
		usage()
	}
	hostPort := *flHostPort
	name := *flLogName

	if len(flag.Args()) == 0 {
		log.Printf("must supply a command")
		usage()
	}

	cmdName := flag.Args()[0]
	cmdArgs := flag.Args()[1:]

	var err error

	path, err := exec.LookPath(cmdName)
	if err != nil {
		log.Printf("Unable to locate %v", cmdName)
		os.Exit(127)
	}

	cmd := exec.Command(path, cmdArgs...)

	// TODO (dano): tolerate syslog downtime by reconnecting

	cmd.Stdout, err = NewSysLogger("stdout", hostPort, name, protocol)
	if err != nil {
		log.Printf("error creating syslog writer for stdout: %v", err)
	}

	cmd.Stderr, err = NewSysLogger("stderr", hostPort, name, protocol)
	if err != nil {
		log.Printf("error creating syslog writer for stderr: %v", err)
	}

	err = cmd.Run()
	if err != nil {
		if msg, ok := err.(*exec.ExitError); ok {
			os.Exit(msg.Sys().(syscall.WaitStatus).ExitStatus())
		} else {
			log.Printf("error running command: %v", err)
			os.Exit(1)
		}
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

// XXX: This should be moved to the cli package.

package target

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

	. "mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/newt/repo"
	"mynewt.apache.org/newt/util"
)

func varsFromChildDirs(key string, fullPath bool) ([]string, error) {
	valueSlice := []string{}

	repos := project.GetProject().Repos()
	searchDirs := project.GetProject().PackageSearchDirs()
	for _, r := range repos {
		for _, pkgDir := range searchDirs {
			pkgBaseDir := r.Path() + "/" + pkgDir
			values, err := util.DescendantDirsOfParent(pkgBaseDir, key,
				fullPath)
			if err != nil {
				return nil, util.NewNewtError(err.Error())
			}

			for _, value := range values {
				if fullPath {
					value = strings.TrimPrefix(value,
						project.GetProject().Path()+"/")
				}
				if strings.HasPrefix(value, repo.REPOS_DIR+"/") {
					parts := strings.SplitN(value, "/", 2)
					if len(parts) > 1 {
						value = newtutil.BuildPackageString(parts[0], parts[1])
					}
				}
				valueSlice = append(valueSlice, value)
			}
		}
	}

	return util.SortFields(valueSlice...), nil
}

func varsFromPackageType(pt PackageType, fullPath bool) ([]string, error) {
	values := []string{}

	packs := project.GetProject().PackagesOfType(pt)
	for _, pack := range packs {
		value := pack.FullName()
		if !fullPath {
			value = filepath.Base(value)
		}

		values = append(values, value)
	}

	return values, nil
}

var varsMap = map[string]func() ([]string, error){
	"target.arch": func() ([]string, error) {
		return varsFromChildDirs("arch", false)
	},

	"target.bsp": func() ([]string, error) {
		return varsFromChildDirs("bsp", true)
	},

	"target.app": func() ([]string, error) {
		return varsFromPackageType(pkg.PACKAGE_TYPE_APP, true)
	},
}

// Returns a slice of valid values for the target variable with the specified
// name.  If an invalid target variable is specified, an error is returned.
func VarValues(varName string) ([]string, error) {
	fn := varsMap[varName]
	if fn == nil {
		err := util.NewNewtError(fmt.Sprintf("Unknown target variable: \"%s\"", varName))
		return nil, err
	}

	values, err := fn()
	if err != nil {
		return nil, err
	}

	return values, nil
}
<commit_msg>Valid BSP values were displayed incorrectly.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

// XXX: This should be moved to the cli package.

package target

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

	. "mynewt.apache.org/newt/newt/interfaces"
	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/newt/repo"
	"mynewt.apache.org/newt/util"
)

func varsFromChildDirs(key string, fullPath bool) ([]string, error) {
	valueSlice := []string{}

	repos := project.GetProject().Repos()
	searchDirs := project.GetProject().PackageSearchDirs()
	for _, r := range repos {
		for _, pkgDir := range searchDirs {
			pkgBaseDir := r.Path() + "/" + pkgDir
			values, err := util.DescendantDirsOfParent(pkgBaseDir, key,
				fullPath)
			if err != nil {
				return nil, util.NewNewtError(err.Error())
			}

			for _, value := range values {
				if fullPath {
					value = strings.TrimPrefix(value,
						project.GetProject().Path()+"/")
				}
				if strings.HasPrefix(value, repo.REPOS_DIR+"/") {
					parts := strings.SplitN(value, "/", 2)
					if len(parts) > 1 {
						value = newtutil.BuildPackageString(parts[0], parts[1])
					}
				}
				valueSlice = append(valueSlice, value)
			}
		}
	}

	return util.SortFields(valueSlice...), nil
}

func varsFromPackageType(pt PackageType, fullPath bool) ([]string, error) {
	values := []string{}

	packs := project.GetProject().PackagesOfType(pt)
	for _, pack := range packs {
		value := pack.FullName()
		if !fullPath {
			value = filepath.Base(value)
		}

		values = append(values, value)
	}

	return values, nil
}

var varsMap = map[string]func() ([]string, error){
	"target.bsp": func() ([]string, error) {
		return varsFromPackageType(pkg.PACKAGE_TYPE_BSP, true)
	},

	"target.app": func() ([]string, error) {
		return varsFromPackageType(pkg.PACKAGE_TYPE_APP, true)
	},
}

// Returns a slice of valid values for the target variable with the specified
// name.  If an invalid target variable is specified, an error is returned.
func VarValues(varName string) ([]string, error) {
	fn := varsMap[varName]
	if fn == nil {
		err := util.NewNewtError(fmt.Sprintf("Unknown target variable: \"%s\"", varName))
		return nil, err
	}

	values, err := fn()
	if err != nil {
		return nil, err
	}

	return values, nil
}
<|endoftext|>


<commit_before>package afero

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"
	"time"
)

var tempDirs []string

func NewTempOsBaseFs(t *testing.T) Fs {
	name, err := TempDir(NewOsFs(), "", "")
	if err != nil {
		t.Error("error creating tempDir", err)
	}

	tempDirs = append(tempDirs, name)

	return NewBasePathFs(NewOsFs(), name)
}

func CleanupTempDirs(t *testing.T) {
	osfs := NewOsFs()
	type ev struct {
		path string
		e    error
	}

	errs := []ev{}

	for _, x := range tempDirs {
		err := osfs.RemoveAll(x)
		if err != nil {
			errs = append(errs, ev{path: x, e: err})
		}
	}

	for _, e := range errs {
		fmt.Println("error removing tempDir", e.path, e.e)
	}

	if len(errs) > 0 {
		t.Error("error cleaning up tempDirs")
	}
	tempDirs = []string{}
}

func TestUnionCreateExisting(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}

	ufs := NewCopyOnWriteFs(roBase, &MemMapFs{})

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, err := ufs.OpenFile("/home/test/file.txt", os.O_RDWR, 0666)
	if err != nil {
		t.Errorf("Failed to open file r/w: %s", err)
	}

	_, err = fh.Write([]byte("####"))
	if err != nil {
		t.Errorf("Failed to write file: %s", err)
	}
	fh.Seek(0, 0)
	data, err := ioutil.ReadAll(fh)
	if err != nil {
		t.Errorf("Failed to read file: %s", err)
	}
	if string(data) != "#### is a test" {
		t.Errorf("Got wrong data")
	}
	fh.Close()

	fh, _ = base.Open("/home/test/file.txt")
	data, err = ioutil.ReadAll(fh)
	if string(data) != "This is a test" {
		t.Errorf("Got wrong data in base file")
	}
	fh.Close()

	fh, err = ufs.Create("/home/test/file.txt")
	switch err {
	case nil:
		if fi, _ := fh.Stat(); fi.Size() != 0 {
			t.Errorf("Create did not truncate file")
		}
		fh.Close()
	default:
		t.Errorf("Create failed on existing file")
	}

}

func TestUnionMergeReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}

	ufs := &CopyOnWriteFs{base: roBase, layer: &MemMapFs{}}

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Create("/home/test/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Open("/home/test")
	files, err := fh.Readdirnames(-1)
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 2 {
		t.Errorf("Got wrong number of files: %v", files)
	}
}

func TestExistingDirectoryCollisionReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}
	overlay := &MemMapFs{}

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	overlay.MkdirAll("home/test", 0777)
	fh, _ = overlay.Create("/home/test/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Create("/home/test/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Open("/home/test")
	files, err := fh.Readdirnames(-1)
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 3 {
		t.Errorf("Got wrong number of files in union: %v", files)
	}

	fh, _ = overlay.Open("/home/test")
	files, err = fh.Readdirnames(-1)
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 2 {
		t.Errorf("Got wrong number of files in overlay: %v", files)
	}
}

func TestNestedDirBaseReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}
	overlay := &MemMapFs{}

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/home/test/foo/bar", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = base.Create("/home/test/foo/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = base.Create("/home/test/foo/bar/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	overlay.MkdirAll("/", 0777)

	// Opening something only in the base
	fh, _ = ufs.Open("/home/test/foo")
	list, err := fh.Readdir(-1)
	if err != nil {
		t.Errorf("Readdir failed %s", err)
	}
	if len(list) != 2 {
		for _, x := range list {
			fmt.Println(x.Name())
		}
		t.Errorf("Got wrong number of files in union: %v", len(list))
	}
}

func TestNestedDirOverlayReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}
	overlay := &MemMapFs{}

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/", 0777)
	overlay.MkdirAll("/home/test/foo/bar", 0777)
	fh, _ := overlay.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	// Opening nested dir only in the overlay
	fh, _ = ufs.Open("/home/test/foo")
	list, err := fh.Readdir(-1)
	if err != nil {
		t.Errorf("Readdir failed %s", err)
	}
	if len(list) != 2 {
		for _, x := range list {
			fmt.Println(x.Name())
		}
		t.Errorf("Got wrong number of files in union: %v", len(list))
	}
}

func TestNestedDirOverlayOsFsReaddir(t *testing.T) {
	defer CleanupTempDirs(t)
	base := NewTempOsBaseFs(t)
	roBase := &ReadOnlyFs{source: base}
	overlay := NewTempOsBaseFs(t)

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/", 0777)
	overlay.MkdirAll("/home/test/foo/bar", 0777)
	fh, _ := overlay.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	// Opening nested dir only in the overlay
	fh, _ = ufs.Open("/home/test/foo")
	list, err := fh.Readdir(-1)
	fh.Close()
	if err != nil {
		t.Errorf("Readdir failed %s", err)
	}
	if len(list) != 2 {
		for _, x := range list {
			fmt.Println(x.Name())
		}
		t.Errorf("Got wrong number of files in union: %v", len(list))
	}
}

func TestCopyOnWriteFsWithOsFs(t *testing.T) {
	defer CleanupTempDirs(t)
	base := NewTempOsBaseFs(t)
	roBase := &ReadOnlyFs{source: base}
	overlay := NewTempOsBaseFs(t)

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	overlay.MkdirAll("home/test", 0777)
	fh, _ = overlay.Create("/home/test/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Create("/home/test/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Open("/home/test")
	files, err := fh.Readdirnames(-1)
	fh.Close()
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 3 {
		t.Errorf("Got wrong number of files in union: %v", files)
	}

	fh, _ = overlay.Open("/home/test")
	files, err = fh.Readdirnames(-1)
	fh.Close()
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 2 {
		t.Errorf("Got wrong number of files in overlay: %v", files)
	}
}

func TestUnionCacheWrite(t *testing.T) {
	base := &MemMapFs{}
	layer := &MemMapFs{}

	ufs := NewCacheOnReadFs(base, layer, 0)

	base.Mkdir("/data", 0777)

	fh, err := ufs.Create("/data/file.txt")
	if err != nil {
		t.Errorf("Failed to create file")
	}
	_, err = fh.Write([]byte("This is a test"))
	if err != nil {
		t.Errorf("Failed to write file")
	}

	fh.Seek(0, os.SEEK_SET)
	buf := make([]byte, 4)
	_, err = fh.Read(buf)
	fh.Write([]byte(" IS A"))
	fh.Close()

	baseData, _ := ReadFile(base, "/data/file.txt")
	layerData, _ := ReadFile(layer, "/data/file.txt")
	if string(baseData) != string(layerData) {
		t.Errorf("Different data: %s <=> %s", baseData, layerData)
	}
}

func TestUnionCacheExpire(t *testing.T) {
	base := &MemMapFs{}
	layer := &MemMapFs{}
	ufs := &CacheOnReadFs{base: base, layer: layer, cacheTime: 1 * time.Second}

	base.Mkdir("/data", 0777)

	fh, err := ufs.Create("/data/file.txt")
	if err != nil {
		t.Errorf("Failed to create file")
	}
	_, err = fh.Write([]byte("This is a test"))
	if err != nil {
		t.Errorf("Failed to write file")
	}
	fh.Close()

	fh, _ = base.Create("/data/file.txt")
	// sleep some time, so we really get a different time.Now() on write...
	time.Sleep(2 * time.Second)
	fh.WriteString("Another test")
	fh.Close()

	data, _ := ReadFile(ufs, "/data/file.txt")
	if string(data) != "Another test" {
		t.Errorf("cache time failed: <%s>", data)
	}
}
<commit_msg>CacheOnReadFS: erroneous NotExists error<commit_after>package afero

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"testing"
	"time"
)

var tempDirs []string

func NewTempOsBaseFs(t *testing.T) Fs {
	name, err := TempDir(NewOsFs(), "", "")
	if err != nil {
		t.Error("error creating tempDir", err)
	}

	tempDirs = append(tempDirs, name)

	return NewBasePathFs(NewOsFs(), name)
}

func CleanupTempDirs(t *testing.T) {
	osfs := NewOsFs()
	type ev struct {
		path string
		e    error
	}

	errs := []ev{}

	for _, x := range tempDirs {
		err := osfs.RemoveAll(x)
		if err != nil {
			errs = append(errs, ev{path: x, e: err})
		}
	}

	for _, e := range errs {
		fmt.Println("error removing tempDir", e.path, e.e)
	}

	if len(errs) > 0 {
		t.Error("error cleaning up tempDirs")
	}
	tempDirs = []string{}
}

func TestUnionCreateExisting(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}

	ufs := NewCopyOnWriteFs(roBase, &MemMapFs{})

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, err := ufs.OpenFile("/home/test/file.txt", os.O_RDWR, 0666)
	if err != nil {
		t.Errorf("Failed to open file r/w: %s", err)
	}

	_, err = fh.Write([]byte("####"))
	if err != nil {
		t.Errorf("Failed to write file: %s", err)
	}
	fh.Seek(0, 0)
	data, err := ioutil.ReadAll(fh)
	if err != nil {
		t.Errorf("Failed to read file: %s", err)
	}
	if string(data) != "#### is a test" {
		t.Errorf("Got wrong data")
	}
	fh.Close()

	fh, _ = base.Open("/home/test/file.txt")
	data, err = ioutil.ReadAll(fh)
	if string(data) != "This is a test" {
		t.Errorf("Got wrong data in base file")
	}
	fh.Close()

	fh, err = ufs.Create("/home/test/file.txt")
	switch err {
	case nil:
		if fi, _ := fh.Stat(); fi.Size() != 0 {
			t.Errorf("Create did not truncate file")
		}
		fh.Close()
	default:
		t.Errorf("Create failed on existing file")
	}

}

func TestUnionMergeReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}

	ufs := &CopyOnWriteFs{base: roBase, layer: &MemMapFs{}}

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Create("/home/test/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Open("/home/test")
	files, err := fh.Readdirnames(-1)
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 2 {
		t.Errorf("Got wrong number of files: %v", files)
	}
}

func TestExistingDirectoryCollisionReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}
	overlay := &MemMapFs{}

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	overlay.MkdirAll("home/test", 0777)
	fh, _ = overlay.Create("/home/test/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Create("/home/test/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Open("/home/test")
	files, err := fh.Readdirnames(-1)
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 3 {
		t.Errorf("Got wrong number of files in union: %v", files)
	}

	fh, _ = overlay.Open("/home/test")
	files, err = fh.Readdirnames(-1)
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 2 {
		t.Errorf("Got wrong number of files in overlay: %v", files)
	}
}

func TestNestedDirBaseReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}
	overlay := &MemMapFs{}

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/home/test/foo/bar", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = base.Create("/home/test/foo/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = base.Create("/home/test/foo/bar/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	overlay.MkdirAll("/", 0777)

	// Opening something only in the base
	fh, _ = ufs.Open("/home/test/foo")
	list, err := fh.Readdir(-1)
	if err != nil {
		t.Errorf("Readdir failed %s", err)
	}
	if len(list) != 2 {
		for _, x := range list {
			fmt.Println(x.Name())
		}
		t.Errorf("Got wrong number of files in union: %v", len(list))
	}
}

func TestNestedDirOverlayReaddir(t *testing.T) {
	base := &MemMapFs{}
	roBase := &ReadOnlyFs{source: base}
	overlay := &MemMapFs{}

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/", 0777)
	overlay.MkdirAll("/home/test/foo/bar", 0777)
	fh, _ := overlay.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	// Opening nested dir only in the overlay
	fh, _ = ufs.Open("/home/test/foo")
	list, err := fh.Readdir(-1)
	if err != nil {
		t.Errorf("Readdir failed %s", err)
	}
	if len(list) != 2 {
		for _, x := range list {
			fmt.Println(x.Name())
		}
		t.Errorf("Got wrong number of files in union: %v", len(list))
	}
}

func TestNestedDirOverlayOsFsReaddir(t *testing.T) {
	defer CleanupTempDirs(t)
	base := NewTempOsBaseFs(t)
	roBase := &ReadOnlyFs{source: base}
	overlay := NewTempOsBaseFs(t)

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/", 0777)
	overlay.MkdirAll("/home/test/foo/bar", 0777)
	fh, _ := overlay.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()
	fh, _ = overlay.Create("/home/test/foo/bar/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	// Opening nested dir only in the overlay
	fh, _ = ufs.Open("/home/test/foo")
	list, err := fh.Readdir(-1)
	fh.Close()
	if err != nil {
		t.Errorf("Readdir failed %s", err)
	}
	if len(list) != 2 {
		for _, x := range list {
			fmt.Println(x.Name())
		}
		t.Errorf("Got wrong number of files in union: %v", len(list))
	}
}

func TestCopyOnWriteFsWithOsFs(t *testing.T) {
	defer CleanupTempDirs(t)
	base := NewTempOsBaseFs(t)
	roBase := &ReadOnlyFs{source: base}
	overlay := NewTempOsBaseFs(t)

	ufs := &CopyOnWriteFs{base: roBase, layer: overlay}

	base.MkdirAll("/home/test", 0777)
	fh, _ := base.Create("/home/test/file.txt")
	fh.WriteString("This is a test")
	fh.Close()

	overlay.MkdirAll("home/test", 0777)
	fh, _ = overlay.Create("/home/test/file2.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Create("/home/test/file3.txt")
	fh.WriteString("This is a test")
	fh.Close()

	fh, _ = ufs.Open("/home/test")
	files, err := fh.Readdirnames(-1)
	fh.Close()
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 3 {
		t.Errorf("Got wrong number of files in union: %v", files)
	}

	fh, _ = overlay.Open("/home/test")
	files, err = fh.Readdirnames(-1)
	fh.Close()
	if err != nil {
		t.Errorf("Readdirnames failed")
	}
	if len(files) != 2 {
		t.Errorf("Got wrong number of files in overlay: %v", files)
	}
}

func TestUnionCacheWrite(t *testing.T) {
	base := &MemMapFs{}
	layer := &MemMapFs{}

	ufs := NewCacheOnReadFs(base, layer, 0)

	base.Mkdir("/data", 0777)

	fh, err := ufs.Create("/data/file.txt")
	if err != nil {
		t.Errorf("Failed to create file")
	}
	_, err = fh.Write([]byte("This is a test"))
	if err != nil {
		t.Errorf("Failed to write file")
	}

	fh.Seek(0, os.SEEK_SET)
	buf := make([]byte, 4)
	_, err = fh.Read(buf)
	fh.Write([]byte(" IS A"))
	fh.Close()

	baseData, _ := ReadFile(base, "/data/file.txt")
	layerData, _ := ReadFile(layer, "/data/file.txt")
	if string(baseData) != string(layerData) {
		t.Errorf("Different data: %s <=> %s", baseData, layerData)
	}
}

func TestUnionCacheExpire(t *testing.T) {
	base := &MemMapFs{}
	layer := &MemMapFs{}
	ufs := &CacheOnReadFs{base: base, layer: layer, cacheTime: 1 * time.Second}

	base.Mkdir("/data", 0777)

	fh, err := ufs.Create("/data/file.txt")
	if err != nil {
		t.Errorf("Failed to create file")
	}
	_, err = fh.Write([]byte("This is a test"))
	if err != nil {
		t.Errorf("Failed to write file")
	}
	fh.Close()

	fh, _ = base.Create("/data/file.txt")
	// sleep some time, so we really get a different time.Now() on write...
	time.Sleep(2 * time.Second)
	fh.WriteString("Another test")
	fh.Close()

	data, _ := ReadFile(ufs, "/data/file.txt")
	if string(data) != "Another test" {
		t.Errorf("cache time failed: <%s>", data)
	}
}

func TestCacheOnReadFs_Open_NotInLayer(t *testing.T) {
	base := NewMemMapFs()
	layer := NewMemMapFs()
	fs := NewCacheOnReadFs(base, layer, 0)

	fh, err := base.Create("/file.txt")
	if err != nil {
		t.Fatal("unable to create file: ", err)
	}

	txt := []byte("This is a test")
	fh.Write(txt)
	fh.Close()

	fh, err = fs.Open("/file.txt")
	if err != nil {
		t.Fatal("could not open file: ", err)
	}

	b, err := ReadAll(fh)
	fh.Close()

	if err != nil {
		t.Fatal("could not read file: ", err)
	} else if !bytes.Equal(txt, b) {
		t.Fatalf("wanted file text %q, got %q", txt, b)
	}

	fh, err = layer.Open("/file.txt")
	if err != nil {
		t.Fatal("could not open file from layer: ", err)
	}
	fh.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	_ "reflect"
	"regexp"
)

type routes struct {
	dynamic map[string]regexp.Regexp
}

func main() {

	//	var routes Dynamic

	r := regexp.MustCompile("p([a-z]+)ch")

	route := routes{
		dynamic: map[string]regexp.Regexp{
			"test": *r,
		},
	}

	//	fmt.Println(set)
	fmt.Println(route.dynamic["test"])

	//fmt.Println(reflect.TypeOf(r))

	//fmt.Println(r.MatchString("peach"))
	//fmt.Println(r.MatchString("This is all Γςεεκ to me."))
	//fmt.Println(r.MatchString("This is all ⢓⢔⢕⢖⢗⢘⢙⢚⢛ to me."))
	//fmt.Println(r.MatchString("🌵 "))

}
<commit_msg>	modified:   regex.go<commit_after>package main

import (
	"fmt"
	_ "reflect"
	"regexp"
)

type routes struct {
	dynamic map[string]regexp.Regexp
}

func main() {

	dynamic_route := make(map[string]string)

	dynamic_route["r_1"] = "p([a-z]+)ch"
	dynamic_route["r_2"] = "p([a-z0-9]+)ch"
	dynamic_route["r_3"] = "/simple"

	dynamic_set := make(map[string]regexp.Regexp)

	for k, v := range dynamic_route {
		r := regexp.MustCompile(v)
		dynamic_set[k] = *r
	}

	strings := []string{"peach", "peach2", "p3ch", "/simple"}

	for _, s := range strings {
		for k, v := range dynamic_set {
			if v.MatchString(s) {
				fmt.Printf("Match %s -> %v [%v]\n", dynamic_route[k], s, k)
			}
		}
	}

	//fmt.Println(reflect.TypeOf(r))

	//fmt.Println(r.MatchString("peach"))
	//fmt.Println(r.MatchString("This is all Γςεεκ to me."))
	//fmt.Println(r.MatchString("This is all ⢓⢔⢕⢖⢗⢘⢙⢚⢛ to me."))
	//fmt.Println(r.MatchString("🌵 "))

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"regexp"
	"strings"
	"time"

	golog "github.com/op/go-logging"

	dockerapi "github.com/fsouza/go-dockerclient"
	"github.com/gliderlabs/pkg/usage"
	"github.com/gliderlabs/registrator/bridge"
	"github.com/gliderlabs/registrator/logging"
)

var log = golog.MustGetLogger("main")

var Version string

var versionChecker = usage.NewChecker("registrator", Version)

var hostIp = flag.String("ip", "", "IP for ports mapped to the host")
var internal = flag.Bool("internal", false, "Use internal ports instead of published ones")
var useIpFromLabel = flag.String("useIpFromLabel", "", "Use IP which is stored in a label assigned to the container")
var refreshInterval = flag.Int("ttl-refresh", 0, "Frequency with which service TTLs are refreshed")
var refreshTtl = flag.Int("ttl", 0, "TTL for services (default is no expiry)")
var forceTags = flag.String("tags", "", "Append tags for all registered services")
var resyncInterval = flag.Int("resync", 0, "Frequency with which services are resynchronized")
var deregister = flag.String("deregister", "always", "Deregister exited services \"always\" or \"on-success\"")
var retryAttempts = flag.Int("retry-attempts", 0, "Max retry attempts to establish a connection with the backend. Use -1 for infinite retries")
var retryInterval = flag.Int("retry-interval", 2000, "Interval (in millisecond) between retry-attempts.")
var cleanup = flag.Bool("cleanup", false, "Remove dangling services")
var requireLabel = flag.Bool("require-label", false, "Only register containers which have the SERVICE_REGISTER label, and ignore all others.")
var ipLookupSource = flag.String("ip-lookup-source", "", "Used to configure IP lookup source. Useful when running locally")

// below IP regex was obtained from http://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/
var ipRegEx, _ = regexp.Compile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`)
var discoveredIP = ""

func getopt(name, def string) string {
	if env := os.Getenv(name); env != "" {
		return env
	}
	return def
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	if len(os.Args) == 2 && os.Args[1] == "--version" {
		versionChecker.PrintVersion()
		os.Exit(0)
	}

	flag.Parse()

	logging.Configure()

	log.Infof("Starting registrator %s ...", Version)
	quit := make(chan struct{})
	defer func() {
		if err := recover(); err != nil {
			log.Fatalf("Panic Occured:", err)
		} else {
			close(quit)
			log.Critical("Docker event loop closed") // todo: reconnect?
		}
	}()

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "  %s [options] <registry URI>\n\n", os.Args[0])
		flag.PrintDefaults()
		log.Error("Failed to start registrator, options were incorrect.")
	}

	if flag.NArg() != 1 {
		if flag.NArg() == 0 {
			fmt.Fprint(os.Stderr, "Missing required argument for registry URI.\n\n")
		} else {
			fmt.Fprintln(os.Stderr, "Extra unparsed arguments:")
			fmt.Fprintln(os.Stderr, " ", strings.Join(flag.Args()[1:], " "))
			fmt.Fprint(os.Stderr, "Options should come before the registry URI argument.\n\n")
		}
		flag.Usage()
		os.Exit(2)
	}

	if *hostIp != "" {
		if !ipRegEx.MatchString(*hostIp) {
			fmt.Fprintf(os.Stderr, "Invalid IP address '%s', please use a valid address.\n", *hostIp)
			os.Exit(2)
		}
		log.Debug("Forcing host IP to", *hostIp)
	}

	if *requireLabel {
		log.Info("SERVICE_REGISTER label is required to register containers.")
	}

	var err error
	if *ipLookupSource != "" {
		bridge.SetExternalIPSource(*ipLookupSource)
		discoveredIP, err = bridge.GetIPFromExternalSource()
		if err == nil {
			log.Infof("ipLookupSource provided. Deferring to external source for IP address. Current IP is: %s", discoveredIP)
		}
		if !ipRegEx.MatchString(discoveredIP) {
			log.Error("Invalid IP address from ipLookupSource '%s', please use a valid address.\n", discoveredIP)
		}
	}

	if (*refreshTtl == 0 && *refreshInterval > 0) || (*refreshTtl > 0 && *refreshInterval == 0) {
		assert(errors.New("-ttl and -ttl-refresh must be specified together or not at all"))
	} else if *refreshTtl > 0 && *refreshTtl <= *refreshInterval {
		assert(errors.New("-ttl must be greater than -ttl-refresh"))
	}

	if *retryInterval <= 0 {
		assert(errors.New("-retry-interval must be greater than 0"))
	}

	dockerHost := os.Getenv("DOCKER_HOST")
	if dockerHost == "" {
		os.Setenv("DOCKER_HOST", "unix:///tmp/docker.sock")
	}

	docker, err := dockerapi.NewClientFromEnv()
	assert(err)

	if *deregister != "always" && *deregister != "on-success" {
		assert(errors.New("-deregister must be \"always\" or \"on-success\""))
	}
	selectedIP := *hostIp
	if discoveredIP != "" {
		selectedIP = discoveredIP
	}

	log.Info("Creating Bridge")
	b, err := bridge.New(docker, flag.Arg(0), bridge.Config{
		HostIp:          selectedIP,
		Internal:        *internal,
		UseIpFromLabel:  *useIpFromLabel,
		ForceTags:       *forceTags,
		RefreshTtl:      *refreshTtl,
		RefreshInterval: *refreshInterval,
		DeregisterCheck: *deregister,
		Cleanup:         *cleanup,
		RequireLabel:    *requireLabel,
	})
	assert(err)
	log.Info("Bridge Created")

	attempt := 0
	for *retryAttempts == -1 || attempt <= *retryAttempts {
		log.Debugf("Connecting to backend (%v/%v)", attempt, *retryAttempts)

		err = b.Ping()
		if err == nil {
			break
		}

		if err != nil && attempt == *retryAttempts {
			assert(err)
		}

		time.Sleep(time.Duration(*retryInterval) * time.Millisecond)
		attempt++
	}

	// Start event listener before listing containers to avoid missing anything
	events := make(chan *dockerapi.APIEvents)
	assert(docker.AddEventListener(events))

	b.Sync(false)

	// Start a IP check ticker only if an external source was provided
	if *ipLookupSource != "" {
		ipTicker := time.NewTicker(time.Duration(10 * time.Second))
		go func() {
			for {
				select {
				case <-ipTicker.C:
					resyncProcess(b, *ipLookupSource)
				case <-quit:
					log.Debug("Quit message received. Exiting IP Check loop")
					ipTicker.Stop()
					return
				}
			}
		}()
	}

	// Start a dead container pruning timer to allow refresh to work independently
	if *refreshInterval > 0 {
		ticker := time.NewTicker(time.Duration(*refreshInterval) * time.Second)
		go func() {
			for {
				select {
				case <-ticker.C:
					b.PruneDeadContainers()
				case <-quit:
					log.Debug("Quit message received. Exiting PruneDeadContainer loop")
					ticker.Stop()
					return
				}
			}
		}()
	}

	// Start the TTL refresh timer
	if *refreshInterval > 0 {
		ticker := time.NewTicker(time.Duration(*refreshInterval) * time.Second)
		go func() {
			for {
				select {
				case <-ticker.C:
					b.Refresh()
				case <-quit:
					log.Debug("Quit message received. Exiting Refresh loop")
					ticker.Stop()
					return
				}
			}
		}()
	}

	// Start the resync timer if enabled
	if *resyncInterval > 0 {
		resyncTicker := time.NewTicker(time.Duration(*resyncInterval) * time.Second)
		go func() {
			for {
				select {
				case <-resyncTicker.C:
					resyncProcess(b, *ipLookupSource)
				case <-quit:
					log.Debug("Quit message received. Exiting Resync loop")
					resyncTicker.Stop()
					return
				}
			}
		}()
	}

	// Process Docker events
	for msg := range events {
		switch msg.Status {
		case "start":
			log.Debugf("Docker Event Received: Start %s", msg.ID)
			go b.Add(msg.ID)
		case "die":
			log.Debugf("Docker Event Received: Die %s", msg.ID)
			go b.RemoveOnExit(msg.ID)
		}
	}
}

func resyncProcess(b *bridge.Bridge, ipLookupSource string) {
	if ipLookupSource != "" {
		temporaryIP, err := bridge.GetIPFromExternalSource()
		if err == nil && (temporaryIP != discoveredIP) {
			discoveredIP = temporaryIP
			log.Infof("Network change has been detected by different IP. New IP is: %s", discoveredIP)
			if !ipRegEx.MatchString(discoveredIP) {
				fmt.Fprintf(os.Stderr, "Invalid IP when polling ipLookupSource '%s', please use a valid address.\n", discoveredIP)
			} else {
				go func(ip string, bridgeInstance *bridge.Bridge) {
					b.AllocateNewIPToServices(ip)
				}(discoveredIP, b)
			}
		}
	} else {
		b.Sync(true)
	}
}
<commit_msg>Add extra locking around resync<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"regexp"
	"strings"
	"time"

	golog "github.com/op/go-logging"

	dockerapi "github.com/fsouza/go-dockerclient"
	"github.com/gliderlabs/pkg/usage"
	"github.com/gliderlabs/registrator/bridge"
	"github.com/gliderlabs/registrator/logging"
)

var log = golog.MustGetLogger("main")

var Version string

var versionChecker = usage.NewChecker("registrator", Version)

var hostIp = flag.String("ip", "", "IP for ports mapped to the host")
var internal = flag.Bool("internal", false, "Use internal ports instead of published ones")
var useIpFromLabel = flag.String("useIpFromLabel", "", "Use IP which is stored in a label assigned to the container")
var refreshInterval = flag.Int("ttl-refresh", 0, "Frequency with which service TTLs are refreshed")
var refreshTtl = flag.Int("ttl", 0, "TTL for services (default is no expiry)")
var forceTags = flag.String("tags", "", "Append tags for all registered services")
var resyncInterval = flag.Int("resync", 0, "Frequency with which services are resynchronized")
var deregister = flag.String("deregister", "always", "Deregister exited services \"always\" or \"on-success\"")
var retryAttempts = flag.Int("retry-attempts", 0, "Max retry attempts to establish a connection with the backend. Use -1 for infinite retries")
var retryInterval = flag.Int("retry-interval", 2000, "Interval (in millisecond) between retry-attempts.")
var cleanup = flag.Bool("cleanup", false, "Remove dangling services")
var requireLabel = flag.Bool("require-label", false, "Only register containers which have the SERVICE_REGISTER label, and ignore all others.")
var ipLookupSource = flag.String("ip-lookup-source", "", "Used to configure IP lookup source. Useful when running locally")

// below IP regex was obtained from http://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/
var ipRegEx, _ = regexp.Compile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`)
var discoveredIP = ""

func getopt(name, def string) string {
	if env := os.Getenv(name); env != "" {
		return env
	}
	return def
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	if len(os.Args) == 2 && os.Args[1] == "--version" {
		versionChecker.PrintVersion()
		os.Exit(0)
	}

	flag.Parse()

	logging.Configure()

	log.Infof("Starting registrator %s ...", Version)
	quit := make(chan struct{})
	defer func() {
		if err := recover(); err != nil {
			log.Fatalf("Panic Occured:", err)
		} else {
			close(quit)
			log.Critical("Docker event loop closed") // todo: reconnect?
		}
	}()

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "  %s [options] <registry URI>\n\n", os.Args[0])
		flag.PrintDefaults()
		log.Error("Failed to start registrator, options were incorrect.")
	}

	if flag.NArg() != 1 {
		if flag.NArg() == 0 {
			fmt.Fprint(os.Stderr, "Missing required argument for registry URI.\n\n")
		} else {
			fmt.Fprintln(os.Stderr, "Extra unparsed arguments:")
			fmt.Fprintln(os.Stderr, " ", strings.Join(flag.Args()[1:], " "))
			fmt.Fprint(os.Stderr, "Options should come before the registry URI argument.\n\n")
		}
		flag.Usage()
		os.Exit(2)
	}

	if *hostIp != "" {
		if !ipRegEx.MatchString(*hostIp) {
			fmt.Fprintf(os.Stderr, "Invalid IP address '%s', please use a valid address.\n", *hostIp)
			os.Exit(2)
		}
		log.Debug("Forcing host IP to", *hostIp)
	}

	if *requireLabel {
		log.Info("SERVICE_REGISTER label is required to register containers.")
	}

	var err error
	if *ipLookupSource != "" {
		bridge.SetExternalIPSource(*ipLookupSource)
		discoveredIP, err = bridge.GetIPFromExternalSource()
		if err == nil {
			log.Infof("ipLookupSource provided. Deferring to external source for IP address. Current IP is: %s", discoveredIP)
		}
		if !ipRegEx.MatchString(discoveredIP) {
			log.Error("Invalid IP address from ipLookupSource '%s', please use a valid address.\n", discoveredIP)
		}
	}

	if (*refreshTtl == 0 && *refreshInterval > 0) || (*refreshTtl > 0 && *refreshInterval == 0) {
		assert(errors.New("-ttl and -ttl-refresh must be specified together or not at all"))
	} else if *refreshTtl > 0 && *refreshTtl <= *refreshInterval {
		assert(errors.New("-ttl must be greater than -ttl-refresh"))
	}

	if *retryInterval <= 0 {
		assert(errors.New("-retry-interval must be greater than 0"))
	}

	dockerHost := os.Getenv("DOCKER_HOST")
	if dockerHost == "" {
		os.Setenv("DOCKER_HOST", "unix:///tmp/docker.sock")
	}

	docker, err := dockerapi.NewClientFromEnv()
	assert(err)

	if *deregister != "always" && *deregister != "on-success" {
		assert(errors.New("-deregister must be \"always\" or \"on-success\""))
	}
	selectedIP := *hostIp
	if discoveredIP != "" {
		selectedIP = discoveredIP
	}

	log.Info("Creating Bridge")
	b, err := bridge.New(docker, flag.Arg(0), bridge.Config{
		HostIp:          selectedIP,
		Internal:        *internal,
		UseIpFromLabel:  *useIpFromLabel,
		ForceTags:       *forceTags,
		RefreshTtl:      *refreshTtl,
		RefreshInterval: *refreshInterval,
		DeregisterCheck: *deregister,
		Cleanup:         *cleanup,
		RequireLabel:    *requireLabel,
	})
	assert(err)
	log.Info("Bridge Created")

	attempt := 0
	for *retryAttempts == -1 || attempt <= *retryAttempts {
		log.Debugf("Connecting to backend (%v/%v)", attempt, *retryAttempts)

		err = b.Ping()
		if err == nil {
			break
		}

		if err != nil && attempt == *retryAttempts {
			assert(err)
		}

		time.Sleep(time.Duration(*retryInterval) * time.Millisecond)
		attempt++
	}

	// Start event listener before listing containers to avoid missing anything
	events := make(chan *dockerapi.APIEvents)
	assert(docker.AddEventListener(events))

	b.Sync(false)

	// Start a IP check ticker only if an external source was provided
	if *ipLookupSource != "" {
		ipTicker := time.NewTicker(time.Duration(10 * time.Second))
		go func() {
			for {
				select {
				case <-ipTicker.C:
					b.Lock()
					resyncProcess(b, *ipLookupSource)
					b.Unlock()
				case <-quit:
					log.Debug("Quit message received. Exiting IP Check loop")
					ipTicker.Stop()
					return
				}
			}
		}()
	}

	// Start a dead container pruning timer to allow refresh to work independently
	if *refreshInterval > 0 {
		ticker := time.NewTicker(time.Duration(*refreshInterval) * time.Second)
		go func() {
			for {
				select {
				case <-ticker.C:
					b.PruneDeadContainers()
				case <-quit:
					log.Debug("Quit message received. Exiting PruneDeadContainer loop")
					ticker.Stop()
					return
				}
			}
		}()
	}

	// Start the TTL refresh timer
	if *refreshInterval > 0 {
		ticker := time.NewTicker(time.Duration(*refreshInterval) * time.Second)
		go func() {
			for {
				select {
				case <-ticker.C:
					b.Refresh()
				case <-quit:
					log.Debug("Quit message received. Exiting Refresh loop")
					ticker.Stop()
					return
				}
			}
		}()
	}

	// Start the resync timer if enabled
	if *resyncInterval > 0 {
		resyncTicker := time.NewTicker(time.Duration(*resyncInterval) * time.Second)
		go func() {
			for {
				select {
				case <-resyncTicker.C:
					b.Lock()
					resyncProcess(b, *ipLookupSource)
					b.Unlock()
				case <-quit:
					log.Debug("Quit message received. Exiting Resync loop")
					resyncTicker.Stop()
					return
				}
			}
		}()
	}

	// Process Docker events
	for msg := range events {
		switch msg.Status {
		case "start":
			log.Debugf("Docker Event Received: Start %s", msg.ID)
			go b.Add(msg.ID)
		case "die":
			log.Debugf("Docker Event Received: Die %s", msg.ID)
			go b.RemoveOnExit(msg.ID)
		}
	}
}

func resyncProcess(b *bridge.Bridge, ipLookupSource string) {
	if ipLookupSource != "" {
		temporaryIP, err := bridge.GetIPFromExternalSource()
		if err == nil && (temporaryIP != discoveredIP) {
			discoveredIP = temporaryIP
			log.Infof("Network change has been detected by different IP. New IP is: %s", discoveredIP)
			if !ipRegEx.MatchString(discoveredIP) {
				fmt.Fprintf(os.Stderr, "Invalid IP when polling ipLookupSource '%s', please use a valid address.\n", discoveredIP)
			} else {
				go func(ip string, bridgeInstance *bridge.Bridge) {
					b.AllocateNewIPToServices(ip)
				}(discoveredIP, b)
			}
		}
	} else {
		b.Sync(true)
	}
}
<|endoftext|>