<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

// Package args has common command-line flags for generation programs.
package args

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"k8s.io/kubernetes/cmd/libs/go2idl/generator"
	"k8s.io/kubernetes/cmd/libs/go2idl/namer"
	"k8s.io/kubernetes/cmd/libs/go2idl/parser"
	"k8s.io/kubernetes/cmd/libs/go2idl/types"
	"k8s.io/kubernetes/pkg/util"
	utilflag "k8s.io/kubernetes/pkg/util/flag"

	"github.com/spf13/pflag"
)

// Default returns a defaulted GeneratorArgs. You may change the defaults
// before calling AddFlags.
func Default() *GeneratorArgs {
	generatorArgs := &GeneratorArgs{
		OutputBase:        DefaultSourceTree(),
		GoHeaderFilePath:  filepath.Join(DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt"),
		GeneratedBuildTag: "ignore_autogenerated",
	}
	generatorArgs.AddFlags(pflag.CommandLine)
	return generatorArgs
}

// GeneratorArgs has arguments that are passed to generators.
type GeneratorArgs struct {
	// Which directories to parse.
	InputDirs []string

	// Source tree to write results to.
	OutputBase string

	// Package path within the source tree.
	OutputPackagePath string

	// Output file name.
	OutputFileBaseName string

	// Where to get copyright header text.
	GoHeaderFilePath string

	// If true, only verify, don't write anything.
	VerifyOnly bool

	// GeneratedBuildTag is the tag used to identify code generated by execution
	// of this type. Each generator should use a different tag, and different
	// groups of generators (external API that depends on Kube generations) should
	// keep tags distinct as well.
	GeneratedBuildTag string

	// Any custom arguments go here
	CustomArgs interface{}
}

func (g *GeneratorArgs) AddFlags(fs *pflag.FlagSet) {
	fs.StringSliceVarP(&g.InputDirs, "input-dirs", "i", g.InputDirs, "Comma-separated list of import paths to get input types from.")
	fs.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/ or ./ if $GOPATH is not set.")
	fs.StringVarP(&g.OutputPackagePath, "output-package", "p", g.OutputPackagePath, "Base package path.")
	fs.StringVarP(&g.OutputFileBaseName, "output-file-base", "O", g.OutputFileBaseName, "Base name (without .go suffix) for output files.")
	fs.StringVarP(&g.GoHeaderFilePath, "go-header-file", "h", g.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.")
	fs.BoolVar(&g.VerifyOnly, "verify-only", g.VerifyOnly, "If true, only verify existing output, do not write anything.")
	fs.StringVar(&g.GeneratedBuildTag, "build-tag", g.GeneratedBuildTag, "A Go build tag to use to identify files generated by this command. Should be unique.")
}

// LoadGoBoilerplate loads the boilerplate file passed to --go-header-file.
func (g *GeneratorArgs) LoadGoBoilerplate() ([]byte, error) {
	b, err := ioutil.ReadFile(g.GoHeaderFilePath)
	if err != nil {
		return nil, err
	}
	b = bytes.Replace(b, []byte("YEAR"), []byte(strconv.Itoa(time.Now().Year())), -1)
	return b, nil
}

// NewBuilder makes a new parser.Builder and populates it with the input
// directories.
func (g *GeneratorArgs) NewBuilder() (*parser.Builder, error) {
	b := parser.New()
	// Ignore all auto-generated files.
	b.AddBuildTags(g.GeneratedBuildTag)

	for _, d := range g.InputDirs {
		var err error
		if strings.HasSuffix(d, "/...") {
			err = b.AddDirRecursive(strings.TrimSuffix(d, "/..."))
		} else {
			err = b.AddDir(d)
		}
		if err != nil {
			return nil, fmt.Errorf("unable to add directory %q: %v", d, err)
		}
	}
	return b, nil
}

// InputIncludes returns true if the given package is a (sub) package of one of
// the InputDirs.
func (g *GeneratorArgs) InputIncludes(p *types.Package) bool {
	for _, dir := range g.InputDirs {
		if strings.HasPrefix(p.Path, dir) {
			return true
		}
	}
	return false
}

// DefaultSourceTree returns the /src directory of the first entry in $GOPATH.
// If $GOPATH is empty, it returns "./". Useful as a default output location.
func DefaultSourceTree() string {
	paths := strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
	if len(paths) > 0 && len(paths[0]) > 0 {
		return filepath.Join(paths[0], "src")
	}
	return "./"
}

// Execute implements main().
// If you don't need any non-default behavior, use as:
// args.Default().Execute(...)
func (g *GeneratorArgs) Execute(nameSystems namer.NameSystems, defaultSystem string, pkgs func(*generator.Context, *GeneratorArgs) generator.Packages) error {
	utilflag.InitFlags()
	util.InitLogs()

	b, err := g.NewBuilder()
	if err != nil {
		return fmt.Errorf("Failed making a parser: %v", err)
	}

	c, err := generator.NewContext(b, nameSystems, defaultSystem)
	if err != nil {
		return fmt.Errorf("Failed making a context: %v", err)
	}

	c.Verify = g.VerifyOnly
	packages := pkgs(c, g)
	if err := c.ExecutePackages(g.OutputBase, packages); err != nil {
		return fmt.Errorf("Failed executing generator: %v", err)
	}

	return nil
}
<commit_msg>move pkg/util/ files to their own package to reduce client-go dependencies<commit_after>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

// Package args has common command-line flags for generation programs.
package args

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"k8s.io/kubernetes/cmd/libs/go2idl/generator"
	"k8s.io/kubernetes/cmd/libs/go2idl/namer"
	"k8s.io/kubernetes/cmd/libs/go2idl/parser"
	"k8s.io/kubernetes/cmd/libs/go2idl/types"
	utilflag "k8s.io/kubernetes/pkg/util/flag"
	"k8s.io/kubernetes/pkg/util/logs"

	"github.com/spf13/pflag"
)

// Default returns a defaulted GeneratorArgs. You may change the defaults
// before calling AddFlags.
func Default() *GeneratorArgs {
	generatorArgs := &GeneratorArgs{
		OutputBase:        DefaultSourceTree(),
		GoHeaderFilePath:  filepath.Join(DefaultSourceTree(), "k8s.io/kubernetes/hack/boilerplate/boilerplate.go.txt"),
		GeneratedBuildTag: "ignore_autogenerated",
	}
	generatorArgs.AddFlags(pflag.CommandLine)
	return generatorArgs
}

// GeneratorArgs has arguments that are passed to generators.
type GeneratorArgs struct {
	// Which directories to parse.
	InputDirs []string

	// Source tree to write results to.
	OutputBase string

	// Package path within the source tree.
	OutputPackagePath string

	// Output file name.
	OutputFileBaseName string

	// Where to get copyright header text.
	GoHeaderFilePath string

	// If true, only verify, don't write anything.
	VerifyOnly bool

	// GeneratedBuildTag is the tag used to identify code generated by execution
	// of this type. Each generator should use a different tag, and different
	// groups of generators (external API that depends on Kube generations) should
	// keep tags distinct as well.
	GeneratedBuildTag string

	// Any custom arguments go here
	CustomArgs interface{}
}

func (g *GeneratorArgs) AddFlags(fs *pflag.FlagSet) {
	fs.StringSliceVarP(&g.InputDirs, "input-dirs", "i", g.InputDirs, "Comma-separated list of import paths to get input types from.")
	fs.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/ or ./ if $GOPATH is not set.")
	fs.StringVarP(&g.OutputPackagePath, "output-package", "p", g.OutputPackagePath, "Base package path.")
	fs.StringVarP(&g.OutputFileBaseName, "output-file-base", "O", g.OutputFileBaseName, "Base name (without .go suffix) for output files.")
	fs.StringVarP(&g.GoHeaderFilePath, "go-header-file", "h", g.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.")
	fs.BoolVar(&g.VerifyOnly, "verify-only", g.VerifyOnly, "If true, only verify existing output, do not write anything.")
	fs.StringVar(&g.GeneratedBuildTag, "build-tag", g.GeneratedBuildTag, "A Go build tag to use to identify files generated by this command. Should be unique.")
}

// LoadGoBoilerplate loads the boilerplate file passed to --go-header-file.
func (g *GeneratorArgs) LoadGoBoilerplate() ([]byte, error) {
	b, err := ioutil.ReadFile(g.GoHeaderFilePath)
	if err != nil {
		return nil, err
	}
	b = bytes.Replace(b, []byte("YEAR"), []byte(strconv.Itoa(time.Now().Year())), -1)
	return b, nil
}

// NewBuilder makes a new parser.Builder and populates it with the input
// directories.
func (g *GeneratorArgs) NewBuilder() (*parser.Builder, error) {
	b := parser.New()
	// Ignore all auto-generated files.
	b.AddBuildTags(g.GeneratedBuildTag)

	for _, d := range g.InputDirs {
		var err error
		if strings.HasSuffix(d, "/...") {
			err = b.AddDirRecursive(strings.TrimSuffix(d, "/..."))
		} else {
			err = b.AddDir(d)
		}
		if err != nil {
			return nil, fmt.Errorf("unable to add directory %q: %v", d, err)
		}
	}
	return b, nil
}

// InputIncludes returns true if the given package is a (sub) package of one of
// the InputDirs.
func (g *GeneratorArgs) InputIncludes(p *types.Package) bool {
	for _, dir := range g.InputDirs {
		if strings.HasPrefix(p.Path, dir) {
			return true
		}
	}
	return false
}

// DefaultSourceTree returns the /src directory of the first entry in $GOPATH.
// If $GOPATH is empty, it returns "./". Useful as a default output location.
func DefaultSourceTree() string {
	paths := strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator))
	if len(paths) > 0 && len(paths[0]) > 0 {
		return filepath.Join(paths[0], "src")
	}
	return "./"
}

// Execute implements main().
// If you don't need any non-default behavior, use as:
// args.Default().Execute(...)
func (g *GeneratorArgs) Execute(nameSystems namer.NameSystems, defaultSystem string, pkgs func(*generator.Context, *GeneratorArgs) generator.Packages) error {
	utilflag.InitFlags()
	logs.InitLogs()

	b, err := g.NewBuilder()
	if err != nil {
		return fmt.Errorf("Failed making a parser: %v", err)
	}

	c, err := generator.NewContext(b, nameSystems, defaultSystem)
	if err != nil {
		return fmt.Errorf("Failed making a context: %v", err)
	}

	c.Verify = g.VerifyOnly
	packages := pkgs(c, g)
	if err := c.ExecutePackages(g.OutputBase, packages); err != nil {
		return fmt.Errorf("Failed executing generator: %v", err)
	}

	return nil
}
<|endoftext|>


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

package api

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/pufferpanel/apufferi/v4/response"
	"github.com/pufferpanel/apufferi/v4/scope"
	"github.com/pufferpanel/pufferpanel/v2"
	"github.com/pufferpanel/pufferpanel/v2/models"
	"github.com/pufferpanel/pufferpanel/v2/services"
	"github.com/pufferpanel/pufferpanel/v2/web/handlers"
	uuid "github.com/satori/go.uuid"
	"github.com/spf13/viper"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

func registerNodes(g *gin.RouterGroup) {
	g.Handle("GET", "", handlers.OAuth2Handler(scope.NodesView, false), getAllNodes)
	g.Handle("OPTIONS", "", response.CreateOptions("GET"))
	g.Handle("POST", "", handlers.OAuth2Handler(scope.NodesEdit, false), createNode)

	g.Handle("GET", "/:id", handlers.OAuth2Handler(scope.NodesView, false), getNode)
	g.Handle("PUT", "/:id", handlers.OAuth2Handler(scope.NodesEdit, false), updateNode)
	g.Handle("DELETE", "/:id", handlers.OAuth2Handler(scope.NodesEdit, false), deleteNode)
	g.Handle("OPTIONS", "/:id", response.CreateOptions("PUT", "GET", "POST", "DELETE"))

	g.Handle("GET", "/:id/deployment", handlers.OAuth2Handler(scope.NodesDeploy, false), response.NotImplemented)
	g.Handle("OPTIONS", "/:id/deployment", response.CreateOptions("GET"))

	//g.Handle("POST", "/:id/reset", handlers.OAuth2(scope.NodesDeploy, false), response.NotImplemented)
	//g.Handle("OPTIONS", "/:id/reset", response.CreateOptions("POST"))
}

// @Summary Get nodes
// @Description Gets all nodes registered to the panel
// @Accept json
// @Produce json
// @Success 200 {object} models.NodesView "Nodes"
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Router /nodes [get]
func getAllNodes(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	var nodes *models.Nodes
	if nodes, err = ns.GetAll(); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	data := models.FromNodes(nodes)

	c.JSON(http.StatusOK, data)
}

// @Summary Get node
// @Description Gets information about a single node
// @Accept json
// @Produce json
// @Success 200 {object} models.NodeView "Nods"
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Router /nodes/{id} [get]
func getNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	id, ok := validateId(c)
	if !ok {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	data := models.FromNode(node)

	c.JSON(http.StatusOK, data)
}

// @Summary Create node
// @Description Creates a node
// @Accept json
// @Produce json
// @Success 200 {object} models.NodeView "Node created"
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Param id path string true "Node Identifier"
// @Router /nodes [post]
func createNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	model := &models.NodeView{}
	if err = c.BindJSON(model); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if err = model.Valid(false); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	create := &models.Node{}
	model.CopyToModel(create)
	create.Secret = strings.Replace(uuid.NewV4().String(), "-", "", -1)
	if err = ns.Create(create); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.JSON(http.StatusOK, create)
}

// @Summary Update node
// @Description Updates a node with given information
// @Accept json
// @Produce json
// @Success 204 {object} response.Empty
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Param id path string true "Node Id"
// @Router /nodes/{id} [put]
func updateNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	viewModel := &models.NodeView{}
	if err = c.BindJSON(viewModel); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	id, ok := validateId(c)
	if !ok {
		return
	}

	if err = viewModel.Valid(true); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	viewModel.CopyToModel(node)
	if err = ns.Update(node); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

// @Summary Deletes a node
// @Description Deletes the node
// @Accept json
// @Produce json
// @Success 204 {object} response.Empty
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Param id path string true "Node Id"
// @Router /nodes/{id} [delete]
func deleteNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	id, ok := validateId(c)
	if !ok {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	err = ns.Delete(node.ID)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

func deployNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	id, ok := validateId(c)
	if !ok {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	services.ValidateTokenLoaded()
	file, err := ioutil.ReadFile(viper.GetString("token.public"))
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	data := &Deployment{
		ClientId:     fmt.Sprintf(".node_%d", node.ID),
		ClientSecret: node.Secret,
		BaseUrl:      fmt.Sprintf("%s://%s", c.Request.URL.Scheme, c.Request.URL.Host),
		PublicKey:    string(file),
	}

	c.JSON(http.StatusOK, data)
}

func validateId(c *gin.Context) (uint, bool) {
	param := c.Param("id")

	id, err := strconv.Atoi(param)

	if response.HandleError(c, err, http.StatusBadRequest) || id <= 0 {
		response.HandleError(c, pufferpanel.ErrFieldTooSmall("id", 0), http.StatusBadRequest)
		return 0, false
	}

	return uint(id), true
}

type Deployment struct {
	ClientId     string `json:"clientId"`
	ClientSecret string `json:"clientSecret"`
	BaseUrl      string `json:"baseUrl"`
	PublicKey    string `json:"publicKey"`
}
<commit_msg>Add deployment endpoint<commit_after>/*
 Copyright 2018 Padduck, LLC
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 	http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package api

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/pufferpanel/apufferi/v4/response"
	"github.com/pufferpanel/apufferi/v4/scope"
	"github.com/pufferpanel/pufferpanel/v2"
	"github.com/pufferpanel/pufferpanel/v2/models"
	"github.com/pufferpanel/pufferpanel/v2/services"
	"github.com/pufferpanel/pufferpanel/v2/web/handlers"
	uuid "github.com/satori/go.uuid"
	"github.com/spf13/viper"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

func registerNodes(g *gin.RouterGroup) {
	g.Handle("GET", "", handlers.OAuth2Handler(scope.NodesView, false), getAllNodes)
	g.Handle("OPTIONS", "", response.CreateOptions("GET"))
	g.Handle("POST", "", handlers.OAuth2Handler(scope.NodesEdit, false), createNode)

	g.Handle("GET", "/:id", handlers.OAuth2Handler(scope.NodesView, false), getNode)
	g.Handle("PUT", "/:id", handlers.OAuth2Handler(scope.NodesEdit, false), updateNode)
	g.Handle("DELETE", "/:id", handlers.OAuth2Handler(scope.NodesEdit, false), deleteNode)
	g.Handle("OPTIONS", "/:id", response.CreateOptions("PUT", "GET", "POST", "DELETE"))

	g.Handle("GET", "/:id/deployment", handlers.OAuth2Handler(scope.NodesDeploy, false), deployNode)
	g.Handle("OPTIONS", "/:id/deployment", response.CreateOptions("GET"))

	//g.Handle("POST", "/:id/reset", handlers.OAuth2(scope.NodesDeploy, false), response.NotImplemented)
	//g.Handle("OPTIONS", "/:id/reset", response.CreateOptions("POST"))
}

// @Summary Get nodes
// @Description Gets all nodes registered to the panel
// @Accept json
// @Produce json
// @Success 200 {object} models.NodesView "Nodes"
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Router /nodes [get]
func getAllNodes(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	var nodes *models.Nodes
	if nodes, err = ns.GetAll(); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	data := models.FromNodes(nodes)

	c.JSON(http.StatusOK, data)
}

// @Summary Get node
// @Description Gets information about a single node
// @Accept json
// @Produce json
// @Success 200 {object} models.NodeView "Nods"
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Router /nodes/{id} [get]
func getNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	id, ok := validateId(c)
	if !ok {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	data := models.FromNode(node)

	c.JSON(http.StatusOK, data)
}

// @Summary Create node
// @Description Creates a node
// @Accept json
// @Produce json
// @Success 200 {object} models.NodeView "Node created"
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Param id path string true "Node Identifier"
// @Router /nodes [post]
func createNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	model := &models.NodeView{}
	if err = c.BindJSON(model); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	if err = model.Valid(false); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	create := &models.Node{}
	model.CopyToModel(create)
	create.Secret = strings.Replace(uuid.NewV4().String(), "-", "", -1)
	if err = ns.Create(create); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.JSON(http.StatusOK, create)
}

// @Summary Update node
// @Description Updates a node with given information
// @Accept json
// @Produce json
// @Success 204 {object} response.Empty
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Param id path string true "Node Id"
// @Router /nodes/{id} [put]
func updateNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	viewModel := &models.NodeView{}
	if err = c.BindJSON(viewModel); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	id, ok := validateId(c)
	if !ok {
		return
	}

	if err = viewModel.Valid(true); response.HandleError(c, err, http.StatusBadRequest) {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	viewModel.CopyToModel(node)
	if err = ns.Update(node); response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

// @Summary Deletes a node
// @Description Deletes the node
// @Accept json
// @Produce json
// @Success 204 {object} response.Empty
// @Failure 400 {object} response.Error
// @Failure 403 {object} response.Error
// @Failure 404 {object} response.Error
// @Failure 500 {object} response.Error
// @Param id path string true "Node Id"
// @Router /nodes/{id} [delete]
func deleteNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	id, ok := validateId(c)
	if !ok {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	err = ns.Delete(node.ID)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	c.Status(http.StatusNoContent)
}

func deployNode(c *gin.Context) {
	var err error
	db := handlers.GetDatabase(c)
	ns := &services.Node{DB: db}

	id, ok := validateId(c)
	if !ok {
		return
	}

	node, err := ns.Get(id)
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	services.ValidateTokenLoaded()
	file, err := ioutil.ReadFile(viper.GetString("token.public"))
	if response.HandleError(c, err, http.StatusInternalServerError) {
		return
	}

	data := &Deployment{
		ClientId:     fmt.Sprintf(".node_%d", node.ID),
		ClientSecret: node.Secret,
		PublicKey:    string(file),
	}

	c.JSON(http.StatusOK, data)
}

func validateId(c *gin.Context) (uint, bool) {
	param := c.Param("id")

	id, err := strconv.Atoi(param)

	if response.HandleError(c, err, http.StatusBadRequest) || id <= 0 {
		response.HandleError(c, pufferpanel.ErrFieldTooSmall("id", 0), http.StatusBadRequest)
		return 0, false
	}

	return uint(id), true
}

type Deployment struct {
	ClientId     string `json:"clientId"`
	ClientSecret string `json:"clientSecret"`
	PublicKey    string `json:"publicKey"`
}
<|endoftext|>


<commit_before>// Package apps is the HTTP frontend of the application package. It
// exposes the HTTP api install, update or uninstall applications.
package apps

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/vfs"
	"github.com/cozy/cozy-stack/web/jsonapi"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/cozy/cozy-stack/web/permissions"
	"github.com/labstack/echo"
)

// JSMimeType is the content-type for javascript
const JSMimeType = "application/javascript"

const typeTextEventStream = "text/event-stream"

// installHandler handles all POST /:slug request and tries to install
// or update the application with the given Source.
func installHandler(installerType apps.AppType) echo.HandlerFunc {
	return func(c echo.Context) error {
		instance := middlewares.GetInstance(c)
		slug := c.Param("slug")
		if err := permissions.AllowInstallApp(c, permissions.POST); err != nil {
			return err
		}
		inst, err := apps.NewInstaller(instance, instance.VFS(),
			&apps.InstallerOptions{
				Type:      installerType,
				SourceURL: c.QueryParam("Source"),
				Slug:      slug,
			},
		)
		if err != nil {
			return wrapAppsError(err)
		}
		go inst.Install()
		return pollInstaller(c, slug, inst)
	}
}

// updateHandler handles all POST /:slug request and tries to install
// or update the application with the given Source.
func updateHandler(installerType apps.AppType) echo.HandlerFunc {
	return func(c echo.Context) error {
		instance := middlewares.GetInstance(c)
		slug := c.Param("slug")
		if err := permissions.AllowInstallApp(c, permissions.POST); err != nil {
			return err
		}
		inst, err := apps.NewInstaller(instance, instance.VFS(),
			&apps.InstallerOptions{
				Type: installerType,
				Slug: slug,
			},
		)
		if err != nil {
			return wrapAppsError(err)
		}
		go inst.Update()
		return pollInstaller(c, slug, inst)
	}
}

// deleteHandler handles all DELETE /:slug used to delete an application with
// the specified slug.
func deleteHandler(installerType apps.AppType) echo.HandlerFunc {
	return func(c echo.Context) error {
		instance := middlewares.GetInstance(c)
		slug := c.Param("slug")
		if err := permissions.AllowInstallApp(c, permissions.DELETE); err != nil {
			return err
		}
		inst, err := apps.NewInstaller(instance, instance.VFS(),
			&apps.InstallerOptions{
				Type: installerType,
				Slug: slug,
			},
		)
		if err != nil {
			return wrapAppsError(err)
		}
		man, err := inst.Delete()
		if err != nil {
			return wrapAppsError(err)
		}
		return jsonapi.Data(c, http.StatusOK, man, nil)
	}
}

func pollInstaller(c echo.Context, slug string, inst *apps.Installer) error {
	accept := c.Request().Header.Get("Accept")
	if accept != typeTextEventStream {
		man, _, err := inst.Poll()
		if err != nil {
			return wrapAppsError(err)
		}
		go func() {
			for {
				_, done, err := inst.Poll()
				if err != nil {
					log.Errorf("[apps] %s could not be installed: %v", slug, err)
					break
				}
				if done {
					break
				}
			}
		}()
		return jsonapi.Data(c, http.StatusAccepted, man, nil)
	}

	w := c.Response().Writer
	w.Header().Set("Content-Type", typeTextEventStream)
	w.WriteHeader(200)
	for {
		man, done, err := inst.Poll()
		if err != nil {
			var b []byte
			if b, err = json.Marshal(err.Error()); err == nil {
				writeStream(w, "error", string(b))
			}
			break
		}
		buf := new(bytes.Buffer)
		if err := jsonapi.WriteData(buf, man, nil); err == nil {
			writeStream(w, "state", buf.String())
		}
		if done {
			break
		}
	}
	return nil
}

func writeStream(w http.ResponseWriter, event string, b string) {
	s := fmt.Sprintf("event: %s\r\ndata: %s\r\n\r\n", event, b)
	_, err := w.Write([]byte(s))
	if err != nil {
		return
	}
	if f, ok := w.(http.Flusher); ok {
		f.Flush()
	}
}

// listHandler handles all GET / requests which can be used to list
// installed applications.
func listHandler(c echo.Context) error {
	instance := middlewares.GetInstance(c)

	if err := permissions.AllowWholeType(c, permissions.GET, consts.Apps); err != nil {
		return err
	}

	docs, err := apps.ListWebapps(instance)
	if err != nil {
		return wrapAppsError(err)
	}

	objs := make([]jsonapi.Object, len(docs))
	for i, d := range docs {
		d.Instance = instance
		objs[i] = jsonapi.Object(d)
	}

	return jsonapi.DataList(c, http.StatusOK, objs, nil)
}

// iconHandler gives the icon of an application
func iconHandler(c echo.Context) error {
	instance := middlewares.GetInstance(c)
	slug := c.Param("slug")
	app, err := apps.GetWebappBySlug(instance, slug)
	if err != nil {
		return err
	}

	if err = permissions.Allow(c, permissions.GET, app); err != nil {
		return err
	}

	filepath := path.Join(vfs.WebappsDirName, slug, app.Icon)
	file, err := instance.VFS().FileByPath(filepath)
	if err != nil {
		return err
	}

	r, err := instance.VFS().OpenFile(file)
	if err != nil {
		return err
	}
	defer r.Close()
	http.ServeContent(c.Response(), c.Request(), filepath, time.Time{}, r)
	return nil
}

// WebappsRoutes sets the routing for the web apps service
func WebappsRoutes(router *echo.Group) {
	router.GET("/", listHandler)
	router.POST("/:slug", installHandler(apps.Webapp))
	router.PUT("/:slug", updateHandler(apps.Webapp))
	router.DELETE("/:slug", deleteHandler(apps.Webapp))
	router.GET("/:slug/icon", iconHandler)
}

// KonnectorRoutes sets the routing for the konnectors service
func KonnectorRoutes(router *echo.Group) {
	router.POST("/:slug", installHandler(apps.Konnector))
	router.POST("/:slug", updateHandler(apps.Konnector))
	router.POST("/:slug", deleteHandler(apps.Konnector))
}

func wrapAppsError(err error) error {
	switch err {
	case apps.ErrInvalidSlugName:
		return jsonapi.InvalidParameter("slug", err)
	case apps.ErrAlreadyExists:
		return jsonapi.Conflict(err)
	case apps.ErrNotFound:
		return jsonapi.NotFound(err)
	case apps.ErrNotSupportedSource:
		return jsonapi.InvalidParameter("Source", err)
	case apps.ErrManifestNotReachable:
		return jsonapi.NotFound(err)
	case apps.ErrSourceNotReachable:
		return jsonapi.BadRequest(err)
	case apps.ErrBadManifest:
		return jsonapi.BadRequest(err)
	case apps.ErrMissingSource:
		return jsonapi.BadRequest(err)
	}
	if _, ok := err.(*url.Error); ok {
		return jsonapi.InvalidParameter("Source", err)
	}
	return err
}
<commit_msg>Fix /konnectors routing<commit_after>// Package apps is the HTTP frontend of the application package. It
// exposes the HTTP api install, update or uninstall applications.
package apps

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"path"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/vfs"
	"github.com/cozy/cozy-stack/web/jsonapi"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/cozy/cozy-stack/web/permissions"
	"github.com/labstack/echo"
)

// JSMimeType is the content-type for javascript
const JSMimeType = "application/javascript"

const typeTextEventStream = "text/event-stream"

// installHandler handles all POST /:slug request and tries to install
// or update the application with the given Source.
func installHandler(installerType apps.AppType) echo.HandlerFunc {
	return func(c echo.Context) error {
		instance := middlewares.GetInstance(c)
		slug := c.Param("slug")
		if err := permissions.AllowInstallApp(c, permissions.POST); err != nil {
			return err
		}
		inst, err := apps.NewInstaller(instance, instance.VFS(),
			&apps.InstallerOptions{
				Type:      installerType,
				SourceURL: c.QueryParam("Source"),
				Slug:      slug,
			},
		)
		if err != nil {
			return wrapAppsError(err)
		}
		go inst.Install()
		return pollInstaller(c, slug, inst)
	}
}

// updateHandler handles all POST /:slug request and tries to install
// or update the application with the given Source.
func updateHandler(installerType apps.AppType) echo.HandlerFunc {
	return func(c echo.Context) error {
		instance := middlewares.GetInstance(c)
		slug := c.Param("slug")
		if err := permissions.AllowInstallApp(c, permissions.POST); err != nil {
			return err
		}
		inst, err := apps.NewInstaller(instance, instance.VFS(),
			&apps.InstallerOptions{
				Type: installerType,
				Slug: slug,
			},
		)
		if err != nil {
			return wrapAppsError(err)
		}
		go inst.Update()
		return pollInstaller(c, slug, inst)
	}
}

// deleteHandler handles all DELETE /:slug used to delete an application with
// the specified slug.
func deleteHandler(installerType apps.AppType) echo.HandlerFunc {
	return func(c echo.Context) error {
		instance := middlewares.GetInstance(c)
		slug := c.Param("slug")
		if err := permissions.AllowInstallApp(c, permissions.DELETE); err != nil {
			return err
		}
		inst, err := apps.NewInstaller(instance, instance.VFS(),
			&apps.InstallerOptions{
				Type: installerType,
				Slug: slug,
			},
		)
		if err != nil {
			return wrapAppsError(err)
		}
		man, err := inst.Delete()
		if err != nil {
			return wrapAppsError(err)
		}
		return jsonapi.Data(c, http.StatusOK, man, nil)
	}
}

func pollInstaller(c echo.Context, slug string, inst *apps.Installer) error {
	accept := c.Request().Header.Get("Accept")
	if accept != typeTextEventStream {
		man, _, err := inst.Poll()
		if err != nil {
			return wrapAppsError(err)
		}
		go func() {
			for {
				_, done, err := inst.Poll()
				if err != nil {
					log.Errorf("[apps] %s could not be installed: %v", slug, err)
					break
				}
				if done {
					break
				}
			}
		}()
		return jsonapi.Data(c, http.StatusAccepted, man, nil)
	}

	w := c.Response().Writer
	w.Header().Set("Content-Type", typeTextEventStream)
	w.WriteHeader(200)
	for {
		man, done, err := inst.Poll()
		if err != nil {
			var b []byte
			if b, err = json.Marshal(err.Error()); err == nil {
				writeStream(w, "error", string(b))
			}
			break
		}
		buf := new(bytes.Buffer)
		if err := jsonapi.WriteData(buf, man, nil); err == nil {
			writeStream(w, "state", buf.String())
		}
		if done {
			break
		}
	}
	return nil
}

func writeStream(w http.ResponseWriter, event string, b string) {
	s := fmt.Sprintf("event: %s\r\ndata: %s\r\n\r\n", event, b)
	_, err := w.Write([]byte(s))
	if err != nil {
		return
	}
	if f, ok := w.(http.Flusher); ok {
		f.Flush()
	}
}

// listHandler handles all GET / requests which can be used to list
// installed applications.
func listHandler(c echo.Context) error {
	instance := middlewares.GetInstance(c)

	if err := permissions.AllowWholeType(c, permissions.GET, consts.Apps); err != nil {
		return err
	}

	docs, err := apps.ListWebapps(instance)
	if err != nil {
		return wrapAppsError(err)
	}

	objs := make([]jsonapi.Object, len(docs))
	for i, d := range docs {
		d.Instance = instance
		objs[i] = jsonapi.Object(d)
	}

	return jsonapi.DataList(c, http.StatusOK, objs, nil)
}

// iconHandler gives the icon of an application
func iconHandler(c echo.Context) error {
	instance := middlewares.GetInstance(c)
	slug := c.Param("slug")
	app, err := apps.GetWebappBySlug(instance, slug)
	if err != nil {
		return err
	}

	if err = permissions.Allow(c, permissions.GET, app); err != nil {
		return err
	}

	filepath := path.Join(vfs.WebappsDirName, slug, app.Icon)
	file, err := instance.VFS().FileByPath(filepath)
	if err != nil {
		return err
	}

	r, err := instance.VFS().OpenFile(file)
	if err != nil {
		return err
	}
	defer r.Close()
	http.ServeContent(c.Response(), c.Request(), filepath, time.Time{}, r)
	return nil
}

// WebappsRoutes sets the routing for the web apps service
func WebappsRoutes(router *echo.Group) {
	router.GET("/", listHandler)
	router.POST("/:slug", installHandler(apps.Webapp))
	router.PUT("/:slug", updateHandler(apps.Webapp))
	router.DELETE("/:slug", deleteHandler(apps.Webapp))
	router.GET("/:slug/icon", iconHandler)
}

// KonnectorRoutes sets the routing for the konnectors service
func KonnectorRoutes(router *echo.Group) {
	router.POST("/:slug", installHandler(apps.Konnector))
	router.PUT("/:slug", updateHandler(apps.Konnector))
	router.DELETE("/:slug", deleteHandler(apps.Konnector))
}

func wrapAppsError(err error) error {
	switch err {
	case apps.ErrInvalidSlugName:
		return jsonapi.InvalidParameter("slug", err)
	case apps.ErrAlreadyExists:
		return jsonapi.Conflict(err)
	case apps.ErrNotFound:
		return jsonapi.NotFound(err)
	case apps.ErrNotSupportedSource:
		return jsonapi.InvalidParameter("Source", err)
	case apps.ErrManifestNotReachable:
		return jsonapi.NotFound(err)
	case apps.ErrSourceNotReachable:
		return jsonapi.BadRequest(err)
	case apps.ErrBadManifest:
		return jsonapi.BadRequest(err)
	case apps.ErrMissingSource:
		return jsonapi.BadRequest(err)
	}
	if _, ok := err.(*url.Error); ok {
		return jsonapi.InvalidParameter("Source", err)
	}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"log"
	"strconv"
	"time"

	"github.com/brotherlogic/goserver"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildmaster/proto"
	pbs "github.com/brotherlogic/gobuildslave/proto"
)

const (
	intentWait = 1000
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	config  *pb.Config
	serving bool
}

type mainChecker struct{}

func getIP(servertype, servername string) (string, int) {
	conn, _ := grpc.Dial("192.168.86.34:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	r, err := registry.ListAllServices(context.Background(), &pbd.Empty{})
	if err != nil {
		return "", -1
	}
	for _, s := range r.Services {
		log.Printf("Does %v = %v and %v = %v?", s.Name, servertype, s.Identifier, servername)
		if s.Name == servertype && s.Identifier == servername {
			return s.Ip, int(s.Port)
		}
	}

	return "", -1
}

func (t *mainChecker) assess(server string) *pbs.JobList {
	list := &pbs.JobList{}

	ip, port := getIP("gobuildslave", server)
	conn, _ := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
	defer conn.Close()

	slave := pbs.NewGoBuildSlaveClient(conn)
	r, err := slave.List(context.Background(), &pbs.Empty{})
	if err == nil {
		return r
	}

	return list
}

func runJob(job *pbs.JobSpec) {
	log.Printf("RUNNING: %v", job)
	ip, port := getIP("gobuildslave", job.Server)
	conn, _ := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
	defer conn.Close()

	slave := pbs.NewGoBuildSlaveClient(conn)
	slave.Run(context.Background(), job)
}

func (t *mainChecker) discover() *pbd.ServiceList {
	ret := &pbd.ServiceList{}

	conn, _ := grpc.Dial("192.168.86.34:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	r, err := registry.ListAllServices(context.Background(), &pbd.Empty{})
	if err == nil {
		for _, s := range r.Services {
			ret.Services = append(ret.Services, s)
		}
	}

	return ret
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	// Do nothing
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

func getConfig(c checker) *pb.Config {
	list := getFleetStatus(c)
	config := &pb.Config{}

	for _, jlist := range list {
		for _, job := range jlist.Details {
			found := false
			for _, ij := range config.Intents {
				if job.Spec.Name == ij.Spec.Name {
					ij.Masters++
					found = true
				}
			}

			if !found {
				config.Intents = append(config.Intents, &pb.Intent{Spec: &pbs.JobSpec{Name: job.Spec.Name}, Masters: 1})
			}
		}
	}

	return config
}

// MatchIntent tries to match the intent with the state of production
func (s Server) MatchIntent() {
	//for s.serving {
	time.Sleep(intentWait)

	state := getConfig(&mainChecker{})
	diff := configDiff(s.config, state)
	joblist := runJobs(diff)
	for _, job := range joblist {
		runJob(job)
	}
	//}
}

func main() {
	config, err := loadConfig("config.pb")
	if err != nil {
		log.Fatalf("Fatal loading of config: %v", err)
	}

	var sync = flag.Bool("once", true, "One pass intent match")
	s := Server{&goserver.GoServer{}, config, true}
	if *sync {
		s.MatchIntent()
	} else {
		s.Register = s
		s.PrepServer()
		s.RegisterServer("gobuildmaster", false)
		s.Serve()
	}
}
<commit_msg>Added some logging<commit_after>package main

import (
	"context"
	"flag"
	"log"
	"strconv"
	"time"

	"github.com/brotherlogic/goserver"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildmaster/proto"
	pbs "github.com/brotherlogic/gobuildslave/proto"
)

const (
	intentWait = 1000
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	config  *pb.Config
	serving bool
}

type mainChecker struct{}

func getIP(servertype, servername string) (string, int) {
	conn, _ := grpc.Dial("192.168.86.34:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	r, err := registry.ListAllServices(context.Background(), &pbd.Empty{})
	if err != nil {
		return "", -1
	}
	for _, s := range r.Services {
		log.Printf("Does %v = %v and %v = %v?", s.Name, servertype, s.Identifier, servername)
		if s.Name == servertype && s.Identifier == servername {
			return s.Ip, int(s.Port)
		}
	}

	return "", -1
}

func (t *mainChecker) assess(server string) *pbs.JobList {
	list := &pbs.JobList{}

	ip, port := getIP("gobuildslave", server)
	conn, _ := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
	defer conn.Close()

	slave := pbs.NewGoBuildSlaveClient(conn)
	r, err := slave.List(context.Background(), &pbs.Empty{})
	if err == nil {
		return r
	}

	return list
}

func runJob(job *pbs.JobSpec) {
	log.Printf("RUNNING: %v", job)
	ip, port := getIP("gobuildslave", job.Server)
	conn, _ := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
	defer conn.Close()

	slave := pbs.NewGoBuildSlaveClient(conn)
	slave.Run(context.Background(), job)
}

func (t *mainChecker) discover() *pbd.ServiceList {
	ret := &pbd.ServiceList{}

	conn, _ := grpc.Dial("192.168.86.34:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	r, err := registry.ListAllServices(context.Background(), &pbd.Empty{})
	if err == nil {
		for _, s := range r.Services {
			ret.Services = append(ret.Services, s)
		}
	}

	return ret
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	// Do nothing
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

func getConfig(c checker) *pb.Config {
	list := getFleetStatus(c)
	config := &pb.Config{}

	for _, jlist := range list {
		for _, job := range jlist.Details {
			found := false
			for _, ij := range config.Intents {
				if job.Spec.Name == ij.Spec.Name {
					ij.Masters++
					found = true
				}
			}

			if !found {
				config.Intents = append(config.Intents, &pb.Intent{Spec: &pbs.JobSpec{Name: job.Spec.Name}, Masters: 1})
			}
		}
	}

	return config
}

// MatchIntent tries to match the intent with the state of production
func (s Server) MatchIntent() {
	//for s.serving {
	time.Sleep(intentWait)

	state := getConfig(&mainChecker{})
	diff := configDiff(s.config, state)
	joblist := runJobs(diff)
	log.Printf("FOUND %v from %v and %v", joblist, state, diff)
	for _, job := range joblist {
		runJob(job)
	}
	//}
}

func main() {
	config, err := loadConfig("config.pb")
	if err != nil {
		log.Fatalf("Fatal loading of config: %v", err)
	}

	var sync = flag.Bool("once", true, "One pass intent match")
	s := Server{&goserver.GoServer{}, config, true}
	if *sync {
		s.MatchIntent()
	} else {
		s.Register = s
		s.PrepServer()
		s.RegisterServer("gobuildmaster", false)
		s.Serve()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strings"

	"github.com/ivotron/aver"
	"github.com/spf13/cobra"
)

var dbConfig string
var dataFile string
var fileType string

func main() {

	var cmd = &cobra.Command{
		Use:   "aver [OPTIONS] \"<statement(s)>\"",
		Short: "Aver helps you automatically validate assertions on data",
		Long:  ``,
		Run:   Execute,
	}

	cmd.Flags().StringVarP(&dbConfig, "dbconf", "c", "", `Name of file
			containing database configuration. Format is JSON where only top-level
			elements are considered. See http://github.com/ivotron/aver for supported
			drivers and configuration examples.`)
	cmd.Flags().StringVarP(&dataFile, "input", "i", "", `File to read data from.
			Format is inferred from file extension ('csv' and 'json' supported). 'csv'
			is assumed for files without extension`)

	cmd.Execute()
}

func Execute(cmd *cobra.Command, args []string) {
	if dataFile != "" && dbConfig != "" {
		log.Fatal("ERROR: Only one two options 'dbconf' and 'input' allowed.")
	}
	if len(args) > 1 {
		log.Fatal("ERROR: Expecting one double-quoted string as argument.")
	}
	if strings.HasSuffix(dataFile, ".json") {
		fileType = "json"
		log.Fatal("ERROR: JSON not supported yet.")
	} else {
		fileType = "csv"
	}

	if dbConfig != "" {
		dataFile = dbConfig
		fileType = "config"
	}

	db, tblName, err := aver.MakeDb(dataFile, fileType)
	if err != nil {
		log.Fatal("ERROR: " + err.Error())
	}

	holds, err := aver.Holds(args[0], db, tblName)
	if err != nil {
		log.Fatal("ERROR: " + err.Error())
	}

	db.Close()

	if !holds {
		os.Exit(1)
	}
}
<commit_msg>Fixes main so it prints usage() correctly<commit_after>package main

import (
	"log"
	"os"
	"strings"

	"github.com/ivotron/aver"
	"github.com/spf13/cobra"
)

var dbConfig string
var dataFile string
var fileType string

func main() {

	var cmd = &cobra.Command{
		Use:   "aver \"<statement(s)>\"",
		Short: "Aver helps you automatically validate assertions on data",
		Long:  ``,
		Run:   Execute,
	}

	cmd.Flags().StringVarP(&dbConfig, "dbconf", "c", "", `Name of file containing
			database configuration. Format is JSON where only top-level elements are
			considered. See http://github.com/ivotron/aver for supported drivers and
			configuration examples.`)
	cmd.Flags().StringVarP(&dataFile, "input", "i", "", `File to read data from.
			Format is inferred from file extension. 'csv' and 'json' supported; 'csv'
			is assumed for files without extension.`)

	cmd.Execute()
}

func Execute(cmd *cobra.Command, args []string) {
	if len(args) == 0 {
		log.Fatalln(cmd.UsageString())
	}
	if dataFile != "" && dbConfig != "" {
		log.Fatalln("ERROR: Options 'dbconf' and 'input' cannot be used simultaneously.")
	}
	if len(args) != 1 {
		log.Fatalln("ERROR: Expecting one double-quoted string as argument.")
	}
	if strings.HasSuffix(dataFile, ".json") {
		fileType = "json"
		log.Fatalln("ERROR: JSON not supported yet.")
	} else {
		fileType = "csv"
	}

	if dbConfig != "" {
		dataFile = dbConfig
		fileType = "config"
	}

	db, tblName, err := aver.MakeDb(dataFile, fileType)
	if err != nil {
		log.Fatalln("ERROR: " + err.Error())
	}

	holds, err := aver.Holds(args[0], db, tblName)
	if err != nil {
		log.Fatalln("ERROR: " + err.Error())
	}

	db.Close()

	if !holds {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package web

var (
	layoutTemplate = `
{{define "layout"}}

		<title>Micro Web</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
		<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap" rel="stylesheet">

		{{ template "head" . }}

                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navBar">

                </button>
                 Micro

Client

Services

	          {{if .StatsURL}}
Stats
{{end}}

                {{ template "heading" . }}
                {{ template "content" . }}

	  {{template "script" . }}

{{end}}
{{ define "style" }}.search, .service { border-radius: 100px; }; {{end}}
{{ define "head" }}{{end}}
{{ define "script" }}{{end}}
{{ define "title" }}{{end}}
{{ define "heading" }}

{{end}}
`

	indexTemplate = `
{{define "heading"}}
<input class="form-control input-lg search" type=text placeholder="Search"/>
{{end}}
{{define "style" }}
.service {
	margin: 5px 3px 5px 3px;
	padding: 20px;
	text-align: center;
	display: block;
}
.search { border-radius: 100px; }
{{end}}
{{define "title"}}Web{{end}}
{{define "content"}}
	{{if .Results.HasWebServices}}

			{{range .Results.WebServices}}

{{.Name}}

			{{end}}

	{{end}}
{{end}}
{{define "script"}}

{{end}}
`
	callTemplate = `
{{define "title"}}Call{{end}}
{{define "style"}}
	pre {
		word-wrap: break-word;
		border: 0;
	}
	.form-control {
		border: 1px solid whitesmoke;
	}
{{end}}
{{define "content"}}

		<form id="call-form" onsubmit="return call();">

				Service

					<select class="form-control" type=text name=service id=service>
					<option disabled selected> -- select a service -- </option>
					{{range $key, $value := .Results}}
					<option class = "list-group-item" value="{{$key}}">{{$key}}</option>
					{{end}}
					</select>

				Endpoint

					<select class="form-control" type=text name=endpoint id=endpoint>
					<option disabled selected> -- select an endpoint -- </option>
					</select>

				Other Endpoint

					<input class="form-control" type=text name=otherendpoint id=otherendpoint disabled placeholder="Endpoint"/>

				Request
				<textarea class="form-control" name=request id=request rows=8>{}</textarea>

				<button class="btn btn-default" style="border-color: whitesmoke;">Execute</button>

		</form>

ResponseCopy

{}

{{end}}
{{define "script"}}

{{end}}
`
	registryTemplate = `
{{define "heading"}}
<input class="form-control input-lg search" type=text placeholder="Search"/>
{{end}}
{{define "title"}}Services{{end}}
{{define "content"}}

	{{range .Results}}

	    {{.Name}}

	{{end}}
{{end}}
{{define "script"}}

{{end}}
`

	serviceTemplate = `
{{define "title"}}Service{{end}}
{{define "heading"}}
{{with $svc := index .Results 0}}{{$svc.Name}}{{end}}
{{end}}
{{define "style"}}
.table>tbody>tr>th, .table>tbody>tr>td {
    border-top: none;
}
pre {border: 0; padding: 20px;}
{{end}}
{{define "content"}}

Nodes

	{{range .Results}}

Version {{.Version}}

			Id
			Address
			Metadata

			{{range .Nodes}}

				{{.Id}}
				{{.Address}}
				{{ range $key, $value := .Metadata }}{{$key}}={{$value}} {{end}}

			{{end}}

	{{end}}
	{{with $svc := index .Results 0}}
	{{if $svc.Endpoints}}

Endpoints

	{{end}}
	{{range $svc.Endpoints}}

{{.Name}}

				{{if .Metadata}}

					Metadata
					{{ range $key, $value := .Metadata }}{{$key}}={{$value}} {{end}}

				{{end}}

					Request

{{format .Request}}

					Response

{{format .Response}}

	{{end}}
	{{end}}
{{end}}

`
)
<commit_msg>take inspiration from ben on search bar (#580)<commit_after>package web

var (
	layoutTemplate = `
{{define "layout"}}

		<title>Micro Web</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
		<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap" rel="stylesheet">

		{{ template "head" . }}

                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navBar">

                </button>
                 Micro

Client

Services

	          {{if .StatsURL}}
Stats
{{end}}

                {{ template "heading" . }}
                {{ template "content" . }}

	  {{template "script" . }}

{{end}}
{{ define "style" }}
.service { border-radius: 100px; }
.search {
  border-radius: 0;
  border: 0;
  box-shadow: none;
  border-bottom: 1px solid whitesmoke;
}
.search:focus {
  border-color: transparent;
  outline: 0;
  box-shadow: none;
  border-bottom: 1px solid whitesmoke;
}
{{end}}
{{ define "head" }}{{end}}
{{ define "script" }}{{end}}
{{ define "title" }}{{end}}
{{ define "heading" }}

{{end}}
`

	indexTemplate = `
{{define "heading"}}
<input class="form-control input-lg search" type=text placeholder="Search" autofocus>
{{end}}
{{define "style" }}
.search {
  border-radius: 0;
  border: 0;
  box-shadow: none;
  border-bottom: 1px solid whitesmoke;
}
.search:focus {
  border-color: transparent;
  outline: 0;
  box-shadow: none;
  border-bottom: 1px solid whitesmoke;
}
.service {
	margin: 5px 3px 5px 3px;
	padding: 20px;
	text-align: center;
	display: block;
}
.search { border-radius: 100px; }
{{end}}
{{define "title"}}Web{{end}}
{{define "content"}}
	{{if .Results.HasWebServices}}

			{{range .Results.WebServices}}

{{.Name}}

			{{end}}

	{{end}}
{{end}}
{{define "script"}}

{{end}}
`
	callTemplate = `
{{define "title"}}Call{{end}}
{{define "style"}}
	pre {
		word-wrap: break-word;
		border: 0;
	}
	.form-control {
		border: 1px solid whitesmoke;
	}
{{end}}
{{define "content"}}

		<form id="call-form" onsubmit="return call();">

				Service

					<select class="form-control" type=text name=service id=service>
					<option disabled selected> -- select a service -- </option>
					{{range $key, $value := .Results}}
					<option class = "list-group-item" value="{{$key}}">{{$key}}</option>
					{{end}}
					</select>

				Endpoint

					<select class="form-control" type=text name=endpoint id=endpoint>
					<option disabled selected> -- select an endpoint -- </option>
					</select>

				Other Endpoint

					<input class="form-control" type=text name=otherendpoint id=otherendpoint disabled placeholder="Endpoint"/>

				Request
				<textarea class="form-control" name=request id=request rows=8>{}</textarea>

				<button class="btn btn-default" style="border-color: whitesmoke;">Execute</button>

		</form>

ResponseCopy

{}

{{end}}
{{define "script"}}

{{end}}
`
	registryTemplate = `
{{define "heading"}}
<input class="form-control input-lg search" type=text placeholder="Search" autofocus>
{{end}}
{{define "title"}}Services{{end}}
{{define "content"}}

	{{range .Results}}

	    {{.Name}}

	{{end}}
{{end}}
{{define "script"}}

{{end}}
`

	serviceTemplate = `
{{define "title"}}Service{{end}}
{{define "heading"}}
{{with $svc := index .Results 0}}{{$svc.Name}}{{end}}
{{end}}
{{define "style"}}
.table>tbody>tr>th, .table>tbody>tr>td {
    border-top: none;
}
pre {border: 0; padding: 20px;}
{{end}}
{{define "content"}}

Nodes

	{{range .Results}}

Version {{.Version}}

			Id
			Address
			Metadata

			{{range .Nodes}}

				{{.Id}}
				{{.Address}}
				{{ range $key, $value := .Metadata }}{{$key}}={{$value}} {{end}}

			{{end}}

	{{end}}
	{{with $svc := index .Results 0}}
	{{if $svc.Endpoints}}

Endpoints

	{{end}}
	{{range $svc.Endpoints}}

{{.Name}}

				{{if .Metadata}}

					Metadata
					{{ range $key, $value := .Metadata }}{{$key}}={{$value}} {{end}}

				{{end}}

					Request

{{format .Request}}

					Response

{{format .Response}}

	{{end}}
	{{end}}
{{end}}

`
)
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/go-sql-driver/mysql"
	sf "gitlab.alipay-inc.com/Arc/sqlflow/sql"
)

// readStmt reads a SQL statement from the scanner.  A statement could
// have multiple lines and ends at a semicolon at theend of the last
// line.
func readStmt(scn *bufio.Scanner) string {
	stmt := ""
	for scn.Scan() {
		stmt += scn.Text() + "\n"
		if strings.HasSuffix(strings.TrimSpace(scn.Text()), ";") {
			break
		}
	}
	return stmt
}

func displayHead(head map[string]interface{}) {
	cn, ok := head["columnNames"]
	if !ok {
		fmt.Print("ERROR: can't find field columnNames in head")
	}
	cols, ok := cn.([]string)
	if !ok {
		fmt.Print("ERROR: invalid header type")
	}
	for _, ele := range cols {
		fmt.Printf("%15s", ele)
	}
	fmt.Println()
}

func displayRow(row []interface{}) {
	for _, ele := range row {
		fmt.Printf("%15v", ele)
	}
	fmt.Println()
}

func display(rsp interface{}) {
	switch s := rsp.(type) {
	case map[string]interface{}:
		displayHead(s)
	case []interface{}:
		displayRow(s)
	case error:
		fmt.Printf("ERROR: %v\n", s)
	default:
		fmt.Println(s)
	}
}

func main() {
	user := flag.String("db_user", "", "database user name")
	pswd := flag.String("db_password", "", "database user password")
	addr := flag.String("db_address", "", "database address, such as: localhost:3306")
	flag.Parse()

	cfg := &mysql.Config{
		User:   *user,
		Passwd: *pswd,
		Net:    "tcp",
		Addr:   *addr,
	}
	db, err := sf.Open("mysql", cfg.FormatDSN())
	if err != nil {
		log.Fatalf("failed to open database: %v", err)
	}
	defer db.Close()
	if err := db.Ping(); err != nil {
		log.Fatalf("failed to ping database: %v", err)
	}

	scn := bufio.NewScanner(os.Stdin)
	for {
		fmt.Print("sqlflow> ")
		slct := readStmt(scn)
		fmt.Println("-----------------------------")

		stream := sf.Run(slct, db)
		for rsp := range stream.ReadAll() {
			display(rsp)
		}
	}
}
<commit_msg>render a table in demo<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/go-sql-driver/mysql"
	tablewriter "github.com/olekukonko/tablewriter"
	sf "gitlab.alipay-inc.com/Arc/sqlflow/sql"
)

const TABLE_PAGE_SIZE = 1000

// readStmt reads a SQL statement from the scanner.  A statement could
// have multiple lines and ends at a semicolon at theend of the last
// line.
func readStmt(scn *bufio.Scanner) string {
	stmt := ""
	for scn.Scan() {
		stmt += scn.Text() + "\n"
		if strings.HasSuffix(strings.TrimSpace(scn.Text()), ";") {
			break
		}
	}
	return stmt
}

func header(head map[string]interface{}) ([]string, error) {
	cn, ok := head["columnNames"]
	if !ok {
		return nil, fmt.Errorf("can't find field columnNames in head")
	}
	cols, ok := cn.([]string)
	if !ok {
		return nil, fmt.Errorf("invalid header type")
	}
	return cols, nil
}

func render(rsp interface{}, isTable *bool, table *tablewriter.Table) {
	switch s := rsp.(type) {
	case map[string]interface{}: // table header
		*isTable = true
		cols, e := header(s)
		if e == nil {
			table.SetHeader(cols)
		}
	case []interface{}: // row
		row := make([]string, len(s))
		for i, v := range s {
			row[i] = fmt.Sprint(v)
		}
		table.Append(row)
	case error:
		fmt.Printf("ERROR: %v\n", s)
	default:
		fmt.Println(s)
	}
}

func main() {
	user := flag.String("db_user", "", "database user name")
	pswd := flag.String("db_password", "", "database user password")
	addr := flag.String("db_address", "", "database address, such as: localhost:3306")
	flag.Parse()

	cfg := &mysql.Config{
		User:   *user,
		Passwd: *pswd,
		Net:    "tcp",
		Addr:   *addr,
	}
	db, err := sf.Open("mysql", cfg.FormatDSN())
	if err != nil {
		log.Fatalf("failed to open database: %v", err)
	}
	defer db.Close()
	if err := db.Ping(); err != nil {
		log.Fatalf("failed to ping database: %v", err)
	}

	scn := bufio.NewScanner(os.Stdin)
	for {
		fmt.Print("sqlflow> ")
		slct := readStmt(scn)
		fmt.Println("-----------------------------")

		isTable := false
		tableReadered := false
		table := tablewriter.NewWriter(os.Stdout)

		stream := sf.Run(slct, db)
		for rsp := range stream.ReadAll() {
			render(rsp, &isTable, table)

			// pagination. avoid exceed memory
			if isTable && table.NumLines() == TABLE_PAGE_SIZE {
				table.Render()
				tableReadered = true
				table.ClearRows()
			}
		}
		if isTable && (table.NumLines() > 0 || !tableReadered) {
			table.Render()
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/golang/dep"
	"github.com/golang/dep/gps"
	"github.com/golang/dep/gps/verify"
	"github.com/pkg/errors"
)

const checkShortHelp = `Check if imports, Gopkg.toml, and Gopkg.lock are in sync`
const checkLongHelp = `
Check determines if your project is in a good state. If problems are found, it
prints a description of each issue, then exits 1. Passing -q suppresses output.

Flags control which specific checks will be run. By default, dep check verifies
that Gopkg.lock is in sync with Gopkg.toml and the imports in your project's .go
files, and that the vendor directory is in sync with Gopkg.lock. These checks
can be disabled with -skip-lock and -skip-vendor, respectively.

(See https://golang.github.io/dep/docs/ensure-mechanics.html#staying-in-sync for
more information on what it means to be "in sync.")
`

type checkCommand struct {
	quiet                bool
	skiplock, skipvendor bool
}

func (cmd *checkCommand) Name() string { return "check" }
func (cmd *checkCommand) Args() string {
	return "[-q] [-skip-lock] [-skip-vendor]"
}
func (cmd *checkCommand) ShortHelp() string { return checkShortHelp }
func (cmd *checkCommand) LongHelp() string  { return checkLongHelp }
func (cmd *checkCommand) Hidden() bool      { return false }

func (cmd *checkCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.skiplock, "skip-lock", false, "Skip checking that imports and Gopkg.toml are in sync with Gopkg.lock")
	fs.BoolVar(&cmd.skipvendor, "skip-vendor", false, "Skip checking that vendor is in sync with Gopkg.lock")
	fs.BoolVar(&cmd.quiet, "q", false, "Suppress non-error output")
}

func (cmd *checkCommand) Run(ctx *dep.Ctx, args []string) error {
	logger := ctx.Out
	if cmd.quiet {
		logger = log.New(ioutil.Discard, "", 0)
	}

	p, err := ctx.LoadProject()
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}

	sm.UseDefaultSignalHandling()
	defer sm.Release()

	var fail bool
	if !cmd.skiplock {
		if p.Lock == nil {
			return errors.New("Gopkg.lock does not exist, cannot check it against imports and Gopkg.toml")
		}

		lsat := verify.LockSatisfiesInputs(p.Lock, p.Manifest, p.RootPackageTree)
		delta := verify.DiffLocks(p.Lock, p.ChangedLock)
		sat, changed := lsat.Satisfied(), delta.Changed(verify.PruneOptsChanged|verify.HashVersionChanged)

		if changed || !sat {
			fail = true
			logger.Println("# Gopkg.lock is out of sync:")
			if !sat {
				logger.Printf("%s\n", sprintLockUnsat(lsat))
			}
			if changed {
				for pr, lpd := range delta.ProjectDeltas {
					// Only two possible changes right now are prune opts
					// changing or a missing hash digest (for old Gopkg.lock
					// files)
					if lpd.PruneOptsChanged() {
						// Override what's on the lockdiff with the extra info we have;
						// this lets us excise PruneNestedVendorDirs and get the real
						// value from the input param in place.
						old := lpd.PruneOptsBefore & ^gps.PruneNestedVendorDirs
						new := lpd.PruneOptsAfter & ^gps.PruneNestedVendorDirs
						logger.Printf("%s: prune options changed (%s -> %s)\n", pr, old, new)
					}
					if lpd.HashVersionWasZero() {
						logger.Printf("%s: no hash digest in lock\n", pr)
					}
				}
			}
		}
	}

	if !cmd.skipvendor {
		if p.Lock == nil {
			return errors.New("Gopkg.lock does not exist, cannot check vendor against it")
		}

		statuses, err := p.VerifyVendor()
		if err != nil {
			return errors.Wrap(err, "error while verifying vendor")
		}

		if fail {
			logger.Println()
		}
		// One full pass through, to see if we need to print the header.
		for _, status := range statuses {
			if status != verify.NoMismatch {
				fail = true
				logger.Println("# vendor is out of sync:")
				break
			}
		}

		for pr, status := range statuses {
			switch status {
			case verify.NotInTree:
				logger.Printf("%s: missing from vendor\n", pr)
			case verify.NotInLock:
				fi, err := os.Stat(filepath.Join(p.AbsRoot, "vendor", pr))
				if err != nil {
					return errors.Wrap(err, "could not stat file that VerifyVendor claimed existed")
				}

				if fi.IsDir() {
					logger.Printf("%s: unused project\n", pr)
				} else {
					logger.Printf("%s: orphaned file\n", pr)
				}
			case verify.DigestMismatchInLock:
				logger.Printf("%s: hash of vendored tree didn't match digest in Gopkg.lock\n", pr)
			case verify.HashVersionMismatch:
				// This will double-print if the hash version is zero, but
				// that's a rare case that really only occurs before the first
				// run with a version of dep >=0.5.0, so it's fine.
				logger.Printf("%s: hash algorithm mismatch, want version %v\n", pr, verify.HashVersion)
			}
		}
	}

	if fail {
		return silentfail{}
	}
	return nil
}

func sprintLockUnsat(lsat verify.LockSatisfaction) string {
	var buf bytes.Buffer
	for _, missing := range lsat.MissingImports {
		fmt.Fprintf(&buf, "%s: missing from input-imports\n", missing)
	}
	for _, excess := range lsat.ExcessImports {
		fmt.Fprintf(&buf, "%s: in input-imports, but not imported\n", excess)
	}
	for pr, unmatched := range lsat.UnmetOverrides {
		fmt.Fprintf(&buf, "%s@%s: not allowed by override %s\n", pr, unmatched.V, unmatched.C)
	}
	for pr, unmatched := range lsat.UnmetConstraints {
		fmt.Fprintf(&buf, "%s@%s: not allowed by constraint %s\n", pr, unmatched.V, unmatched.C)
	}
	return strings.TrimSpace(buf.String())
}
<commit_msg>dep: Add license header to check.go<commit_after>// Copyright 2018 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 file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/golang/dep"
	"github.com/golang/dep/gps"
	"github.com/golang/dep/gps/verify"
	"github.com/pkg/errors"
)

const checkShortHelp = `Check if imports, Gopkg.toml, and Gopkg.lock are in sync`
const checkLongHelp = `
Check determines if your project is in a good state. If problems are found, it
prints a description of each issue, then exits 1. Passing -q suppresses output.

Flags control which specific checks will be run. By default, dep check verifies
that Gopkg.lock is in sync with Gopkg.toml and the imports in your project's .go
files, and that the vendor directory is in sync with Gopkg.lock. These checks
can be disabled with -skip-lock and -skip-vendor, respectively.

(See https://golang.github.io/dep/docs/ensure-mechanics.html#staying-in-sync for
more information on what it means to be "in sync.")
`

type checkCommand struct {
	quiet                bool
	skiplock, skipvendor bool
}

func (cmd *checkCommand) Name() string { return "check" }
func (cmd *checkCommand) Args() string {
	return "[-q] [-skip-lock] [-skip-vendor]"
}
func (cmd *checkCommand) ShortHelp() string { return checkShortHelp }
func (cmd *checkCommand) LongHelp() string  { return checkLongHelp }
func (cmd *checkCommand) Hidden() bool      { return false }

func (cmd *checkCommand) Register(fs *flag.FlagSet) {
	fs.BoolVar(&cmd.skiplock, "skip-lock", false, "Skip checking that imports and Gopkg.toml are in sync with Gopkg.lock")
	fs.BoolVar(&cmd.skipvendor, "skip-vendor", false, "Skip checking that vendor is in sync with Gopkg.lock")
	fs.BoolVar(&cmd.quiet, "q", false, "Suppress non-error output")
}

func (cmd *checkCommand) Run(ctx *dep.Ctx, args []string) error {
	logger := ctx.Out
	if cmd.quiet {
		logger = log.New(ioutil.Discard, "", 0)
	}

	p, err := ctx.LoadProject()
	if err != nil {
		return err
	}

	sm, err := ctx.SourceManager()
	if err != nil {
		return err
	}

	sm.UseDefaultSignalHandling()
	defer sm.Release()

	var fail bool
	if !cmd.skiplock {
		if p.Lock == nil {
			return errors.New("Gopkg.lock does not exist, cannot check it against imports and Gopkg.toml")
		}

		lsat := verify.LockSatisfiesInputs(p.Lock, p.Manifest, p.RootPackageTree)
		delta := verify.DiffLocks(p.Lock, p.ChangedLock)
		sat, changed := lsat.Satisfied(), delta.Changed(verify.PruneOptsChanged|verify.HashVersionChanged)

		if changed || !sat {
			fail = true
			logger.Println("# Gopkg.lock is out of sync:")
			if !sat {
				logger.Printf("%s\n", sprintLockUnsat(lsat))
			}
			if changed {
				for pr, lpd := range delta.ProjectDeltas {
					// Only two possible changes right now are prune opts
					// changing or a missing hash digest (for old Gopkg.lock
					// files)
					if lpd.PruneOptsChanged() {
						// Override what's on the lockdiff with the extra info we have;
						// this lets us excise PruneNestedVendorDirs and get the real
						// value from the input param in place.
						old := lpd.PruneOptsBefore & ^gps.PruneNestedVendorDirs
						new := lpd.PruneOptsAfter & ^gps.PruneNestedVendorDirs
						logger.Printf("%s: prune options changed (%s -> %s)\n", pr, old, new)
					}
					if lpd.HashVersionWasZero() {
						logger.Printf("%s: no hash digest in lock\n", pr)
					}
				}
			}
		}
	}

	if !cmd.skipvendor {
		if p.Lock == nil {
			return errors.New("Gopkg.lock does not exist, cannot check vendor against it")
		}

		statuses, err := p.VerifyVendor()
		if err != nil {
			return errors.Wrap(err, "error while verifying vendor")
		}

		if fail {
			logger.Println()
		}
		// One full pass through, to see if we need to print the header.
		for _, status := range statuses {
			if status != verify.NoMismatch {
				fail = true
				logger.Println("# vendor is out of sync:")
				break
			}
		}

		for pr, status := range statuses {
			switch status {
			case verify.NotInTree:
				logger.Printf("%s: missing from vendor\n", pr)
			case verify.NotInLock:
				fi, err := os.Stat(filepath.Join(p.AbsRoot, "vendor", pr))
				if err != nil {
					return errors.Wrap(err, "could not stat file that VerifyVendor claimed existed")
				}

				if fi.IsDir() {
					logger.Printf("%s: unused project\n", pr)
				} else {
					logger.Printf("%s: orphaned file\n", pr)
				}
			case verify.DigestMismatchInLock:
				logger.Printf("%s: hash of vendored tree didn't match digest in Gopkg.lock\n", pr)
			case verify.HashVersionMismatch:
				// This will double-print if the hash version is zero, but
				// that's a rare case that really only occurs before the first
				// run with a version of dep >=0.5.0, so it's fine.
				logger.Printf("%s: hash algorithm mismatch, want version %v\n", pr, verify.HashVersion)
			}
		}
	}

	if fail {
		return silentfail{}
	}
	return nil
}

func sprintLockUnsat(lsat verify.LockSatisfaction) string {
	var buf bytes.Buffer
	for _, missing := range lsat.MissingImports {
		fmt.Fprintf(&buf, "%s: missing from input-imports\n", missing)
	}
	for _, excess := range lsat.ExcessImports {
		fmt.Fprintf(&buf, "%s: in input-imports, but not imported\n", excess)
	}
	for pr, unmatched := range lsat.UnmetOverrides {
		fmt.Fprintf(&buf, "%s@%s: not allowed by override %s\n", pr, unmatched.V, unmatched.C)
	}
	for pr, unmatched := range lsat.UnmetConstraints {
		fmt.Fprintf(&buf, "%s@%s: not allowed by constraint %s\n", pr, unmatched.V, unmatched.C)
	}
	return strings.TrimSpace(buf.String())
}
<|endoftext|>


<commit_before>/*
Copyright The Helm Authors.

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

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

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

package main

import (
	"fmt"
	"io"
	"os"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"

	"k8s.io/helm/cmd/helm/require"
	"k8s.io/helm/pkg/getter"
	"k8s.io/helm/pkg/helm/helmpath"
	"k8s.io/helm/pkg/repo"
)

const initDesc = `
This command sets up local configuration in $HELM_HOME (default ~/.helm/).
`

const (
	stableRepository           = "stable"
	defaultStableRepositoryURL = "https://kubernetes-charts.storage.googleapis.com"
)

type initOptions struct {
	skipRefresh         bool   // --skip-refresh
	stableRepositoryURL string // --stable-repo-url

	home helmpath.Home
}

func newInitCmd(out io.Writer) *cobra.Command {
	o := &initOptions{}

	cmd := &cobra.Command{
		Use:   "init",
		Short: "initialize Helm client",
		Long:  initDesc,
		Args:  require.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			o.home = settings.Home
			return o.run(out)
		},
	}

	f := cmd.Flags()
	f.BoolVar(&o.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache")
	f.StringVar(&o.stableRepositoryURL, "stable-repo-url", defaultStableRepositoryURL, "URL for stable repository")

	return cmd
}

// run initializes local config.
func (o *initOptions) run(out io.Writer) error {
	if err := ensureDirectories(o.home, out); err != nil {
		return err
	}
	if err := ensureDefaultRepos(o.home, out, o.skipRefresh, o.stableRepositoryURL); err != nil {
		return err
	}
	if err := ensureRepoFileFormat(o.home.RepositoryFile(), out); err != nil {
		return err
	}
	fmt.Fprintf(out, "$HELM_HOME has been configured at %s.\n", settings.Home)
	fmt.Fprintln(out, "Happy Helming!")
	return nil
}

// ensureDirectories checks to see if $HELM_HOME exists.
//
// If $HELM_HOME does not exist, this function will create it.
func ensureDirectories(home helmpath.Home, out io.Writer) error {
	configDirectories := []string{
		home.String(),
		home.Repository(),
		home.Cache(),
		home.Plugins(),
		home.Starters(),
		home.Archive(),
	}
	for _, p := range configDirectories {
		if fi, err := os.Stat(p); err != nil {
			fmt.Fprintf(out, "Creating %s \n", p)
			if err := os.MkdirAll(p, 0755); err != nil {
				return errors.Wrapf(err, "could not create %s", p)
			}
		} else if !fi.IsDir() {
			return errors.Errorf("%s must be a directory", p)
		}
	}

	return nil
}

func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool, url string) error {
	repoFile := home.RepositoryFile()
	if fi, err := os.Stat(repoFile); err != nil {
		fmt.Fprintf(out, "Creating %s \n", repoFile)
		f := repo.NewRepoFile()
		sr, err := initRepo(url, home.CacheIndex(stableRepository), out, skipRefresh, home)
		if err != nil {
			return err
		}
		f.Add(sr)
		if err := f.WriteFile(repoFile, 0644); err != nil {
			return err
		}
	} else if fi.IsDir() {
		return errors.Errorf("%s must be a file, not a directory", repoFile)
	}
	return nil
}

func initRepo(url, cacheFile string, out io.Writer, skipRefresh bool, home helmpath.Home) (*repo.Entry, error) {
	fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, url)
	c := repo.Entry{
		Name:  stableRepository,
		URL:   url,
		Cache: cacheFile,
	}
	r, err := repo.NewChartRepository(&c, getter.All(settings))
	if err != nil {
		return nil, err
	}

	if skipRefresh {
		return &c, nil
	}

	// In this case, the cacheFile is always absolute. So passing empty string
	// is safe.
	if err := r.DownloadIndexFile(""); err != nil {
		return nil, errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", url)
	}

	return &c, nil
}

func ensureRepoFileFormat(file string, out io.Writer) error {
	r, err := repo.LoadRepositoriesFile(file)
	if err == repo.ErrRepoOutOfDate {
		fmt.Fprintln(out, "Updating repository file format...")
		if err := r.WriteFile(file, 0644); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>fix missing formatting character error in wrapf statement (#4881)<commit_after>/*
Copyright The Helm Authors.

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

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

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

package main

import (
	"fmt"
	"io"
	"os"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"

	"k8s.io/helm/cmd/helm/require"
	"k8s.io/helm/pkg/getter"
	"k8s.io/helm/pkg/helm/helmpath"
	"k8s.io/helm/pkg/repo"
)

const initDesc = `
This command sets up local configuration in $HELM_HOME (default ~/.helm/).
`

const (
	stableRepository           = "stable"
	defaultStableRepositoryURL = "https://kubernetes-charts.storage.googleapis.com"
)

type initOptions struct {
	skipRefresh         bool   // --skip-refresh
	stableRepositoryURL string // --stable-repo-url

	home helmpath.Home
}

func newInitCmd(out io.Writer) *cobra.Command {
	o := &initOptions{}

	cmd := &cobra.Command{
		Use:   "init",
		Short: "initialize Helm client",
		Long:  initDesc,
		Args:  require.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			o.home = settings.Home
			return o.run(out)
		},
	}

	f := cmd.Flags()
	f.BoolVar(&o.skipRefresh, "skip-refresh", false, "do not refresh (download) the local repository cache")
	f.StringVar(&o.stableRepositoryURL, "stable-repo-url", defaultStableRepositoryURL, "URL for stable repository")

	return cmd
}

// run initializes local config.
func (o *initOptions) run(out io.Writer) error {
	if err := ensureDirectories(o.home, out); err != nil {
		return err
	}
	if err := ensureDefaultRepos(o.home, out, o.skipRefresh, o.stableRepositoryURL); err != nil {
		return err
	}
	if err := ensureRepoFileFormat(o.home.RepositoryFile(), out); err != nil {
		return err
	}
	fmt.Fprintf(out, "$HELM_HOME has been configured at %s.\n", settings.Home)
	fmt.Fprintln(out, "Happy Helming!")
	return nil
}

// ensureDirectories checks to see if $HELM_HOME exists.
//
// If $HELM_HOME does not exist, this function will create it.
func ensureDirectories(home helmpath.Home, out io.Writer) error {
	configDirectories := []string{
		home.String(),
		home.Repository(),
		home.Cache(),
		home.Plugins(),
		home.Starters(),
		home.Archive(),
	}
	for _, p := range configDirectories {
		if fi, err := os.Stat(p); err != nil {
			fmt.Fprintf(out, "Creating %s \n", p)
			if err := os.MkdirAll(p, 0755); err != nil {
				return errors.Wrapf(err, "could not create %s", p)
			}
		} else if !fi.IsDir() {
			return errors.Errorf("%s must be a directory", p)
		}
	}

	return nil
}

func ensureDefaultRepos(home helmpath.Home, out io.Writer, skipRefresh bool, url string) error {
	repoFile := home.RepositoryFile()
	if fi, err := os.Stat(repoFile); err != nil {
		fmt.Fprintf(out, "Creating %s \n", repoFile)
		f := repo.NewRepoFile()
		sr, err := initRepo(url, home.CacheIndex(stableRepository), out, skipRefresh, home)
		if err != nil {
			return err
		}
		f.Add(sr)
		if err := f.WriteFile(repoFile, 0644); err != nil {
			return err
		}
	} else if fi.IsDir() {
		return errors.Errorf("%s must be a file, not a directory", repoFile)
	}
	return nil
}

func initRepo(url, cacheFile string, out io.Writer, skipRefresh bool, home helmpath.Home) (*repo.Entry, error) {
	fmt.Fprintf(out, "Adding %s repo with URL: %s \n", stableRepository, url)
	c := repo.Entry{
		Name:  stableRepository,
		URL:   url,
		Cache: cacheFile,
	}
	r, err := repo.NewChartRepository(&c, getter.All(settings))
	if err != nil {
		return nil, err
	}

	if skipRefresh {
		return &c, nil
	}

	// In this case, the cacheFile is always absolute. So passing empty string
	// is safe.
	if err := r.DownloadIndexFile(""); err != nil {
		return nil, errors.Wrapf(err, "%s is not a valid chart repository or cannot be reached", url)
	}

	return &c, nil
}

func ensureRepoFileFormat(file string, out io.Writer) error {
	r, err := repo.LoadRepositoriesFile(file)
	if err == repo.ErrRepoOutOfDate {
		fmt.Fprintln(out, "Updating repository file format...")
		if err := r.WriteFile(file, 0644); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>