<commit_before>// Copyright 2016, RadiantBlue Technologies, 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 logger

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/venicegeo/pz-gocommon/elasticsearch"
	"github.com/venicegeo/pz-gocommon/gocommon"
	syslogger "github.com/venicegeo/pz-gocommon/syslog"
)

const schema = "LogData"
const securitySchema = "AuditData"

type Service struct {
	sync.Mutex

	stats  Stats
	origin string

	esIndex elasticsearch.IIndex
	id      int
}

func (service *Service) Init(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) error {
	var err error

	service.stats.CreatedOn = time.Now()

	ok, err := esIndex.IndexExists()
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating index: %s", esIndex.IndexName())
		err = esIndex.Create("")
		if err != nil {
			log.Fatal(err)
		}
	}

	ok, err = esIndex.TypeExists(schema)
	if err != nil {
		return err
	}
	mapping := `{
    "dynamic": "strict",
    "properties": {
      "facility": {
        "type": "integer"
      },
      "severity": {
        "type": "integer"
      },
      "version": {
        "type": "integer"
      },
      "timeStamp": {
        "type": "string",
        "index": "not_analyzed"
      },
      "hostName": {
        "type": "string",
        "index": "not_analyzed"
      },
      "application": {
        "type": "string",
        "index": "not_analyzed"
      },
      "process": {
        "type": "string",
        "index": "not_analyzed"
      },
      "messageId": {
        "type": "string",
        "index": "not_analyzed"
      },
      "auditData": {
        "dynamic": "strict",
        "properties": {
          "actor": {
            "type": "string",
            "index": "not_analyzed"
          },
          "action": {
            "type": "string",
            "index": "not_analyzed"
          },
          "actee": {
            "type": "string",
            "index": "not_analyzed"
          }
        }
      },
      "metricData": {
        "dynamic": "strict",
        "properties": {
          "name": {
            "type": "string",
            "index": "not_analyzed"
          },
          "value": {
            "type": "double"
          },
          "object": {
            "type": "string",
            "index": "not_analyzed"
          }
        }
      },
      "sourceData": {
        "dynamic": "strict",
        "properties": {
          "file": {
            "type": "string",
            "index": "not_analyzed"
          },
          "function": {
            "type": "string",
            "index": "not_analyzed"
          },
          "line": {
            "type": "integer"
          }
        }
      },
      "message": {
        "type": "string",
        "index": "not_analyzed"
      }
    }
	}`

	if !ok {
		log.Printf("Creating type: %s", schema)

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Printf("LoggerService.Init: %s", err.Error())
			return err
		}
	}

	ok, err = esIndex.TypeExists(securitySchema)
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating type: %s", securitySchema)

		err = esIndex.SetMapping(securitySchema, piazza.JsonString(mapping))
		if err != nil {
			log.Printf("LoggerService.Init: %s", err.Error())
			return err
		}
	}

	service.esIndex = esIndex

	service.origin = string(sys.Name)

	return nil
}

func (service *Service) newInternalErrorResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusInternalServerError,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) newBadRequestResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusBadRequest,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) GetRoot() *piazza.JsonResponse {
	resp := &piazza.JsonResponse{
		StatusCode: 200,
		Data:       "Hi. I'm pz-logger.",
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) GetStats() *piazza.JsonResponse {
	service.Lock()
	t := service.stats
	service.Unlock()

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       t,
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func createQueryDslAsString(
	pagination *piazza.JsonPagination,
	params *piazza.HttpQueryParams) (string, error) {

	must := []map[string]interface{}{}

	service, err := params.GetAsString("service", "")
	if err != nil {
		return "", err
	}

	contains, err := params.GetAsString("contains", "")
	if err != nil {
		return "", err
	}

	before, err := params.GetBefore(time.Time{})
	if err != nil {
		return "", err
	}

	after, err := params.GetAfter(time.Time{})
	if err != nil {
		return "", err
	}

	if service != "" {
		must = append(must, map[string]interface{}{
			"match": map[string]interface{}{
				"service": service,
			},
		})
	}

	if contains != "" {
		must = append(must, map[string]interface{}{
			"multi_match": map[string]interface{}{
				"query":  contains,
				"fields": []string{"address", "message", "service", "severity"},
			},
		})
	}

	if !after.IsZero() || !before.IsZero() {
		rangeParams := map[string]time.Time{}

		if !after.IsZero() {
			rangeParams["gte"] = after
		}

		if !before.IsZero() {
			rangeParams["lte"] = before
		}

		must = append(must, map[string]interface{}{
			"range": map[string]interface{}{
				"createdOn": rangeParams,
			},
		})
	}

	if len(must) == 0 {
		return "", nil
	}

	dsl := map[string]interface{}{
		"query": map[string]interface{}{
			"filtered": map[string]interface{}{
				"query": map[string]interface{}{
					"bool": map[string]interface{}{
						"must": must,
					},
				},
			},
		},
		"size": pagination.PerPage,
		"from": pagination.PerPage * pagination.Page,
	}

	dsl["sort"] = map[string]string{
		pagination.SortBy: string(pagination.Order),
	}

	output, err := json.Marshal(dsl)
	if err != nil {
		return "", err
	}

	return string(output), nil
}

func (service *Service) PostSyslog(mNew *syslogger.Message) *piazza.JsonResponse {
	err := mNew.Validate()
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	err = service.postSyslog(mNew)
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
	}
	return resp
}

func (service *Service) toOldStyle(mNew *syslogger.Message) (*Message, error) {
	var severity Severity

	switch mNew.Severity {
	case syslogger.Debug:
		severity = SeverityDebug
	case syslogger.Informational:
		severity = SeverityInfo
	case syslogger.Warning:
		severity = SeverityWarning
	case syslogger.Error:
		severity = SeverityError
	case syslogger.Fatal:
		severity = SeverityFatal
	default:
		severity = SeverityError
	}

	text := mNew.String()
	application := piazza.ServiceName(mNew.Application)

	mssgOld := &Message{
		CreatedOn: time.Now(),
		Service:   application,
		Address:   mNew.HostName,
		Severity:  severity,
		Message:   text,
	}
	if err := mssgOld.Validate(); err != nil {
		return mssgOld, err
	}
	return mssgOld, nil
}

// postSyslog does not return anything. Any errors go to the local log.
func (service *Service) postSyslog(mNew *syslogger.Message) error {

	service.Lock()
	idStr := strconv.Itoa(service.id)
	service.id++
	service.Unlock()

	isAudit := mNew.AuditData != nil

	_, err := service.esIndex.PostData(schema, idStr, mNew)
	if err != nil {
		log.Printf("old message post: %s", err.Error())
		if !isAudit {
			return errors.New(fmt.Sprintf("Service.postSyslog: %s", err.Error()))
		}
	}

	if isAudit {
		_, err = service.esIndex.PostData(securitySchema, idStr, mNew)
		if err != nil {
			log.Printf("old message audit post: %s", err.Error())
			return errors.New(fmt.Sprintf("Service.postSyslog: %s", err.Error()))
		}
	}

	return nil
}

func (service *Service) getMessageCommon(params *piazza.HttpQueryParams) (*elasticsearch.SearchResult, *piazza.JsonPagination, *piazza.JsonResponse) {
	pagination, err := piazza.NewJsonPagination(params)
	if err != nil {
		return nil, nil, service.newBadRequestResponse(err)
	}

	paginationCreatedOnToTimeStamp(pagination)

	dsl, err := createQueryDslAsString(pagination, params)
	if err != nil {
		return nil, pagination, service.newBadRequestResponse(err)
	}

	var searchResult *elasticsearch.SearchResult

	if dsl == "" {
		searchResult, err = service.esIndex.FilterByMatchAll(schema, pagination)
	} else {
		searchResult, err = service.esIndex.SearchByJSON(schema, dsl)
	}
	if err != nil {
		return nil, pagination, service.newInternalErrorResponse(err)
	}
	return searchResult, pagination, nil
}

func (service *Service) GetSyslog(params *piazza.HttpQueryParams) *piazza.JsonResponse {
	var err error

	searchResult, pagination, jErr := service.getMessageCommon(params)
	if jErr != nil {
		return jErr
	}

	var lines = make([]syslogger.Message, 0)

	if searchResult != nil && searchResult.GetHits() != nil {
		for _, hit := range *searchResult.GetHits() {
			if hit.Source == nil {
				log.Printf("null source hit")
				continue
			}

			var msg syslogger.Message
			err = json.Unmarshal(*hit.Source, &msg)
			if err != nil {
				log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
				return service.newInternalErrorResponse(err)
			}

			// just in case
			err = msg.Validate()
			if err != nil {
				log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
				continue
			}

			lines = append(lines, msg)
		}
	}

	pagination.Count = int(searchResult.TotalHits())
	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       lines,
		Pagination: pagination,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}
	return resp
}
func (service *Service) GetMessage(params *piazza.HttpQueryParams) *piazza.JsonResponse {
	var err error

	searchResult, pagination, jErr := service.getMessageCommon(params)
	if jErr != nil {
		return jErr
	}
	paginationTimeStampToCreateOn(pagination)

	var lines = make([]Message, 0)

	if searchResult != nil && searchResult.GetHits() != nil {
		for _, hit := range *searchResult.GetHits() {
			if hit.Source == nil {
				log.Printf("null source hit")
				continue
			}

			var sysMsg syslogger.Message
			msg := &Message{}
			err = json.Unmarshal(*hit.Source, &sysMsg)
			if err != nil {
				log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
				return service.newInternalErrorResponse(err)
			}

			msg, err = service.toOldStyle(&sysMsg)
			if err != nil {
				log.Printf("UNABLE TO CONVERT TO OLD TYPE: %s", string(*hit.Source))
				continue
			}
			// just in case
			err = msg.Validate()
			if err != nil {
				log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
				continue
			}

			lines = append(lines, *msg)
		}
	}

	pagination.Count = int(searchResult.TotalHits())
	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       lines,
		Pagination: pagination,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}
	return resp
}
<commit_msg>Formatting, remember systest still broken<commit_after>// Copyright 2016, RadiantBlue Technologies, 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 logger

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/venicegeo/pz-gocommon/elasticsearch"
	"github.com/venicegeo/pz-gocommon/gocommon"
	syslogger "github.com/venicegeo/pz-gocommon/syslog"
)

const schema = "LogData"
const securitySchema = "AuditData"

type Service struct {
	sync.Mutex

	stats  Stats
	origin string

	esIndex elasticsearch.IIndex
	id      int
}

func (service *Service) Init(sys *piazza.SystemConfig, esIndex elasticsearch.IIndex) error {
	var err error

	service.stats.CreatedOn = time.Now()

	ok, err := esIndex.IndexExists()
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating index: %s", esIndex.IndexName())
		err = esIndex.Create("")
		if err != nil {
			log.Fatal(err)
		}
	}

	ok, err = esIndex.TypeExists(schema)
	if err != nil {
		return err
	}
	mapping := `
	{
	    "dynamic": "strict",
	    "properties": {
	    	"facility": {
        		"type": "integer"
      		},
      		"severity": {
        		"type": "integer"
      		},
      		"version": {
        		"type": "integer"
      		},
      		"timeStamp": {
        		"type": "string",
        		"index": "not_analyzed"
      		},
      		"hostName": {
        		"type": "string",
        		"index": "not_analyzed"
      		},
      		"application": {
        		"type": "string",
        		"index": "not_analyzed"
      		},
      		"process": {
        		"type": "string",
        		"index": "not_analyzed"
      		},
      		"messageId": {
        		"type": "string",
        		"index": "not_analyzed"
      		},
      		"auditData": {
        		"dynamic": "strict",
        		"properties": {
          			"actor": {
            			"type": "string",
            			"index": "not_analyzed"
          			},
          			"action": {
            			"type": "string",
            			"index": "not_analyzed"
          			},
          			"actee": {
            			"type": "string",
            			"index": "not_analyzed"
          			}
        		}
      		},
     		"metricData": {
        		"dynamic": "strict",
        		"properties": {
          			"name": {
            			"type": "string",
            			"index": "not_analyzed"
          			},
          			"value": {
            			"type": "double"
          			},
          			"object": {
            			"type": "string",
            			"index": "not_analyzed"
          			}
        		}
      		},
      		"sourceData": {
        		"dynamic": "strict",
        		"properties": {
          			"file": {
            			"type": "string",
            			"index": "not_analyzed"
          			},
          			"function": {
            			"type": "string",
            			"index": "not_analyzed"
          			},
          			"line": {
            			"type": "integer"
          			}
        		}
      		},
      		"message": {
        		"type": "string",
        		"index": "not_analyzed"
      		}
    	}
	}`

	if !ok {
		log.Printf("Creating type: %s", schema)

		err = esIndex.SetMapping(schema, piazza.JsonString(mapping))
		if err != nil {
			log.Printf("LoggerService.Init: %s", err.Error())
			return err
		}
	}

	ok, err = esIndex.TypeExists(securitySchema)
	if err != nil {
		return err
	}
	if !ok {
		log.Printf("Creating type: %s", securitySchema)

		err = esIndex.SetMapping(securitySchema, piazza.JsonString(mapping))
		if err != nil {
			log.Printf("LoggerService.Init: %s", err.Error())
			return err
		}
	}

	service.esIndex = esIndex

	service.origin = string(sys.Name)

	return nil
}

func (service *Service) newInternalErrorResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusInternalServerError,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) newBadRequestResponse(err error) *piazza.JsonResponse {
	return &piazza.JsonResponse{
		StatusCode: http.StatusBadRequest,
		Message:    err.Error(),
		Origin:     service.origin,
	}
}

func (service *Service) GetRoot() *piazza.JsonResponse {
	resp := &piazza.JsonResponse{
		StatusCode: 200,
		Data:       "Hi. I'm pz-logger.",
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func (service *Service) GetStats() *piazza.JsonResponse {
	service.Lock()
	t := service.stats
	service.Unlock()

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       t,
	}

	err := resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	return resp
}

func createQueryDslAsString(
	pagination *piazza.JsonPagination,
	params *piazza.HttpQueryParams) (string, error) {

	must := []map[string]interface{}{}

	service, err := params.GetAsString("service", "")
	if err != nil {
		return "", err
	}

	contains, err := params.GetAsString("contains", "")
	if err != nil {
		return "", err
	}

	before, err := params.GetBefore(time.Time{})
	if err != nil {
		return "", err
	}

	after, err := params.GetAfter(time.Time{})
	if err != nil {
		return "", err
	}

	if service != "" {
		must = append(must, map[string]interface{}{
			"match": map[string]interface{}{
				"service": service,
			},
		})
	}

	if contains != "" {
		must = append(must, map[string]interface{}{
			"multi_match": map[string]interface{}{
				"query":  contains,
				"fields": []string{"address", "message", "service", "severity"},
			},
		})
	}

	if !after.IsZero() || !before.IsZero() {
		rangeParams := map[string]time.Time{}

		if !after.IsZero() {
			rangeParams["gte"] = after
		}

		if !before.IsZero() {
			rangeParams["lte"] = before
		}

		must = append(must, map[string]interface{}{
			"range": map[string]interface{}{
				"createdOn": rangeParams,
			},
		})
	}

	if len(must) == 0 {
		return "", nil
	}

	dsl := map[string]interface{}{
		"query": map[string]interface{}{
			"filtered": map[string]interface{}{
				"query": map[string]interface{}{
					"bool": map[string]interface{}{
						"must": must,
					},
				},
			},
		},
		"size": pagination.PerPage,
		"from": pagination.PerPage * pagination.Page,
	}

	dsl["sort"] = map[string]string{
		pagination.SortBy: string(pagination.Order),
	}

	output, err := json.Marshal(dsl)
	if err != nil {
		return "", err
	}

	return string(output), nil
}

func (service *Service) PostSyslog(mNew *syslogger.Message) *piazza.JsonResponse {
	err := mNew.Validate()
	if err != nil {
		return service.newBadRequestResponse(err)
	}

	err = service.postSyslog(mNew)
	if err != nil {
		return service.newInternalErrorResponse(err)
	}

	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
	}
	return resp
}

func (service *Service) toOldStyle(mNew *syslogger.Message) (*Message, error) {
	var severity Severity

	switch mNew.Severity {
	case syslogger.Debug:
		severity = SeverityDebug
	case syslogger.Informational:
		severity = SeverityInfo
	case syslogger.Warning:
		severity = SeverityWarning
	case syslogger.Error:
		severity = SeverityError
	case syslogger.Fatal:
		severity = SeverityFatal
	default:
		severity = SeverityError
	}

	text := mNew.String()
	application := piazza.ServiceName(mNew.Application)

	mssgOld := &Message{
		CreatedOn: time.Now(),
		Service:   application,
		Address:   mNew.HostName,
		Severity:  severity,
		Message:   text,
	}
	if err := mssgOld.Validate(); err != nil {
		return mssgOld, err
	}
	return mssgOld, nil
}

// postSyslog does not return anything. Any errors go to the local log.
func (service *Service) postSyslog(mNew *syslogger.Message) error {

	service.Lock()
	idStr := strconv.Itoa(service.id)
	service.id++
	service.Unlock()

	isAudit := mNew.AuditData != nil

	_, err := service.esIndex.PostData(schema, idStr, mNew)
	if err != nil {
		log.Printf("old message post: %s", err.Error())
		if !isAudit {
			return errors.New(fmt.Sprintf("Service.postSyslog: %s", err.Error()))
		}
	}

	if isAudit {
		_, err = service.esIndex.PostData(securitySchema, idStr, mNew)
		if err != nil {
			log.Printf("old message audit post: %s", err.Error())
			return errors.New(fmt.Sprintf("Service.postSyslog: %s", err.Error()))
		}
	}

	return nil
}

func (service *Service) getMessageCommon(params *piazza.HttpQueryParams) (*elasticsearch.SearchResult, *piazza.JsonPagination, *piazza.JsonResponse) {
	pagination, err := piazza.NewJsonPagination(params)
	if err != nil {
		return nil, nil, service.newBadRequestResponse(err)
	}

	paginationCreatedOnToTimeStamp(pagination)

	dsl, err := createQueryDslAsString(pagination, params)
	if err != nil {
		return nil, pagination, service.newBadRequestResponse(err)
	}

	var searchResult *elasticsearch.SearchResult

	if dsl == "" {
		searchResult, err = service.esIndex.FilterByMatchAll(schema, pagination)
	} else {
		searchResult, err = service.esIndex.SearchByJSON(schema, dsl)
	}
	if err != nil {
		return nil, pagination, service.newInternalErrorResponse(err)
	}
	return searchResult, pagination, nil
}

func (service *Service) GetSyslog(params *piazza.HttpQueryParams) *piazza.JsonResponse {
	var err error

	searchResult, pagination, jErr := service.getMessageCommon(params)
	if jErr != nil {
		return jErr
	}

	var lines = make([]syslogger.Message, 0)

	if searchResult != nil && searchResult.GetHits() != nil {
		for _, hit := range *searchResult.GetHits() {
			if hit.Source == nil {
				log.Printf("null source hit")
				continue
			}

			var msg syslogger.Message
			err = json.Unmarshal(*hit.Source, &msg)
			if err != nil {
				log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
				return service.newInternalErrorResponse(err)
			}

			// just in case
			err = msg.Validate()
			if err != nil {
				log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
				continue
			}

			lines = append(lines, msg)
		}
	}

	pagination.Count = int(searchResult.TotalHits())
	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       lines,
		Pagination: pagination,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}
	return resp
}
func (service *Service) GetMessage(params *piazza.HttpQueryParams) *piazza.JsonResponse {
	var err error

	searchResult, pagination, jErr := service.getMessageCommon(params)
	if jErr != nil {
		return jErr
	}
	paginationTimeStampToCreateOn(pagination)

	var lines = make([]Message, 0)

	if searchResult != nil && searchResult.GetHits() != nil {
		for _, hit := range *searchResult.GetHits() {
			if hit.Source == nil {
				log.Printf("null source hit")
				continue
			}

			var sysMsg syslogger.Message
			msg := &Message{}
			err = json.Unmarshal(*hit.Source, &sysMsg)
			if err != nil {
				log.Printf("UNABLE TO PARSE: %s", string(*hit.Source))
				return service.newInternalErrorResponse(err)
			}

			msg, err = service.toOldStyle(&sysMsg)
			if err != nil {
				log.Printf("UNABLE TO CONVERT TO OLD TYPE: %s", string(*hit.Source))
				continue
			}
			// just in case
			err = msg.Validate()
			if err != nil {
				log.Printf("UNABLE TO VALIDATE: %s", string(*hit.Source))
				continue
			}

			lines = append(lines, *msg)
		}
	}

	pagination.Count = int(searchResult.TotalHits())
	resp := &piazza.JsonResponse{
		StatusCode: http.StatusOK,
		Data:       lines,
		Pagination: pagination,
	}

	err = resp.SetType()
	if err != nil {
		return service.newInternalErrorResponse(err)
	}
	return resp
}
<|endoftext|>


<commit_before>package logging

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
)

const (
	cannotFormatErrorPattern string = "Cannot format log statement: unrecognized parameter %#v"
)

// ErrorLogger provides the interface for outputting errors to a log sink
type ErrorLogger interface {
	// Error will result in complaints by go vet if used with a format string.
	// Use Errorf to avoid those.
	Error(parameters ...interface{})

	// Errorf is provided to get around go vet problems.
	Errorf(parameters ...interface{})
}

// FatalLogger provides the interface for outputting fatal errors.  Implementations
// are free to panic or exit the current process, so use with caution.
type FatalLogger interface {
	Fatal(parameters ...interface{})
}

// Logger defines the expected methods to be provided by logging infrastructure
type Logger interface {
	ErrorLogger
	FatalLogger
	Debug(parameters ...interface{})
	Info(parameters ...interface{})
	Warn(parameters ...interface{})
}

// ErrorWriter adapts a context.Logger so that all output from Write() goes
// to Error(...).  This is useful for HTTP error logs.
type ErrorWriter struct {
	ErrorLogger
}

func (e *ErrorWriter) Write(data []byte) (int, error) {
	e.Error(string(data))
	return len(data), nil
}

var _ io.Writer = (*ErrorWriter)(nil)

// DefaultLogger embeds an io.Writer and sends all output to that writer.  This type
// is primarily intended for testing.
type DefaultLogger struct {
	io.Writer
}

var _ Logger = DefaultLogger{}

// doWrite mimics the behavior of most logging frameworks, albeit with a simpler implementation.
func (logger DefaultLogger) doWrite(level string, parameters ...interface{}) {
	if _, err := fmt.Fprintf(logger, "[%-5.5s] ", level); err != nil {
		panic(err)
	}

	if len(parameters) > 0 {
		switch head := parameters[0].(type) {
		case fmt.Stringer:
			if _, err := fmt.Fprintf(logger, head.String(), parameters[1:]...); err != nil {
				panic(err)
			}

		case string:
			if _, err := fmt.Fprintf(logger, head, parameters[1:]...); err != nil {
				panic(err)
			}

		default:
			panic(
				errors.New(
					fmt.Sprintf(cannotFormatErrorPattern, parameters[0]),
				),
			)
		}
	}

	if _, err := fmt.Fprintln(logger); err != nil {
		panic(err)
	}
}

func (logger DefaultLogger) Debug(parameters ...interface{}) {
	logger.doWrite("DEBUG", parameters...)
}

func (logger DefaultLogger) Info(parameters ...interface{}) {
	logger.doWrite("INFO", parameters...)
}

func (logger DefaultLogger) Warn(parameters ...interface{}) {
	logger.doWrite("WARN", parameters...)
}

func (logger DefaultLogger) Error(parameters ...interface{}) {
	logger.doWrite("ERROR", parameters...)
}

func (logger DefaultLogger) Errorf(parameters ...interface{}) {
	logger.doWrite("ERROR", parameters...)
}

func (logger DefaultLogger) Fatal(parameters ...interface{}) {
	logger.doWrite("FATAL", parameters...)
}

// NewErrorLog creates a new log.Logger appropriate for http.Server.ErrorLog
func NewErrorLog(logger Logger, serverName string) *log.Logger {
	return log.New(&ErrorWriter{logger}, serverName, log.LstdFlags|log.LUTC)
}

// NewConnectionStateLogger produces a function appropriate for http.Server.ConnState.
// The returned function will log debug statements for each state change.
func NewConnectionStateLogger(logger Logger, serverName string) func(net.Conn, http.ConnState) {
	return func(connection net.Conn, connectionState http.ConnState) {
		logger.Debug(
			"[%s] [%s] -> %s",
			serverName,
			connection.LocalAddr().String(),
			connectionState,
		)
	}
}
<commit_msg>Added Printf(), which matches what a number of libraries expect<commit_after>package logging

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
)

const (
	cannotFormatErrorPattern string = "Cannot format log statement: unrecognized parameter %#v"
)

// ErrorLogger provides the interface for outputting errors to a log sink
type ErrorLogger interface {
	// Error will result in complaints by go vet if used with a format string.
	// Use Errorf to avoid those.
	Error(parameters ...interface{})

	// Errorf is provided to get around go vet problems.
	Errorf(parameters ...interface{})
}

// FatalLogger provides the interface for outputting fatal errors.  Implementations
// are free to panic or exit the current process, so use with caution.
type FatalLogger interface {
	Fatal(parameters ...interface{})
}

// Logger defines the expected methods to be provided by logging infrastructure
type Logger interface {
	ErrorLogger
	FatalLogger
	Debug(parameters ...interface{})
	Info(parameters ...interface{})
	Warn(parameters ...interface{})

	// Printf is supplied as a good number of go libraries use a method with
	// this signature to log with.  Most frameworks expect output from this
	// method to be at the INFO level.
	Printf(parameters ...interface{})
}

// ErrorWriter adapts a context.Logger so that all output from Write() goes
// to Error(...).  This is useful for HTTP error logs.
type ErrorWriter struct {
	ErrorLogger
}

func (e *ErrorWriter) Write(data []byte) (int, error) {
	e.Error(string(data))
	return len(data), nil
}

var _ io.Writer = (*ErrorWriter)(nil)

// DefaultLogger embeds an io.Writer and sends all output to that writer.  This type
// is primarily intended for testing.
type DefaultLogger struct {
	io.Writer
}

var _ Logger = DefaultLogger{}

// doWrite mimics the behavior of most logging frameworks, albeit with a simpler implementation.
func (logger DefaultLogger) doWrite(level string, parameters ...interface{}) {
	var buffer bytes.Buffer

	if _, err := fmt.Fprintf(&buffer, "[%-5.5s] ", level); err != nil {
		panic(err)
	}

	if len(parameters) > 0 {
		switch head := parameters[0].(type) {
		case fmt.Stringer:
			if _, err := fmt.Fprintf(&buffer, head.String(), parameters[1:]...); err != nil {
				panic(err)
			}

		case string:
			if _, err := fmt.Fprintf(&buffer, head, parameters[1:]...); err != nil {
				panic(err)
			}

		default:
			panic(
				errors.New(
					fmt.Sprintf(cannotFormatErrorPattern, parameters[0]),
				),
			)
		}
	}

	if _, err := fmt.Fprintln(logger, buffer.String()); err != nil {
		panic(err)
	}
}

func (logger DefaultLogger) Debug(parameters ...interface{}) {
	logger.doWrite("DEBUG", parameters...)
}

func (logger DefaultLogger) Info(parameters ...interface{}) {
	logger.doWrite("INFO", parameters...)
}

func (logger DefaultLogger) Warn(parameters ...interface{}) {
	logger.doWrite("WARN", parameters...)
}

func (logger DefaultLogger) Error(parameters ...interface{}) {
	logger.doWrite("ERROR", parameters...)
}

func (logger DefaultLogger) Errorf(parameters ...interface{}) {
	logger.doWrite("ERROR", parameters...)
}

func (logger DefaultLogger) Fatal(parameters ...interface{}) {
	logger.doWrite("FATAL", parameters...)
}

func (logger DefaultLogger) Printf(parameters ...interface{}) {
	logger.doWrite("INFO", parameters...)
}

// NewErrorLog creates a new log.Logger appropriate for http.Server.ErrorLog
func NewErrorLog(logger Logger, serverName string) *log.Logger {
	return log.New(&ErrorWriter{logger}, serverName, log.LstdFlags|log.LUTC)
}

// NewConnectionStateLogger produces a function appropriate for http.Server.ConnState.
// The returned function will log debug statements for each state change.
func NewConnectionStateLogger(logger Logger, serverName string) func(net.Conn, http.ConnState) {
	return func(connection net.Conn, connectionState http.ConnState) {
		logger.Debug(
			"[%s] [%s] -> %s",
			serverName,
			connection.LocalAddr().String(),
			connectionState,
		)
	}
}
<|endoftext|>


<commit_before>package lookup

import (
	"context"
	"fmt"
	"github.com/puppetlabs/go-evaluator/eval"
	"github.com/puppetlabs/go-evaluator/types"
	"github.com/puppetlabs/go-issues/issue"
)

// A Context is passed to a configured lookup data provider function. The
// context is guaranteed to be unique for the given function in the configuration
// where its declared.
type Context interface {
	// Parent context
	eval.Context

	// NotFound should be called by a function to indicate that a specified key
	// was not found. This is different from returning an UNDEF since UNDEF is
	// a valid value for a key.
	//
	// This method will panic with an internal value that is recovered by the
	// Lookup logic. There is no return from this method.
	NotFound()

	// Explain will add the message returned by the given function to the
	// lookup explainer. The method will only get called when the explanation
	// support is enabled
	Explain(messageProducer func() string)

	// Interpolate resolves interpolation expressions in the given value and returns
	// the result
	Interpolate(val eval.PValue) eval.PValue

	// Cache adds the given key - value association to the cache
	Cache(key string, value eval.PValue) eval.PValue

	// CacheAll adds all key - value associations in the given hash to the cache
	CacheAll(hash eval.KeyedValue)

	// CachedEntry returns the value for the given key together with
	// a boolean to indicate if the value was found or not
	CachedValue(key string) (eval.PValue, bool)

	// CachedEntries calls the consumer with each entry in the cache
	CachedEntries(consumer eval.BiConsumer)
}

type lookupCtx struct {
	eval.Context
	sharedCache *ConcurrentMap
	topProvider LookupKey
	cache map[string]eval.PValue
}

// DoWithParent is like eval.DoWithParent but enables lookup
func DoWithParent(parent context.Context, provider LookupKey, consumer func(Context) error) error {
	return eval.Puppet.DoWithParent(parent, func(c eval.Context) error {
		lc := &lookupCtx{c, NewConcurrentMap(37), provider, map[string]eval.PValue{}}
		return consumer(lc)
	})
}

func Lookup(c eval.Context, name string, dflt eval.PValue, options eval.KeyedValue) eval.PValue {
	return Lookup2(c, []string{name}, types.DefaultAnyType(), dflt, eval.EMPTY_MAP, eval.EMPTY_MAP, options, nil)
}

func Lookup2(
	ctx eval.Context,
	names []string,
	valueType eval.PType,
	defaultValue eval.PValue,
	override eval.KeyedValue,
	defaultValuesHash eval.KeyedValue,
	options eval.KeyedValue,
	block eval.Lambda) eval.PValue {
	lc, ok := ctx.(*lookupCtx)
	if !ok {
		panic(fmt.Errorf(`lookup called without lookup.Context`))
	}
	for _, name := range names {
		if v, ok := lc.lookupViaCache(NewKey(name), options); ok {
			return v
		}
	}
	if defaultValue == nil {
		// nil (as opposed to UNDEF) means that no default was provided.
		if len(names) == 1 {
			panic(eval.Error(HIERA_NAME_NOT_FOUND, issue.H{`name`: names[0]}))
		}
		panic(eval.Error(HIERA_NOT_ANY_NAME_FOUND, issue.H{`name_list`: names}))
	}
	return defaultValue
}

type notFound struct {}

var notFoundSingleton = &notFound{}

func (lookupCtx) NotFound() {
	panic(notFoundSingleton)
}

func (c *lookupCtx) Explain(messageProducer func() string) {
	// TODO: Add explanation support
}

func (c *lookupCtx) Interpolate(val eval.PValue) eval.PValue {
	return Interpolate(c, val, true)
}

func (c *lookupCtx) Cache(key string, value eval.PValue) eval.PValue {
	old, ok := c.cache[key]
	if !ok {
		old = eval.UNDEF
	}
	c.cache[key] = value
	return old
}

func (c *lookupCtx) CacheAll(hash eval.KeyedValue) {
	hash.EachPair(func(k, v eval.PValue) {
		c.cache[k.String()] = v
	})
}

func (c *lookupCtx) CachedValue(key string) (v eval.PValue, ok bool) {
	v, ok = c.cache[key]
	return
}

func (c *lookupCtx) CachedEntries(consumer eval.BiConsumer) {
	for k, v := range c.cache {
		consumer(types.WrapString(k), v)
	}
}

func (c *lookupCtx) WithScope(scope eval.Scope) eval.Context {
	return &lookupCtx{c.Context.WithScope(scope), c.sharedCache, c.topProvider, c.cache}
}

func (c *lookupCtx) lookupViaCache(key Key, options eval.KeyedValue) (eval.PValue, bool) {
	rootKey := key.Root()

	val := c.sharedCache.EnsureSet(rootKey, func() (val interface{}) {
		defer func() {
			if r := recover(); r != nil {
				if r == notFoundSingleton {
					val = r
				} else {
					panic(r)
				}
			}
		}()
		val = Interpolate(c, c.topProvider(c, rootKey, options), true)
		return
	})
	if val == notFoundSingleton {
		return nil, false
	}
	return key.Dig(val.(eval.PValue))
}<commit_msg>Add Fork() method to lookup.Context<commit_after>package lookup

import (
	"context"
	"fmt"
	"github.com/puppetlabs/go-evaluator/eval"
	"github.com/puppetlabs/go-evaluator/types"
	"github.com/puppetlabs/go-issues/issue"
)

// A Context is passed to a configured lookup data provider function. The
// context is guaranteed to be unique for the given function in the configuration
// where its declared.
type Context interface {
	// Parent context
	eval.Context

	// NotFound should be called by a function to indicate that a specified key
	// was not found. This is different from returning an UNDEF since UNDEF is
	// a valid value for a key.
	//
	// This method will panic with an internal value that is recovered by the
	// Lookup logic. There is no return from this method.
	NotFound()

	// Explain will add the message returned by the given function to the
	// lookup explainer. The method will only get called when the explanation
	// support is enabled
	Explain(messageProducer func() string)

	// Interpolate resolves interpolation expressions in the given value and returns
	// the result
	Interpolate(val eval.PValue) eval.PValue

	// Cache adds the given key - value association to the cache
	Cache(key string, value eval.PValue) eval.PValue

	// CacheAll adds all key - value associations in the given hash to the cache
	CacheAll(hash eval.KeyedValue)

	// CachedEntry returns the value for the given key together with
	// a boolean to indicate if the value was found or not
	CachedValue(key string) (eval.PValue, bool)

	// CachedEntries calls the consumer with each entry in the cache
	CachedEntries(consumer eval.BiConsumer)
}

type lookupCtx struct {
	eval.Context
	sharedCache *ConcurrentMap
	topProvider LookupKey
	cache map[string]eval.PValue
}

// DoWithParent is like eval.DoWithParent but enables lookup
func DoWithParent(parent context.Context, provider LookupKey, consumer func(Context) error) error {
	return eval.Puppet.DoWithParent(parent, func(c eval.Context) error {
		lc := &lookupCtx{c, NewConcurrentMap(37), provider, map[string]eval.PValue{}}
		return consumer(lc)
	})
}

func Lookup(c eval.Context, name string, dflt eval.PValue, options eval.KeyedValue) eval.PValue {
	return Lookup2(c, []string{name}, types.DefaultAnyType(), dflt, eval.EMPTY_MAP, eval.EMPTY_MAP, options, nil)
}

func Lookup2(
	ctx eval.Context,
	names []string,
	valueType eval.PType,
	defaultValue eval.PValue,
	override eval.KeyedValue,
	defaultValuesHash eval.KeyedValue,
	options eval.KeyedValue,
	block eval.Lambda) eval.PValue {
	lc, ok := ctx.(*lookupCtx)
	if !ok {
		panic(fmt.Errorf(`lookup called without lookup.Context`))
	}
	for _, name := range names {
		if v, ok := lc.lookupViaCache(NewKey(name), options); ok {
			return v
		}
	}
	if defaultValue == nil {
		// nil (as opposed to UNDEF) means that no default was provided.
		if len(names) == 1 {
			panic(eval.Error(HIERA_NAME_NOT_FOUND, issue.H{`name`: names[0]}))
		}
		panic(eval.Error(HIERA_NOT_ANY_NAME_FOUND, issue.H{`name_list`: names}))
	}
	return defaultValue
}

type notFound struct {}

var notFoundSingleton = &notFound{}

func (lookupCtx) NotFound() {
	panic(notFoundSingleton)
}

func (c *lookupCtx) Explain(messageProducer func() string) {
	// TODO: Add explanation support
}

func (c *lookupCtx) Interpolate(val eval.PValue) eval.PValue {
	return Interpolate(c, val, true)
}

func (c *lookupCtx) Cache(key string, value eval.PValue) eval.PValue {
	old, ok := c.cache[key]
	if !ok {
		old = eval.UNDEF
	}
	c.cache[key] = value
	return old
}

func (c *lookupCtx) CacheAll(hash eval.KeyedValue) {
	hash.EachPair(func(k, v eval.PValue) {
		c.cache[k.String()] = v
	})
}

func (c *lookupCtx) CachedValue(key string) (v eval.PValue, ok bool) {
	v, ok = c.cache[key]
	return
}

func (c *lookupCtx) CachedEntries(consumer eval.BiConsumer) {
	for k, v := range c.cache {
		consumer(types.WrapString(k), v)
	}
}

func (c *lookupCtx) Fork() eval.Context {
	return &lookupCtx{
		Context: c.Context.Fork(),
		sharedCache: c.sharedCache,
		topProvider: c.topProvider,
		cache: map[string]eval.PValue{},
	}
}

func (c *lookupCtx) WithScope(scope eval.Scope) eval.Context {
	return &lookupCtx{c.Context.WithScope(scope), c.sharedCache, c.topProvider, c.cache}
}

func (c *lookupCtx) lookupViaCache(key Key, options eval.KeyedValue) (eval.PValue, bool) {
	rootKey := key.Root()

	val := c.sharedCache.EnsureSet(rootKey, func() (val interface{}) {
		defer func() {
			if r := recover(); r != nil {
				if r == notFoundSingleton {
					val = r
				} else {
					panic(r)
				}
			}
		}()
		val = Interpolate(c, c.topProvider(c, rootKey, options), true)
		return
	})
	if val == notFoundSingleton {
		return nil, false
	}
	return key.Dig(val.(eval.PValue))
}<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/olekukonko/tablewriter"
	"github.com/urfave/cli"
	"github.com/valyala/gorpc"
	"os"
	"strings"
	"sync"
	"time"
)

var (
	// LutraVersion should match the one in lutractl/main.go
	LutraVersion = "0.1"

	// StartupServices Should only be used for the FIRST startup
	// StartupServices is the in-memory map list of processes started on a full-start boot
	StartupServices = make(map[ServiceName][]ServiceName)
	// StartupTargets ordered slice
	StartupTargets = make([]ServiceName, 0)

	// LoadedServices is used for any other actions, start, stop, etc.
	LoadedServices = make(map[ServiceName]*Service)
	// LoadedServicesMu tex to avoid issues
	LoadedServicesMu = sync.RWMutex{}

	// NetFs design the list of known network file systems to be avoided mounted at boot
	NetFs = []string{"nfs", "nfs4", "smbfs", "cifs", "codafs", "ncpfs", "shfs", "fuse", "fuseblk", "glusterfs", "davfs", "fuse.glusterfs"}
	// VirtFs design the list of known virtual file systems to avoid unmounting at shutdown
	VirtFs = []string{"proc", "sysfs", "tmpfs", "devtmpfs", "devpts"}

	// GoRPCServer for client
	GoRPCServer = &gorpc.Server{}
	// GoRPCStarted or not
	GoRPCStarted = false

	//ShuttingDown is used to break various check loops like in getty
	ShuttingDown bool

	lsFnameSerialized = "/run/lutrainit.reexec.ls.bin"
	glFnameSerialized = "/run/lutrainit.reexec.gl.bin"

	// Theses two last should only filled by LDFLAGS, see Makefile

	// LutraBuildTime is the time of the build
	LutraBuildTime string
	// LutraBuildGitHash is the git sha1 of the commit based on
	LutraBuildGitHash string
)

func main() {
	app := cli.NewApp()
	app.Name = "lutrainit"
	app.Usage = "lutra init daemon"
	app.Version = LutraVersion
	app.Commands = []cli.Command{
		CmdServicesTree,
		CmdServicesList,
		CmdSysinit,
	}
	app.Flags = append(app.Flags, []cli.Flag{}...)

	// No argument will start the system init processing
	if len(os.Args) <= 1 {
		os.Args = []string{"lutrainit", "sysinit"}
	}

	app.Run(os.Args)
}

// CmdServicesTree cli command
var CmdServicesTree = cli.Command{
	Name:        "services-tree",
	Usage:       "List the services tree",
	Description: "List the services tree",
	Action:      dumpServicesTree,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "confdir", Value: "/etc/lutrainit", Usage: "Lutrainit config directory"},
	},
}

func dumpServicesTree(ctx *cli.Context) error {
	err := setupLogging(false)
	if err != nil {
		println("[lutra] Error: This is going bad, could not setup logging", err.Error())
		// we have no choice
		// PANIC PANIC PANIC
		os.Exit(-1)
	}

	var baseDir string

	if !ctx.IsSet("confdir") {
		baseDir = "/etc/lutrainit"
	} else {
		baseDir = ctx.String("confdir")
	}
	if err = ReloadConfig(false, baseDir, false); err != nil {
		return err
	}

	time.Sleep(500 * time.Microsecond)

	// Sort the services
	SortServicesForBoot()

	// Print the tree
	for idx, target := range StartupTargets {
		fmt.Printf("+ [%d] %s\n", idx, target)
		for idx, service := range StartupServices[target] {
			fmt.Printf(" - [%d] %s\n", idx, service)
		}
	}

	return nil
}

// CmdServicesList cli command
var CmdServicesList = cli.Command{
	Name:        "services-list",
	Usage:       "List the services list",
	Description: "List the services",
	Action:      dumpServicesList,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "confdir", Value: "/etc/lutrainit", Usage: "Lutrainit config directory"},
	},
}

func dumpServicesList(ctx *cli.Context) error {
	err := setupLogging(false)
	if err != nil {
		println("[lutra] Error: This is going bad, could not setup logging", err.Error())
		// we have no choice
		// PANIC PANIC PANIC
		os.Exit(-1)
	}

	var baseDir string

	if !ctx.IsSet("confdir") {
		baseDir = "/etc/lutrainit"
	} else {
		baseDir = ctx.String("confdir")
	}
	ReloadConfig(false, baseDir, false)

	time.Sleep(500 * time.Microsecond)

	data := [][]string{}
	for _, service := range LoadedServices {
		if !service.IsService() {
			continue
		}
		data = append(data, []string{
			string(service.Name),
			string(service.WantedBy),
			service.Type,
			strings.Join(service.Requires, ","),
			strings.Join(service.After, ","),
			strings.Join(service.Before, ","),
		})
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"name", "target", "type", "requires", "after", "before"})

	for _, v := range data {
		table.Append(v)
	}
	table.Render()

	return nil
}
<commit_msg>Display target name in services-list only on first occurence<commit_after>package main

import (
	"fmt"
	"github.com/olekukonko/tablewriter"
	"github.com/urfave/cli"
	"github.com/valyala/gorpc"
	"os"
	"strings"
	"sync"
	"time"
)

var (
	// LutraVersion should match the one in lutractl/main.go
	LutraVersion = "0.1"

	// StartupServices Should only be used for the FIRST startup
	// StartupServices is the in-memory map list of processes started on a full-start boot
	StartupServices = make(map[ServiceName][]ServiceName)
	// StartupTargets ordered slice
	StartupTargets = make([]ServiceName, 0)

	// LoadedServices is used for any other actions, start, stop, etc.
	LoadedServices = make(map[ServiceName]*Service)
	// LoadedServicesMu tex to avoid issues
	LoadedServicesMu = sync.RWMutex{}

	// NetFs design the list of known network file systems to be avoided mounted at boot
	NetFs = []string{"nfs", "nfs4", "smbfs", "cifs", "codafs", "ncpfs", "shfs", "fuse", "fuseblk", "glusterfs", "davfs", "fuse.glusterfs"}
	// VirtFs design the list of known virtual file systems to avoid unmounting at shutdown
	VirtFs = []string{"proc", "sysfs", "tmpfs", "devtmpfs", "devpts"}

	// GoRPCServer for client
	GoRPCServer = &gorpc.Server{}
	// GoRPCStarted or not
	GoRPCStarted = false

	//ShuttingDown is used to break various check loops like in getty
	ShuttingDown bool

	lsFnameSerialized = "/run/lutrainit.reexec.ls.bin"
	glFnameSerialized = "/run/lutrainit.reexec.gl.bin"

	// Theses two last should only filled by LDFLAGS, see Makefile

	// LutraBuildTime is the time of the build
	LutraBuildTime string
	// LutraBuildGitHash is the git sha1 of the commit based on
	LutraBuildGitHash string
)

func main() {
	app := cli.NewApp()
	app.Name = "lutrainit"
	app.Usage = "lutra init daemon"
	app.Version = LutraVersion
	app.Commands = []cli.Command{
		CmdServicesTree,
		CmdServicesList,
		CmdSysinit,
	}
	app.Flags = append(app.Flags, []cli.Flag{}...)

	// No argument will start the system init processing
	if len(os.Args) <= 1 {
		os.Args = []string{"lutrainit", "sysinit"}
	}

	app.Run(os.Args)
}

// CmdServicesTree cli command
var CmdServicesTree = cli.Command{
	Name:        "services-tree",
	Usage:       "List the services tree",
	Description: "List the services tree",
	Action:      dumpServicesTree,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "confdir", Value: "/etc/lutrainit", Usage: "Lutrainit config directory"},
	},
}

func dumpServicesTree(ctx *cli.Context) error {
	err := setupLogging(false)
	if err != nil {
		println("[lutra] Error: This is going bad, could not setup logging", err.Error())
		// we have no choice
		// PANIC PANIC PANIC
		os.Exit(-1)
	}

	var baseDir string

	if !ctx.IsSet("confdir") {
		baseDir = "/etc/lutrainit"
	} else {
		baseDir = ctx.String("confdir")
	}
	if err = ReloadConfig(false, baseDir, false); err != nil {
		return err
	}

	time.Sleep(500 * time.Microsecond)

	// Sort the services
	SortServicesForBoot()

	// Print the tree
	for idx, target := range StartupTargets {
		fmt.Printf("+ [%d] %s\n", idx, target)
		for idx, service := range StartupServices[target] {
			fmt.Printf(" - [%d] %s\n", idx, service)
		}
	}

	return nil
}

// CmdServicesList cli command
var CmdServicesList = cli.Command{
	Name:        "services-list",
	Usage:       "List the services list",
	Description: "List the services",
	Action:      dumpServicesList,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "confdir", Value: "/etc/lutrainit", Usage: "Lutrainit config directory"},
	},
}

func dumpServicesList(ctx *cli.Context) error {
	err := setupLogging(false)
	if err != nil {
		println("[lutra] Error: This is going bad, could not setup logging", err.Error())
		// we have no choice
		// PANIC PANIC PANIC
		os.Exit(-1)
	}

	var baseDir string

	if !ctx.IsSet("confdir") {
		baseDir = "/etc/lutrainit"
	} else {
		baseDir = ctx.String("confdir")
	}
	ReloadConfig(false, baseDir, false)

	time.Sleep(500 * time.Microsecond)

	SortServicesForBoot()

	data := [][]string{}

	for _, target := range StartupTargets {
		targetDisplay := target // display the target only on the first occurence
		for _, service := range StartupServices[target] {
			s := LoadedServices[service]
			data = append(data, []string{
				string(targetDisplay),
				string(s.Name),
				s.Type,
				strings.Join(s.Requires, ","),
				strings.Join(s.After, ","),
				strings.Join(s.Before, ","),
			})
			targetDisplay = ""
		}
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"target", "name", "type", "requires", "after", "before"})

	for _, v := range data {
		table.Append(v)
	}
	table.Render()

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"os"

	"github.com/jvikstedt/alarm-bot/configuration"
	"github.com/jvikstedt/alarm-bot/tracker"
)

var conf *configuration.Configuration

func main() {
	setupConf()
	for _, c := range conf.TestObjects {
		trackResult, err := tracker.Perform(c.URL, c.MatchString, c.Status)
		if err != nil {
			fmt.Print(err)
		} else {
			fmt.Print(trackResult)
		}
	}
}

func setupConf() {
	confName := os.Getenv("ALARM_BOT_CONFIG")
	if confName == "" {
		confName = "./config.json"
	}
	conf = configuration.NewConfiguration(confName)
}
<commit_msg>Moved setupConf call inside init<commit_after>package main

import (
	"fmt"

	"os"

	"github.com/jvikstedt/alarm-bot/configuration"
	"github.com/jvikstedt/alarm-bot/tracker"
)

var conf *configuration.Configuration

func init() {
	setupConf()
}

func main() {
	for _, c := range conf.TestObjects {
		trackResult, err := tracker.Perform(c.URL, c.MatchString, c.Status)
		if err != nil {
			fmt.Print(err)
		} else {
			fmt.Print(trackResult)
		}
	}
}

func setupConf() {
	confName := os.Getenv("ALARM_BOT_CONFIG")
	if confName == "" {
		confName = "./config.json"
	}
	conf = configuration.NewConfiguration(confName)
}
<|endoftext|>


<commit_before>package manifest

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/mh-cbon/go-msi/guid"
)

type WixManifest struct {
	Product     string       `json:"product"`
	Company     string       `json:"company"`
	Version     string       `json:"version"`
	License     string       `json:"license,omitempty"`
	UpgradeCode string       `json:"upgrade-code"`
	Files       WixFiles     `json:"files,omitempty"`
	Directories []string     `json:"directories,omitempty"`
	RelDirs     []string     `json:"-"`
	Env         WixEnvList   `json:"env,omitempty"`
	Shortcuts   WixShortcuts `json:"shortcuts,omitempty"`
}

type WixFiles struct {
	Guid  string   `json:"guid"`
	Items []string `json:"items"`
}

type WixEnvList struct {
	Guid string   `json:"guid"`
	Vars []WixEnv `json:"vars"`
}
type WixEnv struct {
	Name      string `json:"name"`
	Value     string `json:"value"`
	Permanent string `json:"permanent"`
	System    string `json:"system"`
	Action    string `json:"action"`
	Part      string `json:"part"`
}
type WixShortcuts struct {
	Guid  string        `json:"guid"`
	Items []WixShortcut `json:"items"`
}
type WixShortcut struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Target      string `json:"target"`
	WDir        string `json:"wdir"`
	Arguments   string `json:"arguments"`
}

func (wixFile *WixManifest) Write(p string) error {
	if p == "" {
		p = "wix.json"
	}
	byt, err := json.MarshalIndent(wixFile, "", "  ")
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(p, byt, 0644)
	if err != nil {
		return err
	}
	return nil
}

func (wixFile *WixManifest) Load(p string) error {
	if p == "" {
		p = "wix.json"
	}
	if _, err := os.Stat(p); os.IsNotExist(err) {
		return err
	}
	dat, err := ioutil.ReadFile(p)
	if err != nil {
		return err
	}
	err = json.Unmarshal(dat, &wixFile)
	if err != nil {
		return err
	}
	return nil
}

func (wixFile *WixManifest) SetGuids() (bool, error) {
	var err error
	updated := false
	if wixFile.UpgradeCode == "" {
		wixFile.UpgradeCode, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	if wixFile.Files.Guid == "" {
		wixFile.Files.Guid, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	if wixFile.Env.Guid == "" && len(wixFile.Env.Vars) > 0 {
		wixFile.Env.Guid, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	if wixFile.Shortcuts.Guid == "" && len(wixFile.Shortcuts.Items) > 0 {
		wixFile.Shortcuts.Guid, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	return updated, nil
}

func (wixFile *WixManifest) NeedGuid() bool {
	need := false
	if wixFile.UpgradeCode == "" {
		need = true
	}
	if wixFile.Files.Guid == "" {
		need = true
	}
	if wixFile.Env.Guid == "" && len(wixFile.Env.Vars) > 0 {
		need = true
	}
	if wixFile.Shortcuts.Guid == "" && len(wixFile.Shortcuts.Items) > 0 {
		need = true
	}
	return need
}

func (wixFile *WixManifest) RewriteFilePaths(o string) error {
	var err error
	for i, file := range wixFile.Files.Items {
		file, err = filepath.Abs(file)
		if err != nil {
			return err
		}
		wixFile.Files.Items[i], err = filepath.Rel(o, file)
		if err != nil {
			return err
		}
	}
	for _, d := range wixFile.Directories {
		d, err = filepath.Abs(d)
		if err != nil {
			return err
		}
		r, err := filepath.Rel(o, d)
		if err != nil {
			return err
		}
		wixFile.RelDirs = append(wixFile.RelDirs, r)
	}
	return nil
}
<commit_msg>manifest: omit json fields when empty<commit_after>package manifest

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/mh-cbon/go-msi/guid"
)

type WixManifest struct {
	Product     string       `json:"product"`
	Company     string       `json:"company"`
	Version     string       `json:"version,omitempty"`
	License     string       `json:"license,omitempty"`
	UpgradeCode string       `json:"upgrade-code"`
	Files       WixFiles     `json:"files,omitempty"`
	Directories []string     `json:"directories,omitempty"`
	RelDirs     []string     `json:"-"`
	Env         WixEnvList   `json:"env,omitempty"`
	Shortcuts   WixShortcuts `json:"shortcuts,omitempty"`
}

type WixFiles struct {
	Guid  string   `json:"guid"`
	Items []string `json:"items"`
}

type WixEnvList struct {
	Guid string   `json:"guid"`
	Vars []WixEnv `json:"vars"`
}
type WixEnv struct {
	Name      string `json:"name"`
	Value     string `json:"value"`
	Permanent string `json:"permanent"`
	System    string `json:"system"`
	Action    string `json:"action"`
	Part      string `json:"part"`
}
type WixShortcuts struct {
	Guid  string        `json:"guid"`
	Items []WixShortcut `json:"items"`
}
type WixShortcut struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Target      string `json:"target"`
	WDir        string `json:"wdir"`
	Arguments   string `json:"arguments"`
}

func (wixFile *WixManifest) Write(p string) error {
	if p == "" {
		p = "wix.json"
	}
	byt, err := json.MarshalIndent(wixFile, "", "  ")
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(p, byt, 0644)
	if err != nil {
		return err
	}
	return nil
}

func (wixFile *WixManifest) Load(p string) error {
	if p == "" {
		p = "wix.json"
	}
	if _, err := os.Stat(p); os.IsNotExist(err) {
		return err
	}
	dat, err := ioutil.ReadFile(p)
	if err != nil {
		return err
	}
	err = json.Unmarshal(dat, &wixFile)
	if err != nil {
		return err
	}
	return nil
}

func (wixFile *WixManifest) SetGuids() (bool, error) {
	var err error
	updated := false
	if wixFile.UpgradeCode == "" {
		wixFile.UpgradeCode, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	if wixFile.Files.Guid == "" {
		wixFile.Files.Guid, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	if wixFile.Env.Guid == "" && len(wixFile.Env.Vars) > 0 {
		wixFile.Env.Guid, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	if wixFile.Shortcuts.Guid == "" && len(wixFile.Shortcuts.Items) > 0 {
		wixFile.Shortcuts.Guid, err = guid.Make()
		if err != nil {
			return false, err
		}
		updated = true
	}
	return updated, nil
}

func (wixFile *WixManifest) NeedGuid() bool {
	need := false
	if wixFile.UpgradeCode == "" {
		need = true
	}
	if wixFile.Files.Guid == "" {
		need = true
	}
	if wixFile.Env.Guid == "" && len(wixFile.Env.Vars) > 0 {
		need = true
	}
	if wixFile.Shortcuts.Guid == "" && len(wixFile.Shortcuts.Items) > 0 {
		need = true
	}
	return need
}

func (wixFile *WixManifest) RewriteFilePaths(o string) error {
	var err error
	for i, file := range wixFile.Files.Items {
		file, err = filepath.Abs(file)
		if err != nil {
			return err
		}
		wixFile.Files.Items[i], err = filepath.Rel(o, file)
		if err != nil {
			return err
		}
	}
	for _, d := range wixFile.Directories {
		d, err = filepath.Abs(d)
		if err != nil {
			return err
		}
		r, err := filepath.Rel(o, d)
		if err != nil {
			return err
		}
		wixFile.RelDirs = append(wixFile.RelDirs, r)
	}
	return nil
}
<|endoftext|>


<commit_before>// Package vtrace extends the veyron2/context to allow you to attach
// various types of debugging information.  This debugging information
// accumulates along the various parts of the context tree and can be
// inspected to help you understand the performance and behavior of
// your system even across servers and processes.
//
// A new root context, as created by v23.Runtime.NewContext()
// represents a new operation unconnected to any other.  Vtrace
// represents all the debugging information collected about this
// operation, even across servers and processes, as a single Trace.
// The Trace will be divided into a hierarchy of timespans (Spans).
// For example, imagine our high level operation is making a new
// blog post.  We may have to first authentiate with an auth server,
// then write the new post to a database, and finally notify subscribers
// of the new content.  The trace might look like this:
//
//    Trace:
//    <---------------- Make a new blog post ----------->
//    |                  |                   |
//    <- Authenticate -> |                   |
//                       |                   |
//                       <-- Write to DB --> |
//                                           <- Notify ->
//    0s                      1.5s                      3s
//
// Here we have a single trace with four Spans.  Note that some Spans
// are children of other Spans.  This structure falls directly out of
// our building off of the context.T tree.  When you derive a new
// context using SetNewSpan(), you create a Span thats a child of
// the currently active span in the context.  Note that spans that
// share a parent may overlap in time.
//
// In this case the tree would have been created with code like this:
//
//    function MakeBlogPost(ctx *context.T) {
//        authCtx, _ := vtrace.SetNewSpan(ctx, "Authenticate")
//        Authenticate(authCtx)
//        writeCtx, _ := vtrace.SetNewSpan(ctx, "Write To DB")
//        Write(writeCtx)
//        notifyCtx, _ := vtrace.SetNewSpan(ctx, "Notify")
//        Notify(notifyCtx)
//    }
//
// Just as we have Spans to represent timesspans we have Annotations
// to attach debugging information to the current span that is relevant
// to the current moment.  Currently we only support string annotations.
// You can add an annotation to the current span by calling the Spans
// Annotate method:
//
//    span := vtrace.FromContext(ctx)
//    span.Annotate("Just got an error")
//
// When you make an annotation we record the annotation and the time
// when it was attached.
// TODO(mattr): Allow other types of annotations, for example server
// information, start and stop events.
//
// Traces can be composed of large numbers of spans containing
// data collected from large numbers of different processes.  Because
// this data is large we don't collect it for every context.  By
// default we collect trace data on only a small random sample of
// the contexts that are created.  If a particular operation is of
// special importants you can force it to be collected by calling the
// Trace's ForceCollect method.  All the spans and annotations that
// are added after ForceCollect is called will be collected.
//
// If your trace has collected information you can retrieve the data
// collected so far by calling the Trace.Record() method, which gives
// you a dump in the form of a TraceRecord.
package vtrace

import (
	"v.io/v23/context"
	"v.io/v23/uniqueid"
)

// Spans represent a named time period.  You can create new spans
// to represent new parts of your computation.
// Spans are safe to use from multiple goroutines simultaneously.
type Span interface {
	// Name returns the name of the span.
	Name() string

	// ID returns the uniqueid.ID of the span.
	ID() uniqueid.Id

	// Parent returns the uniqueid.ID of this spans parent span.
	Parent() uniqueid.Id

	// Annotate adds a string annotation to the trace.  Where Spans
	// represent time periods Annotations represent data thats relevant
	// at a specific moment.
	Annotate(s string)

	// Annotatef adds an annotation to the trace.  Where Spans represent
	// time periods Annotations represent data thats relevant at a
	// specific moment.
	// format and a are interpreted as with fmt.Printf.
	Annotatef(format string, a ...interface{})

	// Finish ends the span, marking the end time.  The span should
	// not be used after Finish is called.
	Finish()

	// Trace returns the id of the trace this Span is a member of.
	Trace() uniqueid.Id
}

// Store selectively collects information about traces in the system.
type Store interface {
	// TraceRecords returns TraceRecords for all traces saved in the store.
	TraceRecords() []TraceRecord

	// TraceRecord returns a TraceRecord for a given ID.  Returns
	// nil if the given id is not present.
	TraceRecord(traceid uniqueid.Id) *TraceRecord

	// ForceCollect forces the store to collect all information about a given trace.
	ForceCollect(traceid uniqueid.Id)
}

type Manager interface {
	// SetNewTrace creates a new vtrace context that is not the child of any
	// other span.  This is useful when starting operations that are
	// disconnected from the activity ctx is performing.  For example
	// this might be used to start background tasks.
	SetNewTrace(ctx *context.T) (*context.T, Span)

	// SetContinuedTrace creates a span that represents a continuation of
	// a trace from a remote server.  name is the name of the new span and
	// req contains the parameters needed to connect this span with it's
	// trace.
	SetContinuedTrace(ctx *context.T, name string, req Request) (*context.T, Span)

	// SetNewSpan derives a context with a new Span that can be used to
	// trace and annotate operations across process boundaries.
	SetNewSpan(ctx *context.T, name string) (*context.T, Span)

	// Span finds the currently active span.
	GetSpan(ctx *context.T) Span

	// Store returns the current Store.
	GetStore(ctx *context.T) Store
}

// managerKey is used to store a Manger in the context.
type managerKey struct{}

// WithManager returns a new context with a Vtrace manager attached.
func WithManager(ctx *context.T, manager Manager) *context.T {
	return context.WithValue(ctx, managerKey{}, manager)
}

func manager(ctx *context.T) Manager {
	manager, _ := ctx.Value(managerKey{}).(Manager)
	if manager == nil {
		panic(`Vtrace is uninitialized.
You are calling a Vtrace function but vtrace has not been initialized.
This is normally handled by the runtime initialization.  You should call
v23.Init() in your main or test before performing this function.`)
	}
	return manager
}

// SetNewTrace creates a new vtrace context that is not the child of any
// other span.  This is useful when starting operations that are
// disconnected from the activity ctx is performing.  For example
// this might be used to start background tasks.
func SetNewTrace(ctx *context.T) (*context.T, Span) {
	return manager(ctx).SetNewTrace(ctx)
}

// SetContinuedTrace creates a span that represents a continuation of
// a trace from a remote server.  name is the name of the new span and
// req contains the parameters needed to connect this span with it's
// trace.
func SetContinuedTrace(ctx *context.T, name string, req Request) (*context.T, Span) {
	return manager(ctx).SetContinuedTrace(ctx, name, req)
}

// SetNewSpan derives a context with a new Span that can be used to
// trace and annotate operations across process boundaries.
func SetNewSpan(ctx *context.T, name string) (*context.T, Span) {
	return manager(ctx).SetNewSpan(ctx, name)
}

// Span finds the currently active span.
func GetSpan(ctx *context.T) Span {
	return manager(ctx).GetSpan(ctx)
}

// VtraceStore returns the current Store.
func GetStore(ctx *context.T) Store {
	return manager(ctx).GetStore(ctx)
}

// ForceCollect forces the store to collect all information about the
// current trace.
func ForceCollect(ctx *context.T) {
	m := manager(ctx)
	m.GetStore(ctx).ForceCollect(m.GetSpan(ctx).Trace())
}
<commit_msg>v23: Implement trace control in javascript.<commit_after>// Package vtrace extends the veyron2/context to allow you to attach
// various types of debugging information.  This debugging information
// accumulates along the various parts of the context tree and can be
// inspected to help you understand the performance and behavior of
// your system even across servers and processes.
//
// A new root context, as created by v23.Runtime.NewContext()
// represents a new operation unconnected to any other.  Vtrace
// represents all the debugging information collected about this
// operation, even across servers and processes, as a single Trace.
// The Trace will be divided into a hierarchy of timespans (Spans).
// For example, imagine our high level operation is making a new
// blog post.  We may have to first authentiate with an auth server,
// then write the new post to a database, and finally notify subscribers
// of the new content.  The trace might look like this:
//
//    Trace:
//    <---------------- Make a new blog post ----------->
//    |                  |                   |
//    <- Authenticate -> |                   |
//                       |                   |
//                       <-- Write to DB --> |
//                                           <- Notify ->
//    0s                      1.5s                      3s
//
// Here we have a single trace with four Spans.  Note that some Spans
// are children of other Spans.  This structure falls directly out of
// our building off of the context.T tree.  When you derive a new
// context using SetNewSpan(), you create a Span thats a child of
// the currently active span in the context.  Note that spans that
// share a parent may overlap in time.
//
// In this case the tree would have been created with code like this:
//
//    function MakeBlogPost(ctx *context.T) {
//        authCtx, _ := vtrace.SetNewSpan(ctx, "Authenticate")
//        Authenticate(authCtx)
//        writeCtx, _ := vtrace.SetNewSpan(ctx, "Write To DB")
//        Write(writeCtx)
//        notifyCtx, _ := vtrace.SetNewSpan(ctx, "Notify")
//        Notify(notifyCtx)
//    }
//
// Just as we have Spans to represent timesspans we have Annotations
// to attach debugging information to the current span that is relevant
// to the current moment.  Currently we only support string annotations.
// You can add an annotation to the current span by calling the Spans
// Annotate method:
//
//    span := vtrace.FromContext(ctx)
//    span.Annotate("Just got an error")
//
// When you make an annotation we record the annotation and the time
// when it was attached.
// TODO(mattr): Allow other types of annotations, for example server
// information, start and stop events.
//
// Traces can be composed of large numbers of spans containing
// data collected from large numbers of different processes.  Because
// this data is large we don't collect it for every context.  By
// default we collect trace data on only a small random sample of
// the contexts that are created.  If a particular operation is of
// special importants you can force it to be collected by calling the
// Trace's ForceCollect method.  All the spans and annotations that
// are added after ForceCollect is called will be collected.
//
// If your trace has collected information you can retrieve the data
// collected so far by calling the Trace.Record() method, which gives
// you a dump in the form of a TraceRecord.
package vtrace

import (
	"v.io/v23/context"
	"v.io/v23/uniqueid"
)

// Spans represent a named time period.  You can create new spans
// to represent new parts of your computation.
// Spans are safe to use from multiple goroutines simultaneously.
type Span interface {
	// Name returns the name of the span.
	Name() string

	// ID returns the uniqueid.ID of the span.
	ID() uniqueid.Id

	// Parent returns the uniqueid.ID of this spans parent span.
	Parent() uniqueid.Id

	// Annotate adds a string annotation to the trace.  Where Spans
	// represent time periods Annotations represent data thats relevant
	// at a specific moment.
	Annotate(s string)

	// Annotatef adds an annotation to the trace.  Where Spans represent
	// time periods Annotations represent data thats relevant at a
	// specific moment.
	// format and a are interpreted as with fmt.Printf.
	Annotatef(format string, a ...interface{})

	// Finish ends the span, marking the end time.  The span should
	// not be used after Finish is called.
	Finish()

	// Trace returns the id of the trace this Span is a member of.
	Trace() uniqueid.Id
}

// Store selectively collects information about traces in the system.
type Store interface {
	// TraceRecords returns TraceRecords for all traces saved in the store.
	TraceRecords() []TraceRecord

	// TraceRecord returns a TraceRecord for a given ID.  Returns
	// nil if the given id is not present.
	TraceRecord(traceid uniqueid.Id) *TraceRecord

	// ForceCollect forces the store to collect all information about a given trace.
	ForceCollect(traceid uniqueid.Id)

	// Merge merges a vtrace.Response into the current store.
	Merge(response Response)
}

type Manager interface {
	// SetNewTrace creates a new vtrace context that is not the child of any
	// other span.  This is useful when starting operations that are
	// disconnected from the activity ctx is performing.  For example
	// this might be used to start background tasks.
	SetNewTrace(ctx *context.T) (*context.T, Span)

	// SetContinuedTrace creates a span that represents a continuation of
	// a trace from a remote server.  name is the name of the new span and
	// req contains the parameters needed to connect this span with it's
	// trace.
	SetContinuedTrace(ctx *context.T, name string, req Request) (*context.T, Span)

	// SetNewSpan derives a context with a new Span that can be used to
	// trace and annotate operations across process boundaries.
	SetNewSpan(ctx *context.T, name string) (*context.T, Span)

	// Span finds the currently active span.
	GetSpan(ctx *context.T) Span

	// Store returns the current Store.
	GetStore(ctx *context.T) Store

	// Generate a Request from the current context.
	GetRequest(ctx *context.T) Request

	// Generate a Response from the current context.
	GetResponse(ctx *context.T) Response
}

// managerKey is used to store a Manger in the context.
type managerKey struct{}

// WithManager returns a new context with a Vtrace manager attached.
func WithManager(ctx *context.T, manager Manager) *context.T {
	return context.WithValue(ctx, managerKey{}, manager)
}

func manager(ctx *context.T) Manager {
	manager, _ := ctx.Value(managerKey{}).(Manager)
	if manager == nil {
		panic(`Vtrace is uninitialized.
You are calling a Vtrace function but vtrace has not been initialized.
This is normally handled by the runtime initialization.  You should call
v23.Init() in your main or test before performing this function.`)
	}
	return manager
}

// SetNewTrace creates a new vtrace context that is not the child of any
// other span.  This is useful when starting operations that are
// disconnected from the activity ctx is performing.  For example
// this might be used to start background tasks.
func SetNewTrace(ctx *context.T) (*context.T, Span) {
	return manager(ctx).SetNewTrace(ctx)
}

// SetContinuedTrace creates a span that represents a continuation of
// a trace from a remote server.  name is the name of the new span and
// req contains the parameters needed to connect this span with it's
// trace.
func SetContinuedTrace(ctx *context.T, name string, req Request) (*context.T, Span) {
	return manager(ctx).SetContinuedTrace(ctx, name, req)
}

// SetNewSpan derives a context with a new Span that can be used to
// trace and annotate operations across process boundaries.
func SetNewSpan(ctx *context.T, name string) (*context.T, Span) {
	return manager(ctx).SetNewSpan(ctx, name)
}

// Span finds the currently active span.
func GetSpan(ctx *context.T) Span {
	return manager(ctx).GetSpan(ctx)
}

// VtraceStore returns the current Store.
func GetStore(ctx *context.T) Store {
	return manager(ctx).GetStore(ctx)
}

// ForceCollect forces the store to collect all information about the
// current trace.
func ForceCollect(ctx *context.T) {
	m := manager(ctx)
	m.GetStore(ctx).ForceCollect(m.GetSpan(ctx).Trace())
}

// Generate a Request from the current context.
func GetRequest(ctx *context.T) Request {
	return manager(ctx).GetRequest(ctx)
}

// Generate a Response from the current context.
func GetResponse(ctx *context.T) Response {
	return manager(ctx).GetResponse(ctx)
}
<|endoftext|>


<commit_before>package vxlan

import (
	gonet "net"
	"strconv"
	"errors"
	"strings"
	"fmt"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/network"
	"github.com/samalba/dockerclient"
	"github.com/vishvananda/netlink"
)

type Driver struct {
	network.Driver
	scope	          string
	vtepdev           string
	networks          map[string]*NetworkState
	docker	          *dockerclient.DockerClient
}

// NetworkState is filled in at network creation time
// it contains state that we wish to keep for each network
type NetworkState struct {
	VXLan	 *netlink.Vxlan
	Gateway  string
	IPv4Data []*network.IPAMData
	IPv6Data []*network.IPAMData
}

func NewDriver(scope string, vtepdev string) (*Driver, error) {
	docker, err := dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)
	if err != nil {
		return nil, err
	}
	d := &Driver{
		scope: scope,
		vtepdev: vtepdev,
		networks: make(map[string]*NetworkState),
		docker: docker,
	}
	return d, nil
}

func (d *Driver) GetCapabilities() (*network.CapabilitiesResponse, error) {
	log.Debugf("Get Capabilities request")
	res := &network.CapabilitiesResponse{
		Scope: d.scope,
	}
	log.Debugf("Responding with %+v", res)
	return res, nil
}

type intNames struct {
	VxlanName  string
}

func getIntNames(netID string, docker *dockerclient.DockerClient) (*intNames, error) {
	net, err := docker.InspectNetwork(netID)
	if err != nil {
		return nil, err
	}

	names := &intNames{}

	if net.Driver != "vxlan" {
		log.Errorf("Network %v is not a vxlan network", netID)
		return nil, errors.New("Not a vxlan network")
	}

	names.VxlanName = "vx_" + netID[:12]

	// get interface names from options first
	for k, v := range net.Options {
		if k == "vxlanName" {
			names.VxlanName = v
		}
	}

	return names, nil
}

func getGateway(netID string, docker dockerclient.DockerClient) (string, error) {
	net, err := docker.InspectNetwork(netID)
	if err != nil {
		return "", err
	}

	for i := range net.IPAM.Config {
		if net.IPAM.Config[i].Gateway != "" {
			return net.IPAM.Config[i].Gateway, nil
		}
	}
	return "", nil
}

type intLinks struct {
	Vxlan  *netlink.Vxlan
}

// this function gets netlink devices or creates them if they don't exist
func (d *Driver) getLinks(netID string) (*intLinks, error) {
	docker := d.docker
	net, err := docker.InspectNetwork(netID)
	if err != nil {
		return nil, err
	}

	if net.Driver != "vxlan" {
		log.Errorf("Network %v is not a vxlan network", netID)
		return nil, errors.New("Not a vxlan network")
	}

	names, err := getIntNames(netID, docker)
	if err != nil {
		return nil, err
	}

	// get or create links
	var vxlan *netlink.Vxlan
	vxlanlink, err := netlink.LinkByName(names.VxlanName)
	if err == nil {
		vxlan = &netlink.Vxlan{
			LinkAttrs: *vxlanlink.Attrs(),
		}
	} else {
		vxlan, err = d.createVxLan(names.VxlanName, net)
		if err != nil {
			return nil, err
		}
	}

	links := &intLinks{
		Vxlan: vxlan,
	}

	return links, nil
}

func (d *Driver) createVxLan(vxlanName string, net *dockerclient.NetworkResource) (*netlink.Vxlan, error) {
	vxlan := &netlink.Vxlan{
		LinkAttrs: netlink.LinkAttrs{
			Name: vxlanName,
		},
	}

	// Parse interface options
	for k, v := range net.Options {
		if k == "vxlanMTU" {
			MTU, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.LinkAttrs.MTU = MTU
		}
		if k == "vxlanHardwareAddr" {
			HardwareAddr, err := gonet.ParseMAC(v)
			if err != nil {
				return nil, err
			}
			vxlan.LinkAttrs.HardwareAddr = HardwareAddr
		}
		if k == "vxlanTxQLen" {
			TxQLen, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.LinkAttrs.TxQLen = TxQLen
		}
		if k == "VxlanId" {
			log.Debugf("VxlanID: %+v", v)
			VxlanId, err := strconv.ParseInt(v, 0, 32)
			if err != nil {
				return nil, err
			}
			log.Debugf("VxlanID: %+v", VxlanId)
			log.Debugf("int(VxlanID): %+v", int(VxlanId))
			vxlan.VxlanId = int(VxlanId)
		}
		if k == "VtepDev" {
			vtepDev, err := netlink.LinkByName(v)
			if err != nil {
				return nil, err
			}
			vxlan.VtepDevIndex = vtepDev.Attrs().Index
		}
		if k == "SrcAddr" {
			vxlan.SrcAddr = gonet.ParseIP(v)
		}
		if k == "Group" {
			vxlan.Group = gonet.ParseIP(v)
		}
		if k == "TTL" {
			TTL, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.TTL = TTL
		}
		if k == "TOS" {
			TOS, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.TOS = TOS
		}
		if k == "Learning" {
			Learning, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.Learning = Learning
		}
		if k == "Proxy" {
			Proxy, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.Proxy = Proxy
		}
		if k == "RSC" {
			RSC, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.RSC = RSC
		}
		if k == "L2miss" {
			L2miss, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.L2miss = L2miss
		}
		if k == "L3miss" {
			L3miss, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.L3miss = L3miss
		}
		if k == "NoAge" {
			NoAge, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.NoAge = NoAge
		}
		if k == "GBP" {
			GBP, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.GBP = GBP
		}
		if k == "Age" {
			Age, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.Age = Age
		}
		if k == "Limit" {
			Limit, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.Limit = Limit
		}
		if k == "Port" {
			Port, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.Port = Port
		}
		if k == "PortLow" {
			PortLow, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.PortLow = PortLow
		}
		if k == "PortHigh" {
			PortHigh, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.PortHigh = PortHigh
		}
	}

	if d.vtepdev != "" {
		vtepDev, err := netlink.LinkByName(d.vtepdev)
		if err != nil {
			return nil, err
		}
		vxlan.VtepDevIndex = vtepDev.Attrs().Index
	}

	err := netlink.LinkAdd(vxlan)
	if err != nil {
		return nil, err
	}

	// Parse interface options
	for k, v := range net.Options {
		if k == "vxlanHardwareAddr" {
			hardwareAddr, err := gonet.ParseMAC(v)
			if err != nil {
				return nil, err
			}
			err = netlink.LinkSetHardwareAddr(vxlan, hardwareAddr)
			if err != nil {
				return nil, err
			}
		}
		if k == "vxlanMTU" {
			mtu, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			err = netlink.LinkSetMTU(vxlan, mtu)
			if err != nil {
				return nil, err
			}
		}
	}

	// bring interfaces up
	err = netlink.LinkSetUp(vxlan)
	if err != nil {
		return nil, err
	}

	if d.scope == "local" {
		for i := range net.IPAM.Config {
			mask := strings.Split(net.IPAM.Config[i].Subnet, "/")[1]
			gatewayIP, err := netlink.ParseAddr(net.IPAM.Config[i].Gateway + "/" + mask)
			if err != nil {
				return nil, err
			}
			netlink.AddrAdd(vxlan, gatewayIP)
		}
	}

	return vxlan, nil
}

func (d *Driver) CreateNetwork(r *network.CreateNetworkRequest) error {
	log.Debugf("Create network request: %+v", r)

	// return nil and lazy create the network when a container joins it
	// Active creation when allow_empty is enabled will be handled by watching libkv
	return nil
}

func (d *Driver) deleteNics(netID string) error {
	names, err := getIntNames(netID, d.docker)
	if err != nil {
		return err
	}

	vxlan, err := netlink.LinkByName(names.VxlanName)
	if err == nil {
		err := netlink.LinkDel(vxlan)
		if err != nil {
			return err
		}
		log.Debugf("Deleting interface %+v", names.VxlanName)
	}

	return nil
}

func (d *Driver) DeleteNetwork(r *network.DeleteNetworkRequest) error {
	netID := r.NetworkID
	return d.deleteNics(netID)
}

func (d *Driver) CreateEndpoint(r *network.CreateEndpointRequest) (*network.CreateEndpointResponse, error) {
	log.Debugf("Create endpoint request: %+v", r)
	netID := r.NetworkID
	// get the links
	_, err := d.getLinks(netID)
	if err != nil {
		return nil, err
	}
	return &network.CreateEndpointResponse{}, nil
}

func (d *Driver) DeleteEndpoint(r *network.DeleteEndpointRequest) error {
	log.Debugf("Delete endpoint request: %+v", r)
	netID := r.NetworkID

	links, err := d.getLinks(netID)
	if err != nil {
		return err
	}
	VxlanIndex := links.Vxlan.LinkAttrs.Index

	allLinks, err := netlink.LinkList()
	if err != nil {
		return err
	}

	// FIXME: Check for macvlan interfaces with vxlan as parent in every
	// docker namespace

	for i := range allLinks {
		if allLinks[i].Attrs().Index != VxlanIndex {
			return nil
		}
	}

	log.Debugf("No interfaces attached to vxlan: deleting vxlan interface.")
	return d.deleteNics(netID)
}

func (d *Driver) EndpointInfo(r *network.InfoRequest) (*network.InfoResponse, error) {
	res := &network.InfoResponse{
		Value: make(map[string]string),
	}
	return res, nil
}

func (d *Driver) Join(r *network.JoinRequest) (*network.JoinResponse, error) {
	netID := r.NetworkID
	// get the links
	links, err := d.getLinks(netID)
	if err != nil {
		return nil, err
	}

	// Create a macvlan link
	macvlan := &netlink.Macvlan{
		LinkAttrs: netlink.LinkAttrs{
			Name:        "macvlan_" + r.EndpointID[:7],
			ParentIndex: links.Vxlan.LinkAttrs.Index,
		},
		Mode: netlink.MACVLAN_MODE_BRIDGE,
	}
	if err := netlink.LinkAdd(macvlan); err != nil {
		return nil, err
	}

	gateway, err := getGateway(netID, *d.docker)
	if err != nil {
		return nil, err
	}
	res := &network.JoinResponse{
		InterfaceName: network.InterfaceName{
			SrcName:   "macvlan_" + r.EndpointID[:7],
			DstPrefix: "eth",
		},
		Gateway: gateway,
	}
	log.Debugf("Join endpoint %s:%s to %s", r.NetworkID, r.EndpointID, r.SandboxKey)
	return res, nil
}

func (d *Driver) Leave(r *network.LeaveRequest) error {

	linkName := "macvlan_" + r.EndpointID[:7]
	time.Sleep(10 * time.Second)
	vlanLink, err := netlink.LinkByName(linkName)
	if err != nil {
		return fmt.Errorf("failed to find interface %s on the Docker host : %v", linkName, err)
	}
	// verify a parent interface isn't being deleted
	if vlanLink.Attrs().ParentIndex == 0 {
		return fmt.Errorf("interface %s does not appear to be a slave device: %v", linkName, err)
	}
	// delete the macvlan slave device
	if err := netlink.LinkDel(vlanLink); err != nil {
		return fmt.Errorf("failed to delete  %s link: %v", linkName, err)
	}

	log.Debugf("Deleted subinterface: %s", linkName)
	return nil

}
<commit_msg>implement externalconnectivity functions<commit_after>package vxlan

import (
	gonet "net"
	"strconv"
	"errors"
	"strings"
	"fmt"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/network"
	"github.com/samalba/dockerclient"
	"github.com/vishvananda/netlink"
)

type Driver struct {
	network.Driver
	scope	          string
	vtepdev           string
	networks          map[string]*NetworkState
	docker	          *dockerclient.DockerClient
}

// NetworkState is filled in at network creation time
// it contains state that we wish to keep for each network
type NetworkState struct {
	VXLan	 *netlink.Vxlan
	Gateway  string
	IPv4Data []*network.IPAMData
	IPv6Data []*network.IPAMData
}

func NewDriver(scope string, vtepdev string) (*Driver, error) {
	docker, err := dockerclient.NewDockerClient("unix:///var/run/docker.sock", nil)
	if err != nil {
		return nil, err
	}
	d := &Driver{
		scope: scope,
		vtepdev: vtepdev,
		networks: make(map[string]*NetworkState),
		docker: docker,
	}
	return d, nil
}

func (d *Driver) GetCapabilities() (*network.CapabilitiesResponse, error) {
	log.Debugf("Get Capabilities request")
	res := &network.CapabilitiesResponse{
		Scope: d.scope,
	}
	log.Debugf("Responding with %+v", res)
	return res, nil
}

type intNames struct {
	VxlanName  string
}

func getIntNames(netID string, docker *dockerclient.DockerClient) (*intNames, error) {
	net, err := docker.InspectNetwork(netID)
	if err != nil {
		return nil, err
	}

	names := &intNames{}

	if net.Driver != "vxlan" {
		log.Errorf("Network %v is not a vxlan network", netID)
		return nil, errors.New("Not a vxlan network")
	}

	names.VxlanName = "vx_" + netID[:12]

	// get interface names from options first
	for k, v := range net.Options {
		if k == "vxlanName" {
			names.VxlanName = v
		}
	}

	return names, nil
}

func getGateway(netID string, docker dockerclient.DockerClient) (string, error) {
	net, err := docker.InspectNetwork(netID)
	if err != nil {
		return "", err
	}

	for i := range net.IPAM.Config {
		if net.IPAM.Config[i].Gateway != "" {
			return net.IPAM.Config[i].Gateway, nil
		}
	}
	return "", nil
}

type intLinks struct {
	Vxlan  *netlink.Vxlan
}

// this function gets netlink devices or creates them if they don't exist
func (d *Driver) getLinks(netID string) (*intLinks, error) {
	docker := d.docker
	net, err := docker.InspectNetwork(netID)
	if err != nil {
		return nil, err
	}

	if net.Driver != "vxlan" {
		log.Errorf("Network %v is not a vxlan network", netID)
		return nil, errors.New("Not a vxlan network")
	}

	names, err := getIntNames(netID, docker)
	if err != nil {
		return nil, err
	}

	// get or create links
	var vxlan *netlink.Vxlan
	vxlanlink, err := netlink.LinkByName(names.VxlanName)
	if err == nil {
		vxlan = &netlink.Vxlan{
			LinkAttrs: *vxlanlink.Attrs(),
		}
	} else {
		vxlan, err = d.createVxLan(names.VxlanName, net)
		if err != nil {
			return nil, err
		}
	}

	links := &intLinks{
		Vxlan: vxlan,
	}

	return links, nil
}

func (d *Driver) createVxLan(vxlanName string, net *dockerclient.NetworkResource) (*netlink.Vxlan, error) {
	vxlan := &netlink.Vxlan{
		LinkAttrs: netlink.LinkAttrs{
			Name: vxlanName,
		},
	}

	// Parse interface options
	for k, v := range net.Options {
		if k == "vxlanMTU" {
			MTU, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.LinkAttrs.MTU = MTU
		}
		if k == "vxlanHardwareAddr" {
			HardwareAddr, err := gonet.ParseMAC(v)
			if err != nil {
				return nil, err
			}
			vxlan.LinkAttrs.HardwareAddr = HardwareAddr
		}
		if k == "vxlanTxQLen" {
			TxQLen, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.LinkAttrs.TxQLen = TxQLen
		}
		if k == "VxlanId" {
			log.Debugf("VxlanID: %+v", v)
			VxlanId, err := strconv.ParseInt(v, 0, 32)
			if err != nil {
				return nil, err
			}
			log.Debugf("VxlanID: %+v", VxlanId)
			log.Debugf("int(VxlanID): %+v", int(VxlanId))
			vxlan.VxlanId = int(VxlanId)
		}
		if k == "VtepDev" {
			vtepDev, err := netlink.LinkByName(v)
			if err != nil {
				return nil, err
			}
			vxlan.VtepDevIndex = vtepDev.Attrs().Index
		}
		if k == "SrcAddr" {
			vxlan.SrcAddr = gonet.ParseIP(v)
		}
		if k == "Group" {
			vxlan.Group = gonet.ParseIP(v)
		}
		if k == "TTL" {
			TTL, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.TTL = TTL
		}
		if k == "TOS" {
			TOS, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.TOS = TOS
		}
		if k == "Learning" {
			Learning, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.Learning = Learning
		}
		if k == "Proxy" {
			Proxy, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.Proxy = Proxy
		}
		if k == "RSC" {
			RSC, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.RSC = RSC
		}
		if k == "L2miss" {
			L2miss, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.L2miss = L2miss
		}
		if k == "L3miss" {
			L3miss, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.L3miss = L3miss
		}
		if k == "NoAge" {
			NoAge, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.NoAge = NoAge
		}
		if k == "GBP" {
			GBP, err := strconv.ParseBool(v)
			if err != nil {
				return nil, err
			}
			vxlan.GBP = GBP
		}
		if k == "Age" {
			Age, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.Age = Age
		}
		if k == "Limit" {
			Limit, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.Limit = Limit
		}
		if k == "Port" {
			Port, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.Port = Port
		}
		if k == "PortLow" {
			PortLow, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.PortLow = PortLow
		}
		if k == "PortHigh" {
			PortHigh, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			vxlan.PortHigh = PortHigh
		}
	}

	if d.vtepdev != "" {
		vtepDev, err := netlink.LinkByName(d.vtepdev)
		if err != nil {
			return nil, err
		}
		vxlan.VtepDevIndex = vtepDev.Attrs().Index
	}

	err := netlink.LinkAdd(vxlan)
	if err != nil {
		return nil, err
	}

	// Parse interface options
	for k, v := range net.Options {
		if k == "vxlanHardwareAddr" {
			hardwareAddr, err := gonet.ParseMAC(v)
			if err != nil {
				return nil, err
			}
			err = netlink.LinkSetHardwareAddr(vxlan, hardwareAddr)
			if err != nil {
				return nil, err
			}
		}
		if k == "vxlanMTU" {
			mtu, err := strconv.Atoi(v)
			if err != nil {
				return nil, err
			}
			err = netlink.LinkSetMTU(vxlan, mtu)
			if err != nil {
				return nil, err
			}
		}
	}

	// bring interfaces up
	err = netlink.LinkSetUp(vxlan)
	if err != nil {
		return nil, err
	}

	if d.scope == "local" {
		for i := range net.IPAM.Config {
			mask := strings.Split(net.IPAM.Config[i].Subnet, "/")[1]
			gatewayIP, err := netlink.ParseAddr(net.IPAM.Config[i].Gateway + "/" + mask)
			if err != nil {
				return nil, err
			}
			netlink.AddrAdd(vxlan, gatewayIP)
		}
	}

	return vxlan, nil
}

func (d *Driver) CreateNetwork(r *network.CreateNetworkRequest) error {
	log.Debugf("Create network request: %+v", r)

	// return nil and lazy create the network when a container joins it
	// Active creation when allow_empty is enabled will be handled by watching libkv
	return nil
}

func (d *Driver) deleteNics(netID string) error {
	names, err := getIntNames(netID, d.docker)
	if err != nil {
		return err
	}

	vxlan, err := netlink.LinkByName(names.VxlanName)
	if err == nil {
		err := netlink.LinkDel(vxlan)
		if err != nil {
			return err
		}
		log.Debugf("Deleting interface %+v", names.VxlanName)
	}

	return nil
}

func (d *Driver) DeleteNetwork(r *network.DeleteNetworkRequest) error {
	netID := r.NetworkID
	return d.deleteNics(netID)
}

func (d *Driver) CreateEndpoint(r *network.CreateEndpointRequest) (*network.CreateEndpointResponse, error) {
	log.Debugf("Create endpoint request: %+v", r)
	netID := r.NetworkID
	// get the links
	_, err := d.getLinks(netID)
	if err != nil {
		return nil, err
	}
	return &network.CreateEndpointResponse{}, nil
}

func (d *Driver) DeleteEndpoint(r *network.DeleteEndpointRequest) error {
	log.Debugf("Delete endpoint request: %+v", r)
	netID := r.NetworkID

	links, err := d.getLinks(netID)
	if err != nil {
		return err
	}
	VxlanIndex := links.Vxlan.LinkAttrs.Index

	allLinks, err := netlink.LinkList()
	if err != nil {
		return err
	}

	// FIXME: Check for macvlan interfaces with vxlan as parent in every
	// docker namespace

	for i := range allLinks {
		if allLinks[i].Attrs().Index != VxlanIndex {
			return nil
		}
	}

	log.Debugf("No interfaces attached to vxlan: deleting vxlan interface.")
	return d.deleteNics(netID)
}

func (d *Driver) EndpointInfo(r *network.InfoRequest) (*network.InfoResponse, error) {
	res := &network.InfoResponse{
		Value: make(map[string]string),
	}
	return res, nil
}

func (d *Driver) Join(r *network.JoinRequest) (*network.JoinResponse, error) {
	netID := r.NetworkID
	// get the links
	links, err := d.getLinks(netID)
	if err != nil {
		return nil, err
	}

	// Create a macvlan link
	macvlan := &netlink.Macvlan{
		LinkAttrs: netlink.LinkAttrs{
			Name:        "macvlan_" + r.EndpointID[:7],
			ParentIndex: links.Vxlan.LinkAttrs.Index,
		},
		Mode: netlink.MACVLAN_MODE_BRIDGE,
	}
	if err := netlink.LinkAdd(macvlan); err != nil {
		return nil, err
	}

	gateway, err := getGateway(netID, *d.docker)
	if err != nil {
		return nil, err
	}
	res := &network.JoinResponse{
		InterfaceName: network.InterfaceName{
			SrcName:   "macvlan_" + r.EndpointID[:7],
			DstPrefix: "eth",
		},
		Gateway: gateway,
	}
	log.Debugf("Join endpoint %s:%s to %s", r.NetworkID, r.EndpointID, r.SandboxKey)
	return res, nil
}

func (d *Driver) Leave(r *network.LeaveRequest) error {

	linkName := "macvlan_" + r.EndpointID[:7]
	time.Sleep(10 * time.Second)
	vlanLink, err := netlink.LinkByName(linkName)
	if err != nil {
		return fmt.Errorf("failed to find interface %s on the Docker host : %v", linkName, err)
	}
	// verify a parent interface isn't being deleted
	if vlanLink.Attrs().ParentIndex == 0 {
		return fmt.Errorf("interface %s does not appear to be a slave device: %v", linkName, err)
	}
	// delete the macvlan slave device
	if err := netlink.LinkDel(vlanLink); err != nil {
		return fmt.Errorf("failed to delete  %s link: %v", linkName, err)
	}

	log.Debugf("Deleted subinterface: %s", linkName)
	return nil

}

// The vxlan driver will not expose ports, just respond empty.
func (d *Driver) ProgramExternalConnectivity(r *network.ProgramExternalConnectivityRequest) error {
	return nil
}

func (d *Driver) RevokeExternalConnectivity(r *network.RevokeExternalConnectivityRequest) error {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
	"time"

	. "github.com/aandryashin/matchers"
	"github.com/fsnotify/fsnotify"
)

func TestSingleTimer(t *testing.T) {
	watcher, _ := fsnotify.NewWatcher()
	defer watcher.Close()
	call := false
	watch(watcher, 15*time.Millisecond, func() {
		call = true
	})
	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}
	<-time.After(10 * time.Millisecond)
	AssertThat(t, call, Is{false})
	<-time.After(10 * time.Millisecond)
	AssertThat(t, call, Is{true})
}

func TestMultipleTimer(t *testing.T) {
	watcher, _ := fsnotify.NewWatcher()
	defer watcher.Close()

	call := false
	watch(watcher, 15*time.Millisecond, func() {
		call = true
	})
	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

	<-time.After(10 * time.Millisecond)
	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

	<-time.After(10 * time.Millisecond)
	AssertThat(t, call, Is{false})

	<-time.After(10 * time.Millisecond)
	AssertThat(t, call, Is{true})
}

//func TestTimerCalledOnce(t *testing.T) {
//	watcher, _ := fsnotify.NewWatcher()
//	defer watcher.Close()

//	call := 0
//	watch(watcher, 20*time.Millisecond, func() {
//		call++
//	})
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	AssertThat(t, call, EqualTo{0})

//	<-time.After(20 * time.Millisecond)
//	AssertThat(t, call, EqualTo{1})
//}
<commit_msg>Disabled all timer tests<commit_after>package main

//import (
//	"testing"
//	"time"

//	. "github.com/aandryashin/matchers"
//	"github.com/fsnotify/fsnotify"
//)

//func TestSingleTimer(t *testing.T) {
//	watcher, _ := fsnotify.NewWatcher()
//	defer watcher.Close()
//	call := false
//	watch(watcher, 15*time.Millisecond, func() {
//		call = true
//	})
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}
//	<-time.After(10 * time.Millisecond)
//	AssertThat(t, call, Is{false})
//	<-time.After(10 * time.Millisecond)
//	AssertThat(t, call, Is{true})
//}

//func TestMultipleTimer(t *testing.T) {
//	watcher, _ := fsnotify.NewWatcher()
//	defer watcher.Close()

//	call := false
//	watch(watcher, 15*time.Millisecond, func() {
//		call = true
//	})
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	AssertThat(t, call, Is{false})

//	<-time.After(10 * time.Millisecond)
//	AssertThat(t, call, Is{true})
//}

//func TestTimerCalledOnce(t *testing.T) {
//	watcher, _ := fsnotify.NewWatcher()
//	defer watcher.Close()

//	call := 0
//	watch(watcher, 20*time.Millisecond, func() {
//		call++
//	})
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	watcher.Events <- fsnotify.Event{Op: fsnotify.Create}

//	<-time.After(10 * time.Millisecond)
//	AssertThat(t, call, EqualTo{0})

//	<-time.After(20 * time.Millisecond)
//	AssertThat(t, call, EqualTo{1})
//}
<|endoftext|>