<commit_before>// Take well-formed json from either stdin or an input file and create an attachment notification for Slack
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"flag"
	"fmt"
	"github.com/nlopes/slack"
	"github.com/yieldbot/sensuplugin/sensuhandler"
	"github.com/yieldbot/sensuplugin/sensuutil"
	//"github.com/yieldbot/sensuslack/lib"
	"strconv"
	"strings"
	"time"
)

func setColor(status int) string {
	switch status {
	case 0:
		return "#33CC33"
	case 1:
		return "warning"
	case 2:
		return "#FF0000"
	case 3:
		return "#FF6600"
	default:
		return "#FF6600"
	}
}

func cleanOutput(output string) string {
	return strings.Split(output, ":")[0]
}

func main() {

	slackTokenPtr := flag.String("token", "", "the slack integration token")
	channelPtr := flag.String("channel", "monitoring-test", "the channel to post notifications to")

	flag.Parse()

	slackToken := *slackTokenPtr
	channelName := *channelPtr
	channelID := "C09JY7W0P"

	sensuEvent := new(sensuhandler.SensuEvent)
	sensuEvent = sensuEvent.AcquireSensuEvent()

	// YELLOW
	// this is ugly, needs to be a better way to do this
	if slackToken == "" {
		fmt.Print("Please enter a slack integration token")
		sensuutil.Exit("CONFIGERROR")
	}

	fmt.Printf(channelName)

	// for k, v := range lib.SlackChannels {
	// 	if channelName == k {
	// 		channelID = v
	// 	}
	// }

	if channelID == "000000" {
		fmt.Printf("%v is not mapped, please see the infra team")
		sensuutil.Exit("CONFIGERROR")
	}

	// api := slack.New(slackToken)
	// // If you set debugging, it will log all requests to the console
	// // Useful when encountering issues
	// // api.SetDebug(true)
	// groups, err := api.GetChannelInfo(channelID)
	// if err != nil {
	// 	fmt.Printf("%s\n", err)
	// 	return
	// }
	// fmt.Printf("%v", groups)

	api := slack.New(slackToken)
	params := slack.PostMessageParameters{}
	attachment := slack.Attachment{
		Color: setColor(sensuEvent.Check.Status),

		Fields: []slack.AttachmentField{
			slack.AttachmentField{
				Title: "Monitored Instance",
				Value: sensuEvent.AcquireMonitoredInstance(),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Sensu Client",
				Value: sensuEvent.Client.Name,
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check Name",
				Value: sensuhandler.CreateCheckName(sensuEvent.Check.Name),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check State",
				Value: sensuhandler.DefineStatus(sensuEvent.Check.Status),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Event Time",
				Value: time.Unix(sensuEvent.Check.Issued, 0).Format(time.RFC3339),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check State Duration",
				Value: strconv.Itoa(sensuhandler.DefineCheckStateDuration()),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check Output",
				Value: cleanOutput(sensuEvent.Check.Output),
				Short: true,
			},
		},
	}
	params.Attachments = []slack.Attachment{attachment}
	channelID, timestamp, err := api.PostMessage(channelID, "", params)
	if err != nil {
		sensuutil.EHndlr(err)
	}
	fmt.Printf("Message successfully sent to channel %s at %s", channelID, timestamp)
}
<commit_msg>working on channelid issue<commit_after>// Take well-formed json from either stdin or an input file and create an attachment notification for Slack
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"flag"
	"fmt"
	"github.com/nlopes/slack"
	"github.com/yieldbot/sensuplugin/sensuhandler"
	"github.com/yieldbot/sensuplugin/sensuutil"
	//"github.com/yieldbot/sensuslack/lib"
	"strconv"
	"strings"
	"time"
)

func setColor(status int) string {
	switch status {
	case 0:
		return "#33CC33"
	case 1:
		return "warning"
	case 2:
		return "#FF0000"
	case 3:
		return "#FF6600"
	default:
		return "#FF6600"
	}
}

func cleanOutput(output string) string {
	return strings.Split(output, ":")[0]
}

func main() {

	slackTokenPtr := flag.String("token", "", "the slack integration token")
	channelPtr := flag.String("channel", "monitoring-test", "the channel to post notifications to")

	flag.Parse()

	slackToken := *slackTokenPtr
	channelName := *channelPtr
	channelID := "C09JY7W0P"

	sensuEvent := new(sensuhandler.SensuEvent)
	sensuEvent = sensuEvent.AcquireSensuEvent()

	// YELLOW
	// this is ugly, needs to be a better way to do this
	if slackToken == "" {
		fmt.Print("Please enter a slack integration token")
		sensuutil.Exit("CONFIGERROR")
	}

	fmt.Printf(channelName)

	// for k, v := range lib.SlackChannels {
	// 	if channelName == k {
	// 		channelID = v
	// 	}
	// }

	// if channelID == "000000" {
	// 	fmt.Printf("%v is not mapped, please see the infra team")
	// 	sensuutil.Exit("CONFIGERROR")
	// }

	// api := slack.New(slackToken)
	// // If you set debugging, it will log all requests to the console
	// // Useful when encountering issues
	// // api.SetDebug(true)
	// groups, err := api.GetChannelInfo(channelID)
	// if err != nil {
	// 	fmt.Printf("%s\n", err)
	// 	return
	// }
	// fmt.Printf("%v", groups)

	api := slack.New(slackToken)
	params := slack.PostMessageParameters{}
	attachment := slack.Attachment{
		Color: setColor(sensuEvent.Check.Status),

		Fields: []slack.AttachmentField{
			slack.AttachmentField{
				Title: "Monitored Instance",
				Value: sensuEvent.AcquireMonitoredInstance(),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Sensu Client",
				Value: sensuEvent.Client.Name,
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check Name",
				Value: sensuhandler.CreateCheckName(sensuEvent.Check.Name),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check State",
				Value: sensuhandler.DefineStatus(sensuEvent.Check.Status),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Event Time",
				Value: time.Unix(sensuEvent.Check.Issued, 0).Format(time.RFC3339),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check State Duration",
				Value: strconv.Itoa(sensuhandler.DefineCheckStateDuration()),
				Short: true,
			},
			slack.AttachmentField{
				Title: "Check Output",
				Value: cleanOutput(sensuEvent.Check.Output),
				Short: true,
			},
		},
	}
	params.Attachments = []slack.Attachment{attachment}
	channelID, timestamp, err := api.PostMessage(channelID, "", params)
	if err != nil {
		sensuutil.EHndlr(err)
	}
	fmt.Printf("Message successfully sent to channel %s at %s", channelID, timestamp)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/fsouza/go-dockerclient"

	"go.pedge.io/env"
	"go.pedge.io/proto/server"

	"go.pachyderm.com/pachyderm"
	"go.pachyderm.com/pachyderm/src/pfs"
	"go.pachyderm.com/pachyderm/src/pkg/container"
	"go.pachyderm.com/pachyderm/src/pps"
	"go.pachyderm.com/pachyderm/src/pps/jobserver"
	"go.pachyderm.com/pachyderm/src/pps/persist"
	persistserver "go.pachyderm.com/pachyderm/src/pps/persist/server"
	"go.pachyderm.com/pachyderm/src/pps/pipelineserver"
	"google.golang.org/grpc"
)

var (
	defaultEnv = map[string]string{
		"PPS_ADDRESS":       "0.0.0.0",
		"PPS_PORT":          "651",
		"PPS_TRACE_PORT":    "1051",
		"PPS_DATABASE_NAME": "pachyderm",
	}
)

type appEnv struct {
	PachydermPfsd1Port string `env:"PACHYDERM_PFSD_1_PORT"`
	PfsAddress         string `env:"PFS_ADDRESS"`
	Address            string `env:"PPS_ADDRESS"`
	Port               int    `env:"PPS_PORT"`
	DatabaseAddress    string `env:"PPS_DATABASE_ADDRESS"`
	DatabaseName       string `env:"PPS_DATABASE_NAME"`
	DebugPort          int    `env:"PPS_TRACE_PORT"`
}

func main() {
	env.Main(do, &appEnv{}, defaultEnv)
}

func do(appEnvObj interface{}) error {
	appEnv := appEnvObj.(*appEnv)
	containerClient, err := getContainerClient()
	if err != nil {
		return err
	}
	rethinkAPIClient, err := getRethinkAPIClient(appEnv.DatabaseAddress, appEnv.DatabaseName)
	if err != nil {
		return err
	}
	pfsAddress := appEnv.PachydermPfsd1Port
	if pfsAddress == "" {
		pfsAddress = appEnv.PfsAddress
	} else {
		pfsAddress = strings.Replace(pfsAddress, "tcp://", "", -1)
	}
	clientConn, err := grpc.Dial(pfsAddress, grpc.WithInsecure())
	if err != nil {
		return err
	}
	jobAPIServer := jobserver.NewAPIServer(rethinkAPIClient, containerClient)
	jobAPIClient := pps.NewLocalJobAPIClient(jobAPIServer)
	pfsAPIClient := pfs.NewAPIClient(clientConn)
	pipelineAPIServer := pipelineserver.NewAPIServer(pfsAPIClient, jobAPIClient, rethinkAPIClient)
	return protoserver.Serve(
		uint16(appEnv.Port),
		func(s *grpc.Server) {
			pps.RegisterJobAPIServer(s, jobAPIServer)
			pps.RegisterPipelineAPIServer(s, pipelineAPIServer)
		},
		protoserver.ServeOptions{
			DebugPort: uint16(appEnv.DebugPort),
			Version:   pachyderm.Version,
		},
	)
}

func getContainerClient() (container.Client, error) {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return nil, err
	}
	return container.NewDockerClient(client), nil
}

func getRethinkAPIClient(address string, databaseName string) (persist.APIClient, error) {
	var err error
	if address == "" {
		address, err = getRethinkAddress()
		if err != nil {
			return nil, err
		}
	}
	if err := persistserver.InitDBs(address, databaseName); err != nil {
		return nil, err
	}
	rethinkAPIServer, err := persistserver.NewRethinkAPIServer(address, databaseName)
	if err != nil {
		return nil, err
	}
	return persist.NewLocalAPIClient(rethinkAPIServer), nil
}

func getRethinkAddress() (string, error) {
	rethinkAddr := os.Getenv("RETHINK_PORT_28015_TCP_ADDR")
	if rethinkAddr == "" {
		return "", errors.New("RETHINK_PORT_28015_TCP_ADDR not set")
	}
	return fmt.Sprintf("%s:28015", rethinkAddr), nil
}
<commit_msg>call pps pipeline api server start in ppsd binary<commit_after>package main

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

	"github.com/fsouza/go-dockerclient"

	"go.pedge.io/env"
	"go.pedge.io/proto/server"

	"go.pachyderm.com/pachyderm"
	"go.pachyderm.com/pachyderm/src/pfs"
	"go.pachyderm.com/pachyderm/src/pkg/container"
	"go.pachyderm.com/pachyderm/src/pps"
	"go.pachyderm.com/pachyderm/src/pps/jobserver"
	"go.pachyderm.com/pachyderm/src/pps/persist"
	persistserver "go.pachyderm.com/pachyderm/src/pps/persist/server"
	"go.pachyderm.com/pachyderm/src/pps/pipelineserver"
	"google.golang.org/grpc"
)

var (
	defaultEnv = map[string]string{
		"PPS_ADDRESS":       "0.0.0.0",
		"PPS_PORT":          "651",
		"PPS_TRACE_PORT":    "1051",
		"PPS_DATABASE_NAME": "pachyderm",
	}
)

type appEnv struct {
	PachydermPfsd1Port string `env:"PACHYDERM_PFSD_1_PORT"`
	PfsAddress         string `env:"PFS_ADDRESS"`
	Address            string `env:"PPS_ADDRESS"`
	Port               int    `env:"PPS_PORT"`
	DatabaseAddress    string `env:"PPS_DATABASE_ADDRESS"`
	DatabaseName       string `env:"PPS_DATABASE_NAME"`
	DebugPort          int    `env:"PPS_TRACE_PORT"`
}

func main() {
	env.Main(do, &appEnv{}, defaultEnv)
}

func do(appEnvObj interface{}) error {
	appEnv := appEnvObj.(*appEnv)
	containerClient, err := getContainerClient()
	if err != nil {
		return err
	}
	rethinkAPIClient, err := getRethinkAPIClient(appEnv.DatabaseAddress, appEnv.DatabaseName)
	if err != nil {
		return err
	}
	pfsAddress := appEnv.PachydermPfsd1Port
	if pfsAddress == "" {
		pfsAddress = appEnv.PfsAddress
	} else {
		pfsAddress = strings.Replace(pfsAddress, "tcp://", "", -1)
	}
	clientConn, err := grpc.Dial(pfsAddress, grpc.WithInsecure())
	if err != nil {
		return err
	}
	jobAPIServer := jobserver.NewAPIServer(rethinkAPIClient, containerClient)
	jobAPIClient := pps.NewLocalJobAPIClient(jobAPIServer)
	pfsAPIClient := pfs.NewAPIClient(clientConn)
	pipelineAPIServer := pipelineserver.NewAPIServer(pfsAPIClient, jobAPIClient, rethinkAPIClient)
	errC := make(chan error)
	go func() {
		errC <- protoserver.Serve(
			uint16(appEnv.Port),
			func(s *grpc.Server) {
				pps.RegisterJobAPIServer(s, jobAPIServer)
				pps.RegisterPipelineAPIServer(s, pipelineAPIServer)
			},
			protoserver.ServeOptions{
				DebugPort: uint16(appEnv.DebugPort),
				Version:   pachyderm.Version,
			},
		)
	}()
	// TODO(pedge): pretty sure I had this problem before, this is bad, we would
	// prefer a callback for when the server is ready to accept requests
	time.Sleep(1 * time.Second)
	if err := pipelineAPIServer.Start(); err != nil {
		return err
	}
	return <-errC
}

func getContainerClient() (container.Client, error) {
	client, err := docker.NewClientFromEnv()
	if err != nil {
		return nil, err
	}
	return container.NewDockerClient(client), nil
}

func getRethinkAPIClient(address string, databaseName string) (persist.APIClient, error) {
	var err error
	if address == "" {
		address, err = getRethinkAddress()
		if err != nil {
			return nil, err
		}
	}
	if err := persistserver.InitDBs(address, databaseName); err != nil {
		return nil, err
	}
	rethinkAPIServer, err := persistserver.NewRethinkAPIServer(address, databaseName)
	if err != nil {
		return nil, err
	}
	return persist.NewLocalAPIClient(rethinkAPIServer), nil
}

func getRethinkAddress() (string, error) {
	rethinkAddr := os.Getenv("RETHINK_PORT_28015_TCP_ADDR")
	if rethinkAddr == "" {
		return "", errors.New("RETHINK_PORT_28015_TCP_ADDR not set")
	}
	return fmt.Sprintf("%s:28015", rethinkAddr), nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/yml/nsqthumbnailer"
)

var (
	addr     = flag.String("addr", "127.0.0.1:9900", "http addr (default is 127.0.0.1:9900)")
	URLNames = make(map[string]string)
)

func thumbsHandler(w http.ResponseWriter, r *http.Request) {
	var thumbReq bytes.Buffer
	if r.Method == "GET" {
		// In this case we are going to look for the thumbReq in the URL.
		// It should be base 64 encoded
		path := strings.TrimPrefix(r.URL.Path, URLNames["/thumb/"])
		_, err := io.Copy(&thumbReq, base64.NewDecoder(base64.URLEncoding, strings.NewReader(path)))
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to decode the thumb generation request: %s", err), http.StatusBadRequest)
			return
		}
	} else if r.Method == "POST" {
		// Grab the JSON representation of thumbReq directly from the r.Body
		_, err := io.Copy(&thumbReq, r.Body)
		defer r.Body.Close()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to decode the thumb generation request: %s", err), http.StatusBadRequest)
			return
		}
	} else {
		http.Error(w, fmt.Sprintf("Request method not supported: %s", r.Method), http.StatusBadRequest)
		return
	}
	fmt.Printf("thumbReq: %s\n", thumbReq.String())

	tm := nsqthumbnailer.ThumbnailerMessage{}
	err := json.Unmarshal(thumbReq.Bytes(), &tm)
	if err != nil {
		err = errors.New(fmt.Sprintf("ERROR: failed to unmarshal `thumbReq` into a thumbnailerMessage - %s", err))
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	resultChan := make(chan nsqthumbnailer.ThumbnailResult)
	go tm.GenerateThumbnails(resultChan)

	results := make([]nsqthumbnailer.ThumbnailResult, 0)
	for i := 0; i < len(tm.Opts); i++ {
		result := <-resultChan
		results = append(results, result)
	}
	for _, r := range results {
		if r.Err != nil {
			err := fmt.Errorf("Error: At least one thumb generation failed - %s", r.Err, results)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}

	if tm.DeleteSrc == true {
		fmt.Println("Deleting", tm.SrcImage)
		err = tm.DeleteImage()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}

	body, err := json.Marshal(results)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	w.Write(body)
	return
}

func main() {
	flag.Parse()
	fmt.Println("Starting HTTP thumbnailer on: ", *addr)
	URLNames["/"] = "/"
	URLNames["/thumbs/"] = "/thumbs/"
	URLNames["/debug/"] = "/debug/"

	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("This is the home page"))
	})
	mux.HandleFunc(URLNames["/debug/"], func(w http.ResponseWriter, r *http.Request) {
		thumbReq := []byte("{\"srcImage\": \"file:///home/yml/Dropbox/Devs/golang/nsq_sandbox/nsq-thumb-src-test/baignade.jpg\", \"opts\": [{\"rect\":{\"min\":[200, 200], \"max\":[600,600]},\"width\":150, \"height\":0}], \"dstFolder\":\"file:///home/yml/Dropbox/Devs/golang/nsq_sandbox/nsq-thumb-dst-test/\"}")
		fmt.Printf("thumbReq : %s\n", thumbReq)
		w.Write([]byte("\n"))
		enc := base64.NewEncoder(base64.URLEncoding, w)
		enc.Write(thumbReq)
		enc.Close()
		w.Write([]byte("\n\n"))
	})
	mux.HandleFunc(URLNames["/thumbs/"], thumbsHandler)
	http.ListenAndServe(*addr, mux)

}
<commit_msg>Intermediate commit to add /thumb/ end point<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/yml/nsqthumbnailer"
)

var (
	addr      = flag.String("addr", "127.0.0.1:9900", "http addr (default is 127.0.0.1:9900)")
	srcFolder = flag.String("srcFolder", "", "Source folder including the scheme (file:///tmp/my.jpg)")
	dstFolder = flag.String("dstFolder", "", "Destination folder including the scheme (file:///tmp/my.jpg)")
	URLNames  = make(map[string]string)
)

func thumbHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		var width, height int
		var filename string
		path := strings.TrimPrefix(r.URL.Path, URLNames["/thumb/"])
		fmt.Sscanf(path, "%dx%d/%s", &width, &height, &filename)
		fmt.Printf("[DEBUG] width: %d , height: %d, filename: %s ", width, height, filename)
		// build the thumbReg and generate the thumb and return it or redirect

	} else {
		http.Error(w, fmt.Sprintf("Request method not supported: %s", r.Method), http.StatusBadRequest)
		return
	}

}

func thumbsHandler(w http.ResponseWriter, r *http.Request) {
	var thumbReq bytes.Buffer
	if r.Method == "GET" {
		// In this case we are going to look for the thumbReq in the URL.
		// It should be base 64 encoded
		path := strings.TrimPrefix(r.URL.Path, URLNames["/thumbs/"])
		_, err := io.Copy(&thumbReq, base64.NewDecoder(base64.URLEncoding, strings.NewReader(path)))
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to decode the thumb generation request: %s", err), http.StatusBadRequest)
			return
		}
	} else if r.Method == "POST" {
		// Grab the JSON representation of thumbReq directly from the r.Body
		_, err := io.Copy(&thumbReq, r.Body)
		defer r.Body.Close()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to decode the thumb generation request: %s", err), http.StatusBadRequest)
			return
		}
	} else {
		http.Error(w, fmt.Sprintf("Request method not supported: %s", r.Method), http.StatusBadRequest)
		return
	}
	fmt.Printf("thumbReq: %s\n", thumbReq.String())

	tm := nsqthumbnailer.ThumbnailerMessage{}
	err := json.Unmarshal(thumbReq.Bytes(), &tm)
	if err != nil {
		err = errors.New(fmt.Sprintf("ERROR: failed to unmarshal `thumbReq` into a thumbnailerMessage - %s", err))
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	resultChan := make(chan nsqthumbnailer.ThumbnailResult)
	go tm.GenerateThumbnails(resultChan)

	results := make([]nsqthumbnailer.ThumbnailResult, 0)
	for i := 0; i < len(tm.Opts); i++ {
		result := <-resultChan
		results = append(results, result)
	}
	for _, r := range results {
		if r.Err != nil {
			err := fmt.Errorf("Error: At least one thumb generation failed - %s", r.Err, results)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}

	if tm.DeleteSrc == true {
		fmt.Println("Deleting", tm.SrcImage)
		err = tm.DeleteImage()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}

	body, err := json.Marshal(results)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	w.Write(body)
	return
}

func main() {
	flag.Parse()
	fmt.Println("Starting HTTP thumbnailer on: ", *addr)
	URLNames["/"] = "/"
	URLNames["/thumbs/"] = "/thumbs/"
	URLNames["/thumb/"] = "/thumb/"
	URLNames["/base64Encode/"] = "/debug_base64Encode/"

	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("This is the home page"))
	})
	mux.HandleFunc(URLNames["/base64Encode/"], func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			thumbReq, err := ioutil.ReadAll(r.Body)
			defer r.Body.Close()

			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
			}

			w.Write([]byte("\n"))
			enc := base64.NewEncoder(base64.URLEncoding, w)
			enc.Write(thumbReq)
			enc.Close()
			w.Write([]byte("\n"))
		} else {
			http.Error(w, "This request.Method is not implemented for this endpoint", http.StatusInternalServerError)
		}
	})
	mux.HandleFunc(URLNames["/thumbs/"], thumbsHandler)
	mux.HandleFunc(URLNames["/thumb/"], thumbHandler)
	http.ListenAndServe(*addr, mux)

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"path/filepath"
	"sort"

	"github.com/kopia/kopia/internal/units"
	"github.com/kopia/kopia/snapshot"
	"github.com/kopia/kopia/vault"

	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	backupsCommand    = app.Command("backups", "List history of file or directory backups.")
	backupsPath       = backupsCommand.Arg("source", "File or directory to show history of.").String()
	maxResultsPerPath = backupsCommand.Flag("maxresults", "Maximum number of results.").Default("100").Int()
)

func findBackups(vlt *vault.Vault, sourceInfo snapshot.SourceInfo) ([]string, string, error) {
	var relPath string

	for len(sourceInfo.Path) > 0 {
		prefix := sourceInfo.HashString() + "."

		list, err := vlt.List("B" + prefix)
		if err != nil {
			return nil, "", err
		}

		if len(list) > 0 {
			return list, relPath, nil
		}

		if len(relPath) > 0 {
			relPath = filepath.Base(sourceInfo.Path) + "/" + relPath
		} else {
			relPath = filepath.Base(sourceInfo.Path)
		}

		log.Printf("No backups of %v@%v:%v", sourceInfo.UserName, sourceInfo.Host, sourceInfo.Path)

		parentPath := filepath.Dir(sourceInfo.Path)
		if parentPath == sourceInfo.Path {
			break
		}
		sourceInfo.Path = parentPath
	}

	return nil, "", nil
}

func runBackupsCommand(context *kingpin.ParseContext) error {
	conn := mustOpenConnection()
	defer conn.Close()

	mgr := snapshot.NewManager(conn)

	var previous []string
	var relPath string
	var err error

	if *backupsPath != "" {
		si, err := snapshot.ParseSourceInfo(*backupsPath, getHostName(), getUserName())
		if err != nil {
			return fmt.Errorf("invalid directory: '%s': %s", *backupsPath, err)
		}

		previous, relPath, err = findBackups(conn.Vault, si)
		if relPath != "" {
			relPath = "/" + relPath
		}
	} else {
		previous, err = conn.Vault.List("B")
	}

	if err != nil {
		return fmt.Errorf("cannot list backups: %v", err)
	}

	var lastSource snapshot.SourceInfo
	var count int

	manifests, err := mgr.LoadSnapshots(previous)
	if err != nil {
		return err
	}
	sort.Sort(manifestSorter(manifests))

	for _, m := range manifests {
		if m.Source != lastSource {
			fmt.Printf("\n%v\n", m.Source)
			lastSource = m.Source
			count = 0
		}

		if count < *maxResultsPerPath {
			fmt.Printf(
				"  %v%v %v %10v %v\n",
				m.Handle,
				relPath,
				m.StartTime.Format("2006-01-02 15:04:05 MST"),
				units.BytesString(m.Stats.TotalFileSize),
				deltaBytes(m.Stats.Repository.WrittenBytes),
			)
			count++
		}
	}

	return nil
}

type manifestSorter []*snapshot.Manifest

func (b manifestSorter) Len() int { return len(b) }
func (b manifestSorter) Less(i, j int) bool {
	if b[i].Source.String() < b[j].Source.String() {
		return true
	}
	if b[i].Source.String() > b[j].Source.String() {
		return false
	}

	return b[i].StartTime.UnixNano() < b[j].StartTime.UnixNano()
}

func (b manifestSorter) Swap(i, j int) { b[i], b[j] = b[j], b[i] }

func deltaBytes(b int64) string {
	if b > 0 {
		return "(+" + units.BytesString(b) + ")"
	}

	return "(no change)"
}

func init() {
	backupsCommand.Action(runBackupsCommand)
}
<commit_msg>minor readability tweak<commit_after>package main

import (
	"fmt"
	"log"
	"path/filepath"
	"sort"

	"github.com/kopia/kopia/internal/units"
	"github.com/kopia/kopia/snapshot"
	"github.com/kopia/kopia/vault"

	"strings"

	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	backupsCommand    = app.Command("backups", "List history of file or directory backups.")
	backupsPath       = backupsCommand.Arg("source", "File or directory to show history of.").String()
	maxResultsPerPath = backupsCommand.Flag("maxresults", "Maximum number of results.").Default("100").Int()
)

func findBackups(vlt *vault.Vault, sourceInfo snapshot.SourceInfo) ([]string, string, error) {
	var relPath string

	for len(sourceInfo.Path) > 0 {
		prefix := sourceInfo.HashString() + "."

		list, err := vlt.List("B" + prefix)
		if err != nil {
			return nil, "", err
		}

		if len(list) > 0 {
			return list, relPath, nil
		}

		if len(relPath) > 0 {
			relPath = filepath.Base(sourceInfo.Path) + "/" + relPath
		} else {
			relPath = filepath.Base(sourceInfo.Path)
		}

		log.Printf("No backups of %v@%v:%v", sourceInfo.UserName, sourceInfo.Host, sourceInfo.Path)

		parentPath := filepath.Dir(sourceInfo.Path)
		if parentPath == sourceInfo.Path {
			break
		}
		sourceInfo.Path = parentPath
	}

	return nil, "", nil
}

func runBackupsCommand(context *kingpin.ParseContext) error {
	conn := mustOpenConnection()
	defer conn.Close()

	mgr := snapshot.NewManager(conn)

	var previous []string
	var relPath string
	var err error

	if *backupsPath != "" {
		si, err := snapshot.ParseSourceInfo(*backupsPath, getHostName(), getUserName())
		if err != nil {
			return fmt.Errorf("invalid directory: '%s': %s", *backupsPath, err)
		}

		previous, relPath, err = findBackups(conn.Vault, si)
		if relPath != "" {
			relPath = "/" + relPath
		}
	} else {
		previous, err = conn.Vault.List("B")
	}

	if err != nil {
		return fmt.Errorf("cannot list backups: %v", err)
	}

	var lastSource snapshot.SourceInfo
	var count int

	manifests, err := mgr.LoadSnapshots(previous)
	if err != nil {
		return err
	}
	sort.Sort(manifestSorter(manifests))

	for _, m := range manifests {
		if m.Source != lastSource {
			fmt.Printf("\n%v\n", m.Source)
			lastSource = m.Source
			count = 0
		}

		if count < *maxResultsPerPath {
			fmt.Printf(
				"  %v%v %v %10v %v\n",
				m.Handle,
				relPath,
				m.StartTime.Format("2006-01-02 15:04:05 MST"),
				units.BytesString(m.Stats.TotalFileSize),
				deltaBytes(m.Stats.Repository.WrittenBytes),
			)
			count++
		}
	}

	return nil
}

type manifestSorter []*snapshot.Manifest

func (b manifestSorter) Len() int { return len(b) }
func (b manifestSorter) Less(i, j int) bool {
	if c := strings.Compare(b[i].Source.String(), b[j].Source.String()); c != 0 {
		return c < 0
	}

	return b[i].StartTime.UnixNano() < b[j].StartTime.UnixNano()
}

func (b manifestSorter) Swap(i, j int) { b[i], b[j] = b[j], b[i] }

func deltaBytes(b int64) string {
	if b > 0 {
		return "(+" + units.BytesString(b) + ")"
	}

	return "(no change)"
}

func init() {
	backupsCommand.Action(runBackupsCommand)
}
<|endoftext|>


<commit_before>package commands

import (
	"config"
	"connectordb"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"

	"util"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"
)

var (
	// The git hash/buildstamp is inserted into the build during link time
	// http://www.atatus.com/blog/golang-auto-build-versioning/
	GitHash    = ""
	BuildStamp = ""

	// ErrConfig is shown when a configuration is expected for ConnectorDB
	ErrConfig      = errors.New("You must specify a database directory or config file")
	ErrTooManyArgs = errors.New("Too many arguments were specified.")

	loglevel   string
	logfile    string
	cpuprofile string
	version    bool
)

// RootCmd is the root command under which all other commands are placed.
// It is used to initialize all ariables that are global for the whole app
var RootCmd = &cobra.Command{
	Use:   "connectordb",
	Short: "ConnectorDB is a repository for your quantified-self and IoT data",
	Long:  `ConnectorDB is a database built for interacting with your IoT devices and for storing your quantified-self data.`,

	Run: func(cmd *cobra.Command, args []string) {
		if version {
			fmt.Printf("ConnectorDB v%s\n\narch: %s/%s\ngo: %s\ngit: %s\nbuild: %s\n", connectordb.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), GitHash, BuildStamp)
		} else {
			cmd.HelpFunc()(cmd, args)
		}
	},

	// Set up logging and profiling - everything that is needed for all runs of ConnectorDB
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {

		// We start by initializing logging using defaults.
		// It will be overwritten if config-based later.
		setLogging(nil)

		//Set up CPU profiling if it is enabled
		if cpuprofile != "" {
			log.Info("Writing CPU profile to ", cpuprofile)

			cpufile, err := os.Create(cpuprofile)
			if err != nil {
				return err
			}

			pprof.StartCPUProfile(cpufile)

			//Now, the program will be closed in some way, which might be hard to catch. We use
			//close on exit to shut down the CPU profile.
			// TODO: CloseOnExit only is called on sigint/sigterm. It isn't called
			// on normal exit.
			util.CloseOnExit(util.CloseCall{Callme: func() {
				log.Infof("Writing CPU profile %s...", cpuprofile)
				pprof.StopCPUProfile()
				cpufile.Close()
				log.Info("Finished writing CPU profile.")
			}})

		}

		return nil
	},
}

// setLogging sets up logging using an optional configuration
func setLogging(c *config.Configuration) (err error) {
	if c == nil {
		// Use default config's logging values
		c = config.NewConfiguration()
	}
	if logfile != "" {
		c.LogFile, err = filepath.Abs(logfile)
		if err != nil {
			return err
		}
	}
	if loglevel != "" {
		c.LogLevel = loglevel
	}
	return config.SetLoggingFromConfig(c)
}

func init() {

	RootCmd.PersistentFlags().StringVar(&logfile, "logfile", "", "The file to which log output is written")
	RootCmd.PersistentFlags().StringVarP(&loglevel, "loglevel", "l", "", "The types of messages to show (debug,info,warn,error)")
	RootCmd.PersistentFlags().StringVar(&cpuprofile, "cpuprofile", "", "File to which a cpu profile of ConnectorDB will be written")

	RootCmd.Flags().BoolVar(&version, "version", false, "Show ConnectorDB version and exit")
}
<commit_msg>Added semver<commit_after>package commands

import (
	"config"
	"connectordb"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"

	"util"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"
)

var (
	// The git hash/buildstamp is inserted into the build during link time
	// http://www.atatus.com/blog/golang-auto-build-versioning/
	GitHash    = ""
	BuildStamp = ""

	// ErrConfig is shown when a configuration is expected for ConnectorDB
	ErrConfig      = errors.New("You must specify a database directory or config file")
	ErrTooManyArgs = errors.New("Too many arguments were specified.")

	loglevel   string
	logfile    string
	cpuprofile string
	version    bool
	semver     bool
)

// RootCmd is the root command under which all other commands are placed.
// It is used to initialize all ariables that are global for the whole app
var RootCmd = &cobra.Command{
	Use:   "connectordb",
	Short: "ConnectorDB is a repository for your quantified-self and IoT data",
	Long:  `ConnectorDB is a database built for interacting with your IoT devices and for storing your quantified-self data.`,

	Run: func(cmd *cobra.Command, args []string) {
		if semver {
			fmt.Printf("%s\n", connectordb.Version)
		} else if version {
			fmt.Printf("ConnectorDB v%s\n\narch: %s/%s\ngo: %s\ngit: %s\nbuild: %s\n", connectordb.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), GitHash, BuildStamp)
		} else {
			cmd.HelpFunc()(cmd, args)
		}
	},

	// Set up logging and profiling - everything that is needed for all runs of ConnectorDB
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {

		// We start by initializing logging using defaults.
		// It will be overwritten if config-based later.
		setLogging(nil)

		//Set up CPU profiling if it is enabled
		if cpuprofile != "" {
			log.Info("Writing CPU profile to ", cpuprofile)

			cpufile, err := os.Create(cpuprofile)
			if err != nil {
				return err
			}

			pprof.StartCPUProfile(cpufile)

			//Now, the program will be closed in some way, which might be hard to catch. We use
			//close on exit to shut down the CPU profile.
			// TODO: CloseOnExit only is called on sigint/sigterm. It isn't called
			// on normal exit.
			util.CloseOnExit(util.CloseCall{Callme: func() {
				log.Infof("Writing CPU profile %s...", cpuprofile)
				pprof.StopCPUProfile()
				cpufile.Close()
				log.Info("Finished writing CPU profile.")
			}})

		}

		return nil
	},
}

// setLogging sets up logging using an optional configuration
func setLogging(c *config.Configuration) (err error) {
	if c == nil {
		// Use default config's logging values
		c = config.NewConfiguration()
	}
	if logfile != "" {
		c.LogFile, err = filepath.Abs(logfile)
		if err != nil {
			return err
		}
	}
	if loglevel != "" {
		c.LogLevel = loglevel
	}
	return config.SetLoggingFromConfig(c)
}

func init() {

	RootCmd.PersistentFlags().StringVar(&logfile, "logfile", "", "The file to which log output is written")
	RootCmd.PersistentFlags().StringVarP(&loglevel, "loglevel", "l", "", "The types of messages to show (debug,info,warn,error)")
	RootCmd.PersistentFlags().StringVar(&cpuprofile, "cpuprofile", "", "File to which a cpu profile of ConnectorDB will be written")

	RootCmd.Flags().BoolVar(&version, "version", false, "Show detailed ConnectorDB version and exit")
	RootCmd.Flags().BoolVar(&semver, "semver", false, "Show just ConnectorDB version number")
}
<|endoftext|>


<commit_before>package main // import "honnef.co/go/tools/cmd/stylecheck"
import (
	"os"

	"honnef.co/go/tools/lint/lintutil"
	"honnef.co/go/tools/stylecheck"
)

func main() {
	fs := lintutil.FlagSet("stylecheck")
	gen := fs.Bool("generated", false, "Check generated code")
	fs.Parse(os.Args[1:])
	c := stylecheck.NewChecker()
	c.CheckGenerated = *gen
	cfg := lintutil.CheckerConfig{
		Checker:     c,
		ExitNonZero: true,
	}
	lintutil.ProcessFlagSet([]lintutil.CheckerConfig{cfg}, fs)
}
<commit_msg>cmd/stylecheck: delete<commit_after><|endoftext|>


<commit_before>// Copyright 2015 Red Hat, 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 salt

import (
	"bytes"
	"github.com/sbinet/go-python"
	"github.com/skyrings/skyring/backend"
	"github.com/skyrings/skyring/monitoring"
	"github.com/skyrings/skyring/tools/gopy"
	"github.com/skyrings/skyring/tools/logger"
	"github.com/skyrings/skyring/tools/ssh"
	"github.com/skyrings/skyring/tools/uuid"
	"strings"
	"sync"
	"text/template"
)

var funcNames = [...]string{
	"AcceptNode",
	"GetNodes",
	"GetNodeID",
	"GetNodeNetwork",
	"GetNodeDisk",
	"IgnoreNode",
	"DisableService",
	"EnableService",
	"NodeUp",
	"AddMonitoringPlugin",
	"UpdateMonitoringConfiguration",
	"EnableMonitoringPlugin",
	"DisableMonitoringPlugin",
	"RemoveMonitoringPlugin",
}

var pyFuncs map[string]*gopy.PyFunction

var mutex sync.Mutex

func init() {
	var err error
	if pyFuncs, err = gopy.Import("skyring.saltwrapper", funcNames[:]...); err != nil {
		panic(err)
	}
}

type Salt struct {
}

func (s Salt) AddNode(master string, node string, port uint, fingerprint string, username string, password string) (status bool, err error) {
	if finger, err := s.BootstrapNode(master, node, port, fingerprint, username, password); err == nil {
		status, err = s.AcceptNode(node, finger, false)
	}
	return
}

func (s Salt) AcceptNode(node string, fingerprint string, ignored bool) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["AcceptNode"].Call(node, fingerprint, ignored); err == nil {
		err = gopy.Convert(pyobj, &status)
	}
	return
}

func (s Salt) UpdateMonitoringConfiguration(nodes []string, config []monitoring.Plugin) (failed_nodes []string, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	var pyobj *python.PyObject
	if pyobj, err = pyFuncs["UpdateMonitoringConfiguration"].Call(nodes, monitoring.ToSaltPillarCompat(config)); err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	}
	return
}

func (s Salt) EnableMonitoringPlugin(nodes []string, pluginName string) (failed_nodes map[string]string, err error) {
	failed_nodes = make(map[string]string)
	mutex.Lock()
	defer mutex.Unlock()
	pyobj, err := pyFuncs["EnableMonitoringPlugin"].Call(nodes, pluginName)
	if err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	}
	return
}

func (s Salt) DisableMonitoringPlugin(nodes []string, pluginName string) (failed_nodes map[string]string, err error) {
	failed_nodes = make(map[string]string)
	mutex.Lock()
	defer mutex.Unlock()
	pyobj, err := pyFuncs["DisableMonitoringPlugin"].Call(nodes, pluginName)
	if err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	}
	return
}

func (s Salt) RemoveMonitoringPlugin(nodes []string, pluginName string) (failed_nodes map[string]string, err error) {
	failed_nodes = make(map[string]string)
	mutex.Lock()
	defer mutex.Unlock()
	pyobj, err := pyFuncs["RemoveMonitoringPlugin"].Call(nodes, pluginName)
	if err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	}
	return
}

func (s Salt) AddMonitoringPlugin(pluginNames []string, nodes []string, master string, pluginMap map[string]map[string]string) (failed_nodes map[string]interface{}, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	failed_nodes = make(map[string]interface{})
	pyobj, err := pyFuncs["AddMonitoringPlugin"].Call(pluginNames, nodes, master, pluginMap)
	if err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	}
	return
}

func (s Salt) BootstrapNode(master string, node string, port uint, fingerprint string, username string, password string) (finger string, err error) {
	var buf bytes.Buffer
	t, err := template.ParseFiles("/srv/salt/template/setup-node.sh.template")
	if err != nil {
		logger.Get().Critical("Error Parsing the setup-node.sh.template", err)
		return
	}
	if err = t.Execute(&buf, struct{ Master string }{Master: master}); err != nil {
		logger.Get().Critical("Error Executing the setup-node.sh.template", err)
		return
	}

	if sout, _, err := ssh.Run(buf.String(), node, port, fingerprint, username, password); err == nil {
		finger = strings.TrimSpace(sout)
	}
	return
}

func (s Salt) GetNodes() (nodes backend.NodeList, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["GetNodes"].Call(); err == nil {
		err = gopy.Convert(pyobj, &nodes)
	}
	return
}

func (s Salt) GetNodeID(node string) (id uuid.UUID, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["GetNodeID"].Call(node); err == nil {
		var s string
		if err = gopy.Convert(python.PyDict_GetItemString(pyobj, node), &s); err == nil {
			if i, err := uuid.Parse(s); err == nil {
				id = *i
			}
		}
	}
	return
}

func (s Salt) GetNodeDisk(node string) (disks []backend.Disk, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["GetNodeDisk"].Call(node); err == nil {
		err = gopy.Convert(python.PyDict_GetItemString(pyobj, node), &disks)
	}
	return
}

func (s Salt) GetNodeNetwork(node string) (n backend.Network, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["GetNodeNetwork"].Call(node); err == nil {
		err = gopy.Convert(python.PyDict_GetItemString(pyobj, node), &n)
	}
	return
}

func (s Salt) IgnoreNode(node string) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["IgnoreNode"].Call(node); err == nil {
		err = gopy.Convert(pyobj, &status)
	}
	return
}

func (s Salt) DisableService(node string, service string, stop bool) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["DisableService"].Call(node, service, stop); err == nil {
		err = gopy.Convert(pyobj, &status)
	}
	return
}

func (s Salt) EnableService(node string, service string, start bool) (status bool, error error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["EnableService"].Call(node, service, start); err == nil {
		err = gopy.Convert(pyobj, &status)
	}
	return
}

func (s Salt) NodeUp(node string) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, err := pyFuncs["NodeUp"].Call(node); err == nil {
		err = gopy.Convert(pyobj, &status)
	}
	return
}

func New() backend.Backend {
	return new(Salt)
}
<commit_msg>backend: Corrected to return errors properly from salt.go<commit_after>// Copyright 2015 Red Hat, 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 salt

import (
	"bytes"
	"github.com/sbinet/go-python"
	"github.com/skyrings/skyring/backend"
	"github.com/skyrings/skyring/monitoring"
	"github.com/skyrings/skyring/tools/gopy"
	"github.com/skyrings/skyring/tools/logger"
	"github.com/skyrings/skyring/tools/ssh"
	"github.com/skyrings/skyring/tools/uuid"
	"strings"
	"sync"
	"text/template"
)

var funcNames = [...]string{
	"AcceptNode",
	"GetNodes",
	"GetNodeID",
	"GetNodeNetwork",
	"GetNodeDisk",
	"IgnoreNode",
	"DisableService",
	"EnableService",
	"NodeUp",
	"AddMonitoringPlugin",
	"UpdateMonitoringConfiguration",
	"EnableMonitoringPlugin",
	"DisableMonitoringPlugin",
	"RemoveMonitoringPlugin",
}

var pyFuncs map[string]*gopy.PyFunction

var mutex sync.Mutex

func init() {
	var err error
	if pyFuncs, err = gopy.Import("skyring.saltwrapper", funcNames[:]...); err != nil {
		panic(err)
	}
}

type Salt struct {
}

func (s Salt) AddNode(master string, node string, port uint, fingerprint string, username string, password string) (status bool, err error) {
	if finger, loc_err := s.BootstrapNode(master, node, port, fingerprint, username, password); loc_err == nil {
		status, err = s.AcceptNode(node, finger, false)
	} else {
		status = false
		err = loc_err
	}
	return
}

func (s Salt) AcceptNode(node string, fingerprint string, ignored bool) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["AcceptNode"].Call(node, fingerprint, ignored); loc_err == nil {
		err = gopy.Convert(pyobj, &status)
	} else {
		status = false
		err = loc_err
	}
	return
}

func (s Salt) UpdateMonitoringConfiguration(nodes []string, config []monitoring.Plugin) (failed_nodes []string, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	var pyobj *python.PyObject
	if pyobj, err = pyFuncs["UpdateMonitoringConfiguration"].Call(nodes, monitoring.ToSaltPillarCompat(config)); err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	}
	return
}

func (s Salt) EnableMonitoringPlugin(nodes []string, pluginName string) (failed_nodes map[string]string, err error) {
	failed_nodes = make(map[string]string)
	mutex.Lock()
	defer mutex.Unlock()
	pyobj, loc_err := pyFuncs["EnableMonitoringPlugin"].Call(nodes, pluginName)
	if loc_err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) DisableMonitoringPlugin(nodes []string, pluginName string) (failed_nodes map[string]string, err error) {
	failed_nodes = make(map[string]string)
	mutex.Lock()
	defer mutex.Unlock()
	pyobj, loc_err := pyFuncs["DisableMonitoringPlugin"].Call(nodes, pluginName)
	if loc_err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) RemoveMonitoringPlugin(nodes []string, pluginName string) (failed_nodes map[string]string, err error) {
	failed_nodes = make(map[string]string)
	mutex.Lock()
	defer mutex.Unlock()
	pyobj, loc_err := pyFuncs["RemoveMonitoringPlugin"].Call(nodes, pluginName)
	if loc_err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) AddMonitoringPlugin(pluginNames []string, nodes []string, master string, pluginMap map[string]map[string]string) (failed_nodes map[string]interface{}, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	failed_nodes = make(map[string]interface{})
	pyobj, loc_err := pyFuncs["AddMonitoringPlugin"].Call(pluginNames, nodes, master, pluginMap)
	if loc_err == nil {
		err = gopy.Convert(pyobj, &failed_nodes)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) BootstrapNode(master string, node string, port uint, fingerprint string, username string, password string) (finger string, err error) {
	var buf bytes.Buffer
	t, loc_err := template.ParseFiles("/srv/salt/template/setup-node.sh.template")
	if loc_err != nil {
		logger.Get().Critical("Error Parsing the setup-node.sh.template", err)
		return "", loc_err
	}
	if loc_err = t.Execute(&buf, struct{ Master string }{Master: master}); err != nil {
		logger.Get().Critical("Error Executing the setup-node.sh.template", err)
		return "", loc_err
	}

	if sout, _, loc_err := ssh.Run(buf.String(), node, port, fingerprint, username, password); loc_err == nil {
		return strings.TrimSpace(sout), nil
	}
	return "", loc_err
}

func (s Salt) GetNodes() (nodes backend.NodeList, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["GetNodes"].Call(); loc_err == nil {
		err = gopy.Convert(pyobj, &nodes)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) GetNodeID(node string) (id uuid.UUID, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	pyobj, loc_err := pyFuncs["GetNodeID"].Call(node)
	if loc_err == nil {
		var s string
		loc_err = gopy.Convert(python.PyDict_GetItemString(pyobj, node), &s)
		if loc_err == nil {
			if i, loc_err := uuid.Parse(s); loc_err == nil {
				return *i, nil
			}
		}
	}
	return uuid.UUID{}, loc_err
}

func (s Salt) GetNodeDisk(node string) (disks []backend.Disk, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["GetNodeDisk"].Call(node); loc_err == nil {
		err = gopy.Convert(python.PyDict_GetItemString(pyobj, node), &disks)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) GetNodeNetwork(node string) (n backend.Network, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["GetNodeNetwork"].Call(node); loc_err == nil {
		err = gopy.Convert(python.PyDict_GetItemString(pyobj, node), &n)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) IgnoreNode(node string) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["IgnoreNode"].Call(node); loc_err == nil {
		err = gopy.Convert(pyobj, &status)
	} else {
		err = loc_err
	}
	return
}

func (s Salt) DisableService(node string, service string, stop bool) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["DisableService"].Call(node, service, stop); loc_err == nil {
		err = gopy.Convert(pyobj, &status)
	} else {
		status = false
		err = loc_err
	}
	return
}

func (s Salt) EnableService(node string, service string, start bool) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["EnableService"].Call(node, service, start); loc_err == nil {
		err = gopy.Convert(pyobj, &status)
	} else {
		status = false
		err = loc_err
	}
	return
}

func (s Salt) NodeUp(node string) (status bool, err error) {
	mutex.Lock()
	defer mutex.Unlock()
	if pyobj, loc_err := pyFuncs["NodeUp"].Call(node); loc_err == nil {
		err = gopy.Convert(pyobj, &status)
	} else {
		status = false
		err = loc_err
	}
	return
}

func New() backend.Backend {
	return new(Salt)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"

	"github.com/docker/distribution/reference"

	"github.com/Shopify/voucher/docker"
)

// getCanonicalReference gets the canonical image reference for the passed
// image reference. If the passed reference is not already a canonical image
// reference, this method will connect to the registry to get the current digest
// and create the canonical reference from the original reference and that digest.
//
// This is because Binary Authorization only supports canonical image references,
// as a non-canonical image reference could refer to multiple versions of the same
// image (with different contents).
func getCanonicalReference(client *http.Client, ref reference.Reference) (reference.Canonical, error) {
	if canonicalRef, ok := ref.(reference.Canonical); ok {
		return canonicalRef, nil
	}

	if taggedRef, ok := ref.(reference.NamedTagged); ok {
		imageDigest, err := docker.GetDigestFromTagged(client, taggedRef)
		if nil != err {
			return nil, fmt.Errorf("getting digest from tag failed: %s", err)
		}
		canonicalRef, err := reference.WithDigest(taggedRef, imageDigest)
		if nil != err {
			return nil, fmt.Errorf("making canonical reference failed: %s", err)
		}
		return canonicalRef, nil
	}
	return nil, fmt.Errorf("reference cannot be converted to a canonical reference")
}
<commit_msg>fixes Voucher Client's digest lookup code (#106)<commit_after>package main

import (
	"fmt"
	"net/http"

	"github.com/docker/distribution/reference"

	"github.com/Shopify/voucher/docker"
)

// getCanonicalReference gets the canonical image reference for the passed
// image reference. If the passed reference is not already a canonical image
// reference, this method will connect to the registry to get the current digest
// and create the canonical reference from the original reference and that digest.
//
// This is because Binary Authorization only supports canonical image references,
// as a non-canonical image reference could refer to multiple versions of the same
// image (with different contents).
func getCanonicalReference(client *http.Client, ref reference.Reference) (reference.Canonical, error) {
	if canonicalRef, ok := ref.(reference.Canonical); ok {
		return canonicalRef, nil
	}

	if taggedRef, ok := ref.(reference.NamedTagged); ok {
		imageDigest, err := docker.GetDigestFromTagged(client, taggedRef)
		if nil != err {
			return nil, fmt.Errorf("getting digest from tag failed: %s", err)
		}
		canonicalRef, err := reference.WithDigest(reference.TrimNamed(taggedRef), imageDigest)
		if nil != err {
			return nil, fmt.Errorf("making canonical reference failed: %s", err)
		}
		return canonicalRef, nil
	}
	return nil, fmt.Errorf("reference cannot be converted to a canonical reference")
}
<|endoftext|>


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

// Package value provides functionality for reflect.Value types.
package value

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"unicode"
)

var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()

// Format formats the value v as a string.
//
// This is similar to fmt.Sprintf("%+v", v) except this:
//	* Prints the type unless it can be elided
//	* Avoids printing struct fields that are zero
//	* Prints a nil-slice as being nil, not empty
//	* Prints map entries in deterministic order
func Format(v reflect.Value, useStringer bool) string {
	return formatAny(v, formatConfig{useStringer, true, true, true}, nil)
}

type formatConfig struct {
	useStringer    bool // Should the String method be used if available?
	printType      bool // Should we print the type before the value?
	followPointers bool // Should we recursively follow pointers?
	realPointers   bool // Should we print the real address of pointers?
}

func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) string {
	// TODO: Should this be a multi-line printout in certain situations?

	if !v.IsValid() {
		return "<non-existent>"
	}
	if conf.useStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
		if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
			return "<nil>"
		}

		const stringerPrefix = "s" // Indicates that the String method was used
		s := v.Interface().(fmt.Stringer).String()
		return stringerPrefix + formatString(s)
	}

	switch v.Kind() {
	case reflect.Bool:
		return formatPrimitive(v.Type(), v.Bool(), conf)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return formatPrimitive(v.Type(), v.Int(), conf)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		if v.Type().PkgPath() == "" || v.Kind() == reflect.Uintptr {
			// Unnamed uints are usually bytes or words, so use hexadecimal.
			return formatPrimitive(v.Type(), formatHex(v.Uint()), conf)
		}
		return formatPrimitive(v.Type(), v.Uint(), conf)
	case reflect.Float32, reflect.Float64:
		return formatPrimitive(v.Type(), v.Float(), conf)
	case reflect.Complex64, reflect.Complex128:
		return formatPrimitive(v.Type(), v.Complex(), conf)
	case reflect.String:
		return formatPrimitive(v.Type(), formatString(v.String()), conf)
	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
		return formatPointer(v, conf)
	case reflect.Ptr:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("(%v)(nil)", v.Type())
			}
			return "<nil>"
		}
		if visited[v.Pointer()] || !conf.followPointers {
			return formatPointer(v, conf)
		}
		visited = insertPointer(visited, v.Pointer())
		return "&" + formatAny(v.Elem(), conf, visited)
	case reflect.Interface:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("%v(nil)", v.Type())
			}
			return "<nil>"
		}
		return formatAny(v.Elem(), conf, visited)
	case reflect.Slice:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("%v(nil)", v.Type())
			}
			return "<nil>"
		}
		if visited[v.Pointer()] {
			return formatPointer(v, conf)
		}
		visited = insertPointer(visited, v.Pointer())
		fallthrough
	case reflect.Array:
		var ss []string
		subConf := conf
		subConf.printType = v.Type().Elem().Kind() == reflect.Interface
		for i := 0; i < v.Len(); i++ {
			s := formatAny(v.Index(i), subConf, visited)
			ss = append(ss, s)
		}
		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
		if conf.printType {
			return v.Type().String() + s
		}
		return s
	case reflect.Map:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("%v(nil)", v.Type())
			}
			return "<nil>"
		}
		if visited[v.Pointer()] {
			return formatPointer(v, conf)
		}
		visited = insertPointer(visited, v.Pointer())

		var ss []string
		keyConf, valConf := conf, conf
		keyConf.printType = v.Type().Key().Kind() == reflect.Interface
		keyConf.followPointers = false
		valConf.printType = v.Type().Elem().Kind() == reflect.Interface
		for _, k := range SortKeys(v.MapKeys()) {
			sk := formatAny(k, keyConf, visited)
			sv := formatAny(v.MapIndex(k), valConf, visited)
			ss = append(ss, fmt.Sprintf("%s: %s", sk, sv))
		}
		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
		if conf.printType {
			return v.Type().String() + s
		}
		return s
	case reflect.Struct:
		var ss []string
		subConf := conf
		subConf.printType = true
		for i := 0; i < v.NumField(); i++ {
			vv := v.Field(i)
			if isZero(vv) {
				continue // Elide zero value fields
			}
			name := v.Type().Field(i).Name
			subConf.useStringer = conf.useStringer
			s := formatAny(vv, subConf, visited)
			ss = append(ss, fmt.Sprintf("%s: %s", name, s))
		}
		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
		if conf.printType {
			return v.Type().String() + s
		}
		return s
	default:
		panic(fmt.Sprintf("%v kind not handled", v.Kind()))
	}
}

func formatString(s string) string {
	// Avoid performing quote-escaping if the string is already escaped.
	hasEscapes := strings.ContainsAny(s, `\`)
	allPrintable := strings.IndexFunc(s, unicode.IsPrint) >= 0
	rawAllowed := !strings.ContainsAny(s, "`\n")
	if hasEscapes && allPrintable && rawAllowed {
		return "`" + s + "`"
	}
	return strconv.Quote(s)
}

func formatPrimitive(t reflect.Type, v interface{}, conf formatConfig) string {
	if conf.printType && t.PkgPath() != "" {
		return fmt.Sprintf("%v(%v)", t, v)
	}
	return fmt.Sprintf("%v", v)
}

func formatPointer(v reflect.Value, conf formatConfig) string {
	p := v.Pointer()
	if !conf.realPointers {
		p = 0 // For deterministic printing purposes
	}
	s := formatHex(uint64(p))
	if conf.printType {
		return fmt.Sprintf("(%v)(%s)", v.Type(), s)
	}
	return s
}

func formatHex(u uint64) string {
	var f string
	switch {
	case u <= 0xff:
		f = "0x%02x"
	case u <= 0xffff:
		f = "0x%04x"
	case u <= 0xffffff:
		f = "0x%06x"
	case u <= 0xffffffff:
		f = "0x%08x"
	case u <= 0xffffffffff:
		f = "0x%010x"
	case u <= 0xffffffffffff:
		f = "0x%012x"
	case u <= 0xffffffffffffff:
		f = "0x%014x"
	case u <= 0xffffffffffffffff:
		f = "0x%016x"
	}
	return fmt.Sprintf(f, u)
}

// insertPointer insert p into m, allocating m if necessary.
func insertPointer(m map[uintptr]bool, p uintptr) map[uintptr]bool {
	if m == nil {
		m = make(map[uintptr]bool)
	}
	m[p] = true
	return m
}

// isZero reports whether v is the zero value.
// This does not rely on Interface and so can be used on unexported fields.
func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Bool:
		return v.Bool() == false
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Complex64, reflect.Complex128:
		return v.Complex() == 0
	case reflect.String:
		return v.String() == ""
	case reflect.UnsafePointer:
		return v.Pointer() == 0
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
		return v.IsNil()
	case reflect.Array:
		for i := 0; i < v.Len(); i++ {
			if !isZero(v.Index(i)) {
				return false
			}
		}
		return true
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			if !isZero(v.Field(i)) {
				return false
			}
		}
		return true
	}
	return false
}
<commit_msg>Adjust heuristics for using raw literals (#48)<commit_after>// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// Package value provides functionality for reflect.Value types.
package value

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"unicode"
)

var stringerIface = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()

// Format formats the value v as a string.
//
// This is similar to fmt.Sprintf("%+v", v) except this:
//	* Prints the type unless it can be elided
//	* Avoids printing struct fields that are zero
//	* Prints a nil-slice as being nil, not empty
//	* Prints map entries in deterministic order
func Format(v reflect.Value, useStringer bool) string {
	return formatAny(v, formatConfig{useStringer, true, true, true}, nil)
}

type formatConfig struct {
	useStringer    bool // Should the String method be used if available?
	printType      bool // Should we print the type before the value?
	followPointers bool // Should we recursively follow pointers?
	realPointers   bool // Should we print the real address of pointers?
}

func formatAny(v reflect.Value, conf formatConfig, visited map[uintptr]bool) string {
	// TODO: Should this be a multi-line printout in certain situations?

	if !v.IsValid() {
		return "<non-existent>"
	}
	if conf.useStringer && v.Type().Implements(stringerIface) && v.CanInterface() {
		if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
			return "<nil>"
		}

		const stringerPrefix = "s" // Indicates that the String method was used
		s := v.Interface().(fmt.Stringer).String()
		return stringerPrefix + formatString(s)
	}

	switch v.Kind() {
	case reflect.Bool:
		return formatPrimitive(v.Type(), v.Bool(), conf)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return formatPrimitive(v.Type(), v.Int(), conf)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		if v.Type().PkgPath() == "" || v.Kind() == reflect.Uintptr {
			// Unnamed uints are usually bytes or words, so use hexadecimal.
			return formatPrimitive(v.Type(), formatHex(v.Uint()), conf)
		}
		return formatPrimitive(v.Type(), v.Uint(), conf)
	case reflect.Float32, reflect.Float64:
		return formatPrimitive(v.Type(), v.Float(), conf)
	case reflect.Complex64, reflect.Complex128:
		return formatPrimitive(v.Type(), v.Complex(), conf)
	case reflect.String:
		return formatPrimitive(v.Type(), formatString(v.String()), conf)
	case reflect.UnsafePointer, reflect.Chan, reflect.Func:
		return formatPointer(v, conf)
	case reflect.Ptr:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("(%v)(nil)", v.Type())
			}
			return "<nil>"
		}
		if visited[v.Pointer()] || !conf.followPointers {
			return formatPointer(v, conf)
		}
		visited = insertPointer(visited, v.Pointer())
		return "&" + formatAny(v.Elem(), conf, visited)
	case reflect.Interface:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("%v(nil)", v.Type())
			}
			return "<nil>"
		}
		return formatAny(v.Elem(), conf, visited)
	case reflect.Slice:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("%v(nil)", v.Type())
			}
			return "<nil>"
		}
		if visited[v.Pointer()] {
			return formatPointer(v, conf)
		}
		visited = insertPointer(visited, v.Pointer())
		fallthrough
	case reflect.Array:
		var ss []string
		subConf := conf
		subConf.printType = v.Type().Elem().Kind() == reflect.Interface
		for i := 0; i < v.Len(); i++ {
			s := formatAny(v.Index(i), subConf, visited)
			ss = append(ss, s)
		}
		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
		if conf.printType {
			return v.Type().String() + s
		}
		return s
	case reflect.Map:
		if v.IsNil() {
			if conf.printType {
				return fmt.Sprintf("%v(nil)", v.Type())
			}
			return "<nil>"
		}
		if visited[v.Pointer()] {
			return formatPointer(v, conf)
		}
		visited = insertPointer(visited, v.Pointer())

		var ss []string
		keyConf, valConf := conf, conf
		keyConf.printType = v.Type().Key().Kind() == reflect.Interface
		keyConf.followPointers = false
		valConf.printType = v.Type().Elem().Kind() == reflect.Interface
		for _, k := range SortKeys(v.MapKeys()) {
			sk := formatAny(k, keyConf, visited)
			sv := formatAny(v.MapIndex(k), valConf, visited)
			ss = append(ss, fmt.Sprintf("%s: %s", sk, sv))
		}
		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
		if conf.printType {
			return v.Type().String() + s
		}
		return s
	case reflect.Struct:
		var ss []string
		subConf := conf
		subConf.printType = true
		for i := 0; i < v.NumField(); i++ {
			vv := v.Field(i)
			if isZero(vv) {
				continue // Elide zero value fields
			}
			name := v.Type().Field(i).Name
			subConf.useStringer = conf.useStringer
			s := formatAny(vv, subConf, visited)
			ss = append(ss, fmt.Sprintf("%s: %s", name, s))
		}
		s := fmt.Sprintf("{%s}", strings.Join(ss, ", "))
		if conf.printType {
			return v.Type().String() + s
		}
		return s
	default:
		panic(fmt.Sprintf("%v kind not handled", v.Kind()))
	}
}

func formatString(s string) string {
	// Use quoted string if it the same length as a raw string literal.
	// Otherwise, attempt to use the raw string form.
	qs := strconv.Quote(s)
	if len(qs) == 1+len(s)+1 {
		return qs
	}

	// Disallow newlines to ensure output is a single line.
	// Only allow printable runes for readability purposes.
	rawInvalid := func(r rune) bool {
		return r == '`' || r == '\n' || !unicode.IsPrint(r)
	}
	if strings.IndexFunc(s, rawInvalid) < 0 {
		return "`" + s + "`"
	}
	return qs
}

func formatPrimitive(t reflect.Type, v interface{}, conf formatConfig) string {
	if conf.printType && t.PkgPath() != "" {
		return fmt.Sprintf("%v(%v)", t, v)
	}
	return fmt.Sprintf("%v", v)
}

func formatPointer(v reflect.Value, conf formatConfig) string {
	p := v.Pointer()
	if !conf.realPointers {
		p = 0 // For deterministic printing purposes
	}
	s := formatHex(uint64(p))
	if conf.printType {
		return fmt.Sprintf("(%v)(%s)", v.Type(), s)
	}
	return s
}

func formatHex(u uint64) string {
	var f string
	switch {
	case u <= 0xff:
		f = "0x%02x"
	case u <= 0xffff:
		f = "0x%04x"
	case u <= 0xffffff:
		f = "0x%06x"
	case u <= 0xffffffff:
		f = "0x%08x"
	case u <= 0xffffffffff:
		f = "0x%010x"
	case u <= 0xffffffffffff:
		f = "0x%012x"
	case u <= 0xffffffffffffff:
		f = "0x%014x"
	case u <= 0xffffffffffffffff:
		f = "0x%016x"
	}
	return fmt.Sprintf(f, u)
}

// insertPointer insert p into m, allocating m if necessary.
func insertPointer(m map[uintptr]bool, p uintptr) map[uintptr]bool {
	if m == nil {
		m = make(map[uintptr]bool)
	}
	m[p] = true
	return m
}

// isZero reports whether v is the zero value.
// This does not rely on Interface and so can be used on unexported fields.
func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Bool:
		return v.Bool() == false
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Complex64, reflect.Complex128:
		return v.Complex() == 0
	case reflect.String:
		return v.String() == ""
	case reflect.UnsafePointer:
		return v.Pointer() == 0
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
		return v.IsNil()
	case reflect.Array:
		for i := 0; i < v.Len(); i++ {
			if !isZero(v.Index(i)) {
				return false
			}
		}
		return true
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			if !isZero(v.Field(i)) {
				return false
			}
		}
		return true
	}
	return false
}
<|endoftext|>


<commit_before>//go:generate mockgen -package=mockalerts -destination=mock/alerts.mock.go github.com/libopenstorage/openstorage/alerts FilterDeleter
package alerts

import (
	"encoding/json"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/libopenstorage/openstorage/api"
	"github.com/portworx/kvdb"
	"github.com/sirupsen/logrus"
)

// Error type for defining error constants.
type Error string

// Error satisfies Error interface from std lib.
func (e Error) Error() string {
	return string(e)
}

// Tag tags an error with a tag string.
// Helpful for providing error contexts.
func (e Error) Tag(tag Error) Error {
	return Error(string(tag) + ":" + string(e))
}

const (
	kvdbKey                    = "alerts"
	typeAssertionError   Error = "type assertion error"
	invalidFilterType    Error = "invalid filter type"
	invalidOptionType    Error = "invalid option type"
	incorrectFilterValue Error = "incorrectly set filter value"
)

const (
	HalfDay  = Day / 2
	Day      = 60 * 60 * 24
	FiveDays = Day * 5
)

// Manager manages alerts.
type Manager interface {
	// FilterDeleter allows read only operation on alerts
	FilterDeleter
	// Raise raises an alert.
	Raise(alert *api.Alert) error
	// SetRules sets a set of rules to be performed on alert events.
	SetRules(rules ...Rule)
	// DeleteRules deletes rules
	DeleteRules(rules ...Rule)
}

// FilterDeleter defines a list and delete interface on alerts.
// This interface is used in SDK.
type FilterDeleter interface {
	// Enumerate lists all alerts filtered by a variadic list of filters.
	// It will fetch a superset such that every alert is matched by at least one filter.
	Enumerate(filters ...Filter) ([]*api.Alert, error)
	// Filter filters given list of alerts successively through each filter.
	Filter(alerts []*api.Alert, filters ...Filter) ([]*api.Alert, error)
	// Delete deletes alerts filtered by a chain of filters.
	Delete(filters ...Filter) error
}

func newManager(kv kvdb.Kvdb, options ...Option) (*manager, error) {
	m := &manager{kv: kv, rules: make(map[string]Rule), ttl: HalfDay}
	for _, option := range options {
		switch option.GetType() {
		case ttlOption:
			v, ok := option.GetValue().(uint64)
			if !ok {
				return nil, typeAssertionError
			}
			m.ttl = v
		}
	}
	return m, nil
}

// manager implements Manager interface.
type manager struct {
	kv    kvdb.Kvdb
	rules map[string]Rule
	ttl   uint64
	sync.Mutex
}

// getKey is a util func that constructs kvdb key.
// kvdb tree structure is setup as follows:
// <baseKey>/<resourceType>/<dec2hex(alertType)>/<resourceID>/<alertObject>
func getKey(resourceType string, alertType int64, resourceID string) string {
	return filepath.Join(kvdbKey, resourceType, strconv.FormatInt(alertType, 16), resourceID)
}

func (m *manager) Raise(alert *api.Alert) error {
	for _, rule := range m.rules {
		if rule.GetEvent() == raiseEvent {
			match, err := rule.GetFilter().Match(alert)
			if err != nil {
				return err
			}
			if match {
				if err := rule.GetAction().Run(m); err != nil {
					return err
				}
			}
		}
	}

	if alert.Timestamp == nil {
		alert.Timestamp = &timestamp.Timestamp{Seconds: time.Now().Unix()}
	}

	key := getKey(alert.Resource.String(), alert.GetAlertType(), alert.ResourceId)
	if _, err := m.kv.Delete(key); err != nil && err != kvdb.ErrNotFound {
		logrus.WithField("pkg", "openstorage/alerts").WithField("func", "Raise").Error(err)
	}

	// ttl is time to live. it indicates how long (in seconds) the object should live inside kvdb backend.
	// kvdb will delete the object once ttl elapses.
	if alert.Cleared {
		// if the alert is marked Cleared, it is pushed to kvdb with a ttlOption of half day
		_, err := m.kv.Put(key, alert, m.ttl)
		return err
	} else {
		// otherwise use the ttl value embedded in the alert object
		_, err := m.kv.Put(key, alert, alert.Ttl)
		return err
	}
}

// Enumerate takes a variadic list of filters that are first analyzed to see if one filter
// is inclusive of other. Only the filters that are unique supersets are retained and their contents
// is fetched using kvdb enumerate.
func (m *manager) Enumerate(filters ...Filter) ([]*api.Alert, error) {
	myAlerts := make([]*api.Alert, 0, 0)
	keys, err := getUniqueKeysFromFilters(filters...)
	if err != nil {
		return nil, err
	}

	// enumerate for unique keys
	for key := range keys {
		kvps, err := enumerate(m.kv, key)
		if err != nil {
			return nil, err
		}

		for _, kvp := range kvps {
			alert := new(api.Alert)
			if err := json.Unmarshal(kvp.Value, alert); err != nil {
				return nil, err
			}

			if len(filters) == 0 {
				myAlerts = append(myAlerts, alert)
				continue
			}

			for _, filter := range filters {
				if match, err := filter.Match(alert); err != nil {
					return nil, err
				} else {
					// if alert is matched by at least one filter,
					// include it and break out of loop to avoid further checks.
					if match {
						myAlerts = append(myAlerts, alert)
						break
					}
				}
			}
		}
	}

	return myAlerts, nil
}

// enumerate recursively fetches kvpairs.
// Recursive call is required since, unlike mem kv, an etcd or consul based kv will not return
// leaf objects if the key is a prefix referencing only higher level paths. For instance if the
// kvdb structure is as follows:
// a/b/c/<data>
// a/B/C/<data>
// then enumerating for keys using "a" will only return "b" and "B".
func enumerate(kv kvdb.Kvdb, key string) (kvdb.KVPairs, error) {
	kvps, err := kv.Enumerate(key)
	if err != nil {
		return nil, err
	}

	var keys []string
	var out kvdb.KVPairs
	for _, kvp := range kvps {
		kvp := kvp
		if len(kvp.Value) == 0 {
			keys = append(keys, kvp.Key)
			continue
		}
		out = append(out, kvp)
	}

	for _, key := range keys {
		kvps, err := enumerate(kv, key)
		if err != nil {
			return nil, err
		}
		out = append(out, kvps...)
	}
	return out, nil
}

func (m *manager) Filter(alerts []*api.Alert, filters ...Filter) ([]*api.Alert, error) {
	for _, filter := range filters {
		i := 0
		for j, alert := range alerts {
			match, err := filter.Match(alert)
			if err != nil {
				return nil, err
			}

			if match {
				alerts[i] = alerts[j]
				i += 1
			}
		}

		// shrink the list
		alerts = alerts[:i]

		if len(alerts) == 0 {
			return alerts, nil
		}
	}

	return alerts, nil
}

func (m *manager) Delete(filters ...Filter) error {
	for _, rule := range m.rules {
		if rule.GetEvent() == deleteEvent {
			if err := rule.GetAction().Run(m); err != nil {
				return err
			}
		}
	}

	allFiltersIndexBased := true
Loop:
	for _, filter := range filters {
		switch filter.GetFilterType() {
		case CustomFilter,
			timeSpanFilter,
			alertTypeFilter,
			countSpanFilter,
			minSeverityFilter,
			flagCheckFilter,
			matchAlertTypeFilter,
			matchResourceIDFilter:
			allFiltersIndexBased = false
			break Loop
		}
	}

	if allFiltersIndexBased {
		keys, err := getUniqueKeysFromFilters(filters...)
		if err != nil {
			return err
		}

		for key := range keys {
			if err := m.kv.DeleteTree(key); err != nil {
				return err
			}
		}
	} else {
		myAlerts, err := m.Enumerate(filters...)
		if err != nil {
			return err
		}

		for _, alert := range myAlerts {
			if _, err := m.kv.Delete(getKey(alert.Resource.String(), alert.GetAlertType(), alert.ResourceId)); err != nil {
				return err
			}
		}
	}

	return nil
}

func (m *manager) SetRules(rules ...Rule) {
	m.Lock()
	defer m.Unlock()
	for _, rule := range rules {
		m.rules[rule.GetName()] = rule
	}
}

func (m *manager) DeleteRules(rules ...Rule) {
	m.Lock()
	defer m.Unlock()
	for _, rule := range rules {
		delete(m.rules, rule.GetName())
	}
}
<commit_msg>Delete Alert: When using resourceIDFilter use DeleteKey instead of DeleteTree<commit_after>//go:generate mockgen -package=mockalerts -destination=mock/alerts.mock.go github.com/libopenstorage/openstorage/alerts FilterDeleter
package alerts

import (
	"encoding/json"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/libopenstorage/openstorage/api"
	"github.com/portworx/kvdb"
	"github.com/sirupsen/logrus"
)

// Error type for defining error constants.
type Error string

// Error satisfies Error interface from std lib.
func (e Error) Error() string {
	return string(e)
}

// Tag tags an error with a tag string.
// Helpful for providing error contexts.
func (e Error) Tag(tag Error) Error {
	return Error(string(tag) + ":" + string(e))
}

const (
	kvdbKey                    = "alerts"
	typeAssertionError   Error = "type assertion error"
	invalidFilterType    Error = "invalid filter type"
	invalidOptionType    Error = "invalid option type"
	incorrectFilterValue Error = "incorrectly set filter value"
)

const (
	HalfDay  = Day / 2
	Day      = 60 * 60 * 24
	FiveDays = Day * 5
)

// Manager manages alerts.
type Manager interface {
	// FilterDeleter allows read only operation on alerts
	FilterDeleter
	// Raise raises an alert.
	Raise(alert *api.Alert) error
	// SetRules sets a set of rules to be performed on alert events.
	SetRules(rules ...Rule)
	// DeleteRules deletes rules
	DeleteRules(rules ...Rule)
}

// FilterDeleter defines a list and delete interface on alerts.
// This interface is used in SDK.
type FilterDeleter interface {
	// Enumerate lists all alerts filtered by a variadic list of filters.
	// It will fetch a superset such that every alert is matched by at least one filter.
	Enumerate(filters ...Filter) ([]*api.Alert, error)
	// Filter filters given list of alerts successively through each filter.
	Filter(alerts []*api.Alert, filters ...Filter) ([]*api.Alert, error)
	// Delete deletes alerts filtered by a chain of filters.
	Delete(filters ...Filter) error
}

func newManager(kv kvdb.Kvdb, options ...Option) (*manager, error) {
	m := &manager{kv: kv, rules: make(map[string]Rule), ttl: HalfDay}
	for _, option := range options {
		switch option.GetType() {
		case ttlOption:
			v, ok := option.GetValue().(uint64)
			if !ok {
				return nil, typeAssertionError
			}
			m.ttl = v
		}
	}
	return m, nil
}

// manager implements Manager interface.
type manager struct {
	kv    kvdb.Kvdb
	rules map[string]Rule
	ttl   uint64
	sync.Mutex
}

// getKey is a util func that constructs kvdb key.
// kvdb tree structure is setup as follows:
// <baseKey>/<resourceType>/<dec2hex(alertType)>/<resourceID>/<alertObject>
func getKey(resourceType string, alertType int64, resourceID string) string {
	return filepath.Join(kvdbKey, resourceType, strconv.FormatInt(alertType, 16), resourceID)
}

func (m *manager) Raise(alert *api.Alert) error {
	for _, rule := range m.rules {
		if rule.GetEvent() == raiseEvent {
			match, err := rule.GetFilter().Match(alert)
			if err != nil {
				return err
			}
			if match {
				if err := rule.GetAction().Run(m); err != nil {
					return err
				}
			}
		}
	}

	if alert.Timestamp == nil {
		alert.Timestamp = &timestamp.Timestamp{Seconds: time.Now().Unix()}
	}

	key := getKey(alert.Resource.String(), alert.GetAlertType(), alert.ResourceId)
	if _, err := m.kv.Delete(key); err != nil && err != kvdb.ErrNotFound {
		logrus.WithField("pkg", "openstorage/alerts").WithField("func", "Raise").Error(err)
	}

	// ttl is time to live. it indicates how long (in seconds) the object should live inside kvdb backend.
	// kvdb will delete the object once ttl elapses.
	if alert.Cleared {
		// if the alert is marked Cleared, it is pushed to kvdb with a ttlOption of half day
		_, err := m.kv.Put(key, alert, m.ttl)
		return err
	} else {
		// otherwise use the ttl value embedded in the alert object
		_, err := m.kv.Put(key, alert, alert.Ttl)
		return err
	}
}

// Enumerate takes a variadic list of filters that are first analyzed to see if one filter
// is inclusive of other. Only the filters that are unique supersets are retained and their contents
// is fetched using kvdb enumerate.
func (m *manager) Enumerate(filters ...Filter) ([]*api.Alert, error) {
	myAlerts := make([]*api.Alert, 0, 0)
	keys, err := getUniqueKeysFromFilters(filters...)
	if err != nil {
		return nil, err
	}

	// enumerate for unique keys
	for key := range keys {
		kvps, err := enumerate(m.kv, key)
		if err != nil {
			return nil, err
		}

		for _, kvp := range kvps {
			alert := new(api.Alert)
			if err := json.Unmarshal(kvp.Value, alert); err != nil {
				return nil, err
			}

			if len(filters) == 0 {
				myAlerts = append(myAlerts, alert)
				continue
			}

			for _, filter := range filters {
				if match, err := filter.Match(alert); err != nil {
					return nil, err
				} else {
					// if alert is matched by at least one filter,
					// include it and break out of loop to avoid further checks.
					if match {
						myAlerts = append(myAlerts, alert)
						break
					}
				}
			}
		}
	}

	return myAlerts, nil
}

// enumerate recursively fetches kvpairs.
// Recursive call is required since, unlike mem kv, an etcd or consul based kv will not return
// leaf objects if the key is a prefix referencing only higher level paths. For instance if the
// kvdb structure is as follows:
// a/b/c/<data>
// a/B/C/<data>
// then enumerating for keys using "a" will only return "b" and "B".
func enumerate(kv kvdb.Kvdb, key string) (kvdb.KVPairs, error) {
	kvps, err := kv.Enumerate(key)
	if err != nil {
		return nil, err
	}

	var keys []string
	var out kvdb.KVPairs
	for _, kvp := range kvps {
		kvp := kvp
		if len(kvp.Value) == 0 {
			keys = append(keys, kvp.Key)
			continue
		}
		out = append(out, kvp)
	}

	for _, key := range keys {
		kvps, err := enumerate(kv, key)
		if err != nil {
			return nil, err
		}
		out = append(out, kvps...)
	}
	return out, nil
}

func (m *manager) Filter(alerts []*api.Alert, filters ...Filter) ([]*api.Alert, error) {
	for _, filter := range filters {
		i := 0
		for j, alert := range alerts {
			match, err := filter.Match(alert)
			if err != nil {
				return nil, err
			}

			if match {
				alerts[i] = alerts[j]
				i += 1
			}
		}

		// shrink the list
		alerts = alerts[:i]

		if len(alerts) == 0 {
			return alerts, nil
		}
	}

	return alerts, nil
}

func (m *manager) Delete(filters ...Filter) error {
	for _, rule := range m.rules {
		if rule.GetEvent() == deleteEvent {
			if err := rule.GetAction().Run(m); err != nil {
				return err
			}
		}
	}

	allFiltersIndexBased := true
Loop:
	for _, filter := range filters {
		switch filter.GetFilterType() {
		case CustomFilter,
			timeSpanFilter,
			alertTypeFilter,
			countSpanFilter,
			minSeverityFilter,
			flagCheckFilter,
			matchAlertTypeFilter,
			resourceIDFilter,
			matchResourceIDFilter:
			allFiltersIndexBased = false
			break Loop
		}
	}

	if allFiltersIndexBased {
		keys, err := getUniqueKeysFromFilters(filters...)
		if err != nil {
			return err
		}

		for key := range keys {
			if err := m.kv.DeleteTree(key); err != nil {
				return err
			}
		}
	} else {
		myAlerts, err := m.Enumerate(filters...)
		if err != nil {
			return err
		}

		for _, alert := range myAlerts {
			if _, err := m.kv.Delete(getKey(alert.Resource.String(), alert.GetAlertType(), alert.ResourceId)); err != nil {
				return err
			}
		}
	}

	return nil
}

func (m *manager) SetRules(rules ...Rule) {
	m.Lock()
	defer m.Unlock()
	for _, rule := range rules {
		m.rules[rule.GetName()] = rule
	}
}

func (m *manager) DeleteRules(rules ...Rule) {
	m.Lock()
	defer m.Unlock()
	for _, rule := range rules {
		delete(m.rules, rule.GetName())
	}
}
<|endoftext|>