<commit_before>package rules

import (
	"fmt"
	"github.com/golang/protobuf/v2/proto"
	descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
)

func protoDescriptorProtoFromSource(source string) (*descriptorpb.FileDescriptorProto, error) {
	tmpDir := os.TempDir()

	f, err := ioutil.TempFile(tmpDir, "proto*")

	if err != nil {
		return nil, err
	}

	defer func() {
		if err := closeAndRemoveFile(f); err != nil {
			log.Fatalf("Error removing proto file: %v", err)
		}
	}()

	if _, err = f.WriteString(source); err != nil {
		return nil, err
	}

	descSetF, err := ioutil.TempFile(tmpDir, "descset*")

	if err != nil {
		return nil, err
	}

	defer func() {
		if err := closeAndRemoveFile(descSetF); err != nil {
			log.Fatalf("Error removing descriptor set file: %v", err)
		}
	}()

	cmd := exec.Command(
		"protoc",
		"--include_source_info",
		fmt.Sprintf("--proto_path=%s", tmpDir),
		fmt.Sprintf("--descriptor_set_out=%s", descSetF.Name()),
		f.Name(),
	)

	cmd.Stderr = os.Stderr

	if err = cmd.Run(); err != nil {
		return nil, err
	}

	descSet, err := ioutil.ReadFile(descSetF.Name())

	if err != nil {
		return nil, err
	}

	protoset := &descriptorpb.FileDescriptorSet{}
	if err := proto.Unmarshal(descSet, protoset); err != nil {
		return nil, err
	}

	if len(protoset.GetFile()) == 0 {
		return nil, fmt.Errorf("protoset file list was empty")
	}

	return protoset.GetFile()[0], nil
}

func closeAndRemoveFile(f *os.File) error {
	if err := f.Close(); err != nil {
		return err
	}

	if err := os.Remove(f.Name()); err != nil {
		return err
	}

	return nil
}
<commit_msg>Capturing and returning stderr<commit_after>package rules

import (
	"bytes"
	"fmt"
	"github.com/golang/protobuf/v2/proto"
	descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
)

func protoDescriptorProtoFromSource(source string) (*descriptorpb.FileDescriptorProto, error) {
	tmpDir := os.TempDir()

	f, err := ioutil.TempFile(tmpDir, "proto*")

	if err != nil {
		return nil, err
	}

	defer func() {
		if err := closeAndRemoveFile(f); err != nil {
			log.Fatalf("Error removing proto file: %v", err)
		}
	}()

	if _, err = f.WriteString(source); err != nil {
		return nil, err
	}

	descSetF, err := ioutil.TempFile(tmpDir, "descset*")

	if err != nil {
		return nil, err
	}

	defer func() {
		if err := closeAndRemoveFile(descSetF); err != nil {
			log.Fatalf("Error removing descriptor set file: %v", err)
		}
	}()

	cmd := exec.Command(
		"protoc",
		"--include_source_info",
		fmt.Sprintf("--proto_path=%s", tmpDir),
		fmt.Sprintf("--descriptor_set_out=%s", descSetF.Name()),
		f.Name(),
	)

	var stdErrBuf bytes.Buffer

	cmd.Stderr = &stdErrBuf

	if err = cmd.Run(); err != nil {
		return nil, fmt.Errorf("protoc failed with %v and Stderr %q", err, stdErrBuf.String())
	}

	descSet, err := ioutil.ReadFile(descSetF.Name())

	if err != nil {
		return nil, err
	}

	protoset := &descriptorpb.FileDescriptorSet{}
	if err := proto.Unmarshal(descSet, protoset); err != nil {
		return nil, err
	}

	if len(protoset.GetFile()) == 0 {
		return nil, fmt.Errorf("protoset file list was empty")
	}

	return protoset.GetFile()[0], nil
}

func closeAndRemoveFile(f *os.File) error {
	if err := f.Close(); err != nil {
		return err
	}

	if err := os.Remove(f.Name()); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package ssh

import (
	"log"
	"os"
	"strings"

	"code.google.com/p/go.crypto/ssh"
	"github.com/dynport/urknall"
)

var debugger = log.New(os.Stderr, "", 0)

type Host struct {
	Address  string
	Password string

	address string
	port    int
	user    string

	client *ssh.Client
}

func (host *Host) parseAddress() {
	if host.port > 0 {
		return
	}
	hostAndPort := strings.Split(host.Address, ":")
	var addr string
	if len(hostAndPort) == 2 {
		addr = hostAndPort[0]
	} else {
		host.port = 22
		addr = host.Address
	}
	userAndAddress := strings.Split(addr, "@")
	if len(userAndAddress) == 2 {
		host.user = userAndAddress[0]
		host.address = userAndAddress[1]
	} else {
		host.user = "root"
		host.address = addr
	}

}

func (host *Host) User() string {
	host.parseAddress()
	parts := strings.Split(host.Address, "@")
	if len(parts) == 2 {
		return parts[0]
	}
	return "root"
}

type SshClient interface {
	Client() (*ssh.Client, error)
}

func (c *Host) Client() (*ssh.Client, error) {
	var e error
	config := &ssh.ClientConfig{
		User: c.User(),
	}
	if c.Password != "" {
		config.Auth = append(config.Auth, ssh.Password(c.Password))
	}
	addr := c.Address
	if !strings.Contains(addr, ":") {
		addr += ":22"
	}
	debugger.Printf("connecting %q with %#v", addr, config)
	con, e := ssh.Dial("tcp", addr, config)
	if e != nil {
		return nil, e
	}
	return &ssh.Client{Conn: con}, nil
}

func (c *Host) Command(cmd string) (urknall.Command, error) {
	if c.client == nil {
		var e error
		c.client, e = c.Client()
		if e != nil {
			return nil, e
		}
	}
	ses, e := c.client.NewSession()
	if e != nil {
		return nil, e
	}
	return &Command{command: cmd, session: ses}, nil
}
<commit_msg>fix connecting for ssh commanders<commit_after>package ssh

import (
	"fmt"
	"log"
	"os"
	"strings"

	"code.google.com/p/go.crypto/ssh"
	"github.com/dynport/urknall"
)

var debugger = log.New(os.Stderr, "", 0)

type Host struct {
	Address  string
	Password string

	address string
	port    int
	user    string

	client *ssh.Client
}

func (host *Host) User() string {
	host.parseAddress()
	return host.user
}

func (host *Host) parseAddress() {
	if host.port > 0 {
		return
	}
	hostAndPort := strings.Split(host.Address, ":")
	var addr string
	if len(hostAndPort) == 2 {
		addr = hostAndPort[0]
	} else {
		host.port = 22
		addr = host.Address
	}
	userAndAddress := strings.Split(addr, "@")
	if len(userAndAddress) == 2 {
		host.user = userAndAddress[0]
		host.address = userAndAddress[1]
	} else {
		host.user = "root"
		host.address = addr
	}

}

type SshClient interface {
	Client() (*ssh.Client, error)
}

func (c *Host) Client() (*ssh.Client, error) {
	c.parseAddress()
	var e error
	config := &ssh.ClientConfig{
		User: c.user,
	}
	if c.Password != "" {
		config.Auth = append(config.Auth, ssh.Password(c.Password))
	}
	debugger.Printf("connecting %q with %#v", c.address, config)
	con, e := ssh.Dial("tcp", fmt.Sprintf("%s:%d", c.address, c.port), config)
	if e != nil {
		return nil, e
	}
	return &ssh.Client{Conn: con}, nil
}

func (c *Host) Command(cmd string) (urknall.Command, error) {
	if c.client == nil {
		var e error
		c.client, e = c.Client()
		if e != nil {
			return nil, e
		}
	}
	ses, e := c.client.NewSession()
	if e != nil {
		return nil, e
	}
	return &Command{command: cmd, session: ses}, nil
}
<|endoftext|>


<commit_before>package air

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"net/http"
	"reflect"
	"strconv"
	"strings"
)

// binder is used to provide a `bind()` method for an `Air` instance
// for binds a HTTP request body into privided type.
type binder struct {
	air *Air
}

// newBinder returns a new instance of `binder`.
func newBinder(a *Air) *binder {
	return &binder{
		air: a,
	}
}

// bind binds the HTTP request body into provided type i based on
// "Content-Type" header.
func (b *binder) bind(i interface{}, c *Context) (err error) {
	req := c.Request
	if req.Method() == GET {
		if err = b.bindData(i, c.QueryParams()); err != nil {
			err = NewHTTPError(http.StatusBadRequest, err.Error())
		}
		return
	}
	ctype := req.Header.Get(HeaderContentType)
	if req.Body() == nil {
		err = NewHTTPError(http.StatusBadRequest, "Request Body Can't Be Empty")
		return
	}
	err = ErrUnsupportedMediaType
	switch {
	case strings.HasPrefix(ctype, MIMEApplicationJSON):
		if err = json.NewDecoder(req.Body()).Decode(i); err != nil {
			err = NewHTTPError(http.StatusBadRequest, err.Error())
		}
	case strings.HasPrefix(ctype, MIMEApplicationXML):
		if err = xml.NewDecoder(req.Body()).Decode(i); err != nil {
			err = NewHTTPError(http.StatusBadRequest, err.Error())
		}
	case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
		if err = b.bindData(i, req.FormParams()); err != nil {
			err = NewHTTPError(http.StatusBadRequest, err.Error())
		}
	}
	return
}

// bindData binds the data into a type ptr.
func (b *binder) bindData(ptr interface{}, data map[string][]string) error {
	typ := reflect.TypeOf(ptr).Elem()
	val := reflect.ValueOf(ptr).Elem()

	if typ.Kind() != reflect.Struct {
		return errors.New("Binding Element Must Be A Struct")
	}

	for i := 0; i < typ.NumField(); i++ {
		typeField := typ.Field(i)
		structField := val.Field(i)
		if !structField.CanSet() {
			continue
		}
		structFieldKind := structField.Kind()
		inputFieldName := typeField.Tag.Get("form")

		if inputFieldName == "" {
			inputFieldName = typeField.Name
			// If "form" tag is nil, we inspect if the field is a struct.
			if structFieldKind == reflect.Struct {
				err := b.bindData(structField.Addr().Interface(), data)
				if err != nil {
					return err
				}
				continue
			}
		}
		inputValue, exists := data[inputFieldName]
		if !exists {
			continue
		}

		numElems := len(inputValue)
		if structFieldKind == reflect.Slice && numElems > 0 {
			sliceOf := structField.Type().Elem().Kind()
			slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
			for i := 0; i < numElems; i++ {
				if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
					return err
				}
			}
			val.Field(i).Set(slice)
		} else {
			if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
				return err
			}
		}
	}
	return nil
}

// setWithProperType sets the val into a structField with a proper valueKind.
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
	bitSize := 0
	switch valueKind {
	case reflect.Int8, reflect.Uint8:
		bitSize = 8
	case reflect.Int16, reflect.Uint16:
		bitSize = 16
	case reflect.Int32, reflect.Uint32, reflect.Float32:
		bitSize = 32
	case reflect.Int64, reflect.Uint64, reflect.Float64:
		bitSize = 64
	}

	switch valueKind {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return setIntField(val, bitSize, structField)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return setUintField(val, bitSize, structField)
	case reflect.Bool:
		return setBoolField(val, structField)
	case reflect.Float32, reflect.Float64:
		return setFloatField(val, bitSize, structField)
	case reflect.String:
		structField.SetString(val)
	default:
		return errors.New("Unknown Type")
	}
	return nil
}

// setIntField sets the value into a field with a provided bitSize.
func setIntField(value string, bitSize int, field reflect.Value) error {
	if value == "" {
		value = "0"
	}
	intVal, err := strconv.ParseInt(value, 10, bitSize)
	if err == nil {
		field.SetInt(intVal)
	}
	return err
}

// setUintField sets the value into a field with a provided bitSize.
func setUintField(value string, bitSize int, field reflect.Value) error {
	if value == "" {
		value = "0"
	}
	uintVal, err := strconv.ParseUint(value, 10, bitSize)
	if err == nil {
		field.SetUint(uintVal)
	}
	return err
}

// setBoolField sets the value into a field.
func setBoolField(value string, field reflect.Value) error {
	if value == "" {
		value = "false"
	}
	boolVal, err := strconv.ParseBool(value)
	if err == nil {
		field.SetBool(boolVal)
	}
	return err
}

// setFloatField sets the value into a field with a provided bitSize.
func setFloatField(value string, bitSize int, field reflect.Value) error {
	if value == "" {
		value = "0.0"
	}
	floatVal, err := strconv.ParseFloat(value, bitSize)
	if err == nil {
		field.SetFloat(floatVal)
	}
	return err
}
<commit_msg>refactor: improve JSON and XML in `binder#bind()`<commit_after>package air

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"net/http"
	"reflect"
	"strconv"
	"strings"
)

// binder is used to provide a `bind()` method for an `Air` instance
// for binds a HTTP request body into privided type.
type binder struct {
	air *Air
}

// newBinder returns a new instance of `binder`.
func newBinder(a *Air) *binder {
	return &binder{
		air: a,
	}
}

// bind binds the HTTP request body into provided type i based on
// "Content-Type" header.
func (b *binder) bind(i interface{}, c *Context) (err error) {
	req := c.Request
	if req.Method() == GET {
		if err = b.bindData(i, c.QueryParams()); err != nil {
			err = NewHTTPError(http.StatusBadRequest, err.Error())
		}
		return
	}
	ctype := req.Header.Get(HeaderContentType)
	if req.Body() == nil {
		err = NewHTTPError(http.StatusBadRequest, "Request Body Can't Be Empty")
		return
	}
	err = ErrUnsupportedMediaType
	switch {
	case strings.HasPrefix(ctype, MIMEApplicationJSON):
		if err = json.NewDecoder(req.Body()).Decode(i); err != nil {
			if ute, ok := err.(*json.UnmarshalTypeError); ok {
				err = NewHTTPError(http.StatusBadRequest, fmt.Sprintf(
					"Unmarshal Type Error: expected=%v, got=%v, offset=%v",
					ute.Type, ute.Value, ute.Offset))
			} else if se, ok := err.(*json.SyntaxError); ok {
				err = NewHTTPError(http.StatusBadRequest, fmt.Sprintf(
					"Syntax Error: offset=%v, error=%v",
					se.Offset, se.Error()))
			} else {
				err = NewHTTPError(http.StatusBadRequest, err.Error())
			}
		}
	case strings.HasPrefix(ctype, MIMEApplicationXML):
		if err = xml.NewDecoder(req.Body()).Decode(i); err != nil {
			if ute, ok := err.(*xml.UnsupportedTypeError); ok {
				err = NewHTTPError(http.StatusBadRequest, fmt.Sprintf(
					"Unsupported Type Error: type=%v, error=%v",
					ute.Type, ute.Error()))
			} else if se, ok := err.(*xml.SyntaxError); ok {
				err = NewHTTPError(http.StatusBadRequest, fmt.Sprintf(
					"Syntax Error: line=%v, error=%v",
					se.Line, se.Error()))
			} else {
				err = NewHTTPError(http.StatusBadRequest, err.Error())
			}
		}
	case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
		if err = b.bindData(i, req.FormParams()); err != nil {
			err = NewHTTPError(http.StatusBadRequest, err.Error())
		}
	}
	return
}

// bindData binds the data into a type ptr.
func (b *binder) bindData(ptr interface{}, data map[string][]string) error {
	typ := reflect.TypeOf(ptr).Elem()
	val := reflect.ValueOf(ptr).Elem()

	if typ.Kind() != reflect.Struct {
		return errors.New("Binding Element Must Be A Struct")
	}

	for i := 0; i < typ.NumField(); i++ {
		typeField := typ.Field(i)
		structField := val.Field(i)
		if !structField.CanSet() {
			continue
		}
		structFieldKind := structField.Kind()
		inputFieldName := typeField.Tag.Get("form")

		if inputFieldName == "" {
			inputFieldName = typeField.Name
			// If "form" tag is nil, we inspect if the field is a struct.
			if structFieldKind == reflect.Struct {
				err := b.bindData(structField.Addr().Interface(), data)
				if err != nil {
					return err
				}
				continue
			}
		}
		inputValue, exists := data[inputFieldName]
		if !exists {
			continue
		}

		numElems := len(inputValue)
		if structFieldKind == reflect.Slice && numElems > 0 {
			sliceOf := structField.Type().Elem().Kind()
			slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
			for i := 0; i < numElems; i++ {
				if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
					return err
				}
			}
			val.Field(i).Set(slice)
		} else {
			if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
				return err
			}
		}
	}
	return nil
}

// setWithProperType sets the val into a structField with a proper valueKind.
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
	bitSize := 0
	switch valueKind {
	case reflect.Int8, reflect.Uint8:
		bitSize = 8
	case reflect.Int16, reflect.Uint16:
		bitSize = 16
	case reflect.Int32, reflect.Uint32, reflect.Float32:
		bitSize = 32
	case reflect.Int64, reflect.Uint64, reflect.Float64:
		bitSize = 64
	}

	switch valueKind {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return setIntField(val, bitSize, structField)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return setUintField(val, bitSize, structField)
	case reflect.Bool:
		return setBoolField(val, structField)
	case reflect.Float32, reflect.Float64:
		return setFloatField(val, bitSize, structField)
	case reflect.String:
		structField.SetString(val)
	default:
		return errors.New("Unknown Type")
	}
	return nil
}

// setIntField sets the value into a field with a provided bitSize.
func setIntField(value string, bitSize int, field reflect.Value) error {
	if value == "" {
		value = "0"
	}
	intVal, err := strconv.ParseInt(value, 10, bitSize)
	if err == nil {
		field.SetInt(intVal)
	}
	return err
}

// setUintField sets the value into a field with a provided bitSize.
func setUintField(value string, bitSize int, field reflect.Value) error {
	if value == "" {
		value = "0"
	}
	uintVal, err := strconv.ParseUint(value, 10, bitSize)
	if err == nil {
		field.SetUint(uintVal)
	}
	return err
}

// setBoolField sets the value into a field.
func setBoolField(value string, field reflect.Value) error {
	if value == "" {
		value = "false"
	}
	boolVal, err := strconv.ParseBool(value)
	if err == nil {
		field.SetBool(boolVal)
	}
	return err
}

// setFloatField sets the value into a field with a provided bitSize.
func setFloatField(value string, bitSize int, field reflect.Value) error {
	if value == "" {
		value = "0.0"
	}
	floatVal, err := strconv.ParseFloat(value, bitSize)
	if err == nil {
		field.SetFloat(floatVal)
	}
	return err
}
<|endoftext|>


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

package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// bundleCmd represents the bundle command
var bundleCmd = &cobra.Command{
	Use:   "bundle",
	Short: "Manage plugin bundles",
	Long: `This module lets you manage Tyk plugin bundles.`,
	Run: func(cmd *cobra.Command, args []string) {
		// TODO: Work your own magic here
		fmt.Println("bundle called")
	},
}

func init() {
	RootCmd.AddCommand(bundleCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// bundleCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// bundleCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}
<commit_msg>When bundle is called with no commands, print information.<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"github.com/spf13/cobra"
)

// bundleCmd represents the bundle command
var bundleCmd = &cobra.Command{
	Use:   "bundle",
	Short: "Manage plugin bundles",
	Long: `This module lets you manage Tyk plugin bundles.`,
	Run: func(cmd *cobra.Command, args []string) {
		cmd.Usage()
	},
}

func init() {
	RootCmd.AddCommand(bundleCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// bundleCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// bundleCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"github.com/aquasecurity/kube-bench/check"
	"github.com/fatih/color"
	"github.com/spf13/viper"
)

var (
	kubeMasterBin  = []string{"kube-apiserver", "kube-scheduler", "kube-controller-manager"}
	kubeMasterConf = []string{}

	kubeNodeBin  = []string{"kubelet"}
	kubeNodeConf = []string{}

	kubeFederatedBin  = []string{"federation-apiserver", "federation-controller-manager"}
	kubeFederatedConf = []string{}

	// TODO: Consider specifying this in config file.
	kubeVersion = "Kubernetes v1.6"

	// Used for variable substitution
	symbols = map[string]string{}

	// Print colors
	colors = map[check.State]*color.Color{
		check.PASS: color.New(color.FgGreen),
		check.FAIL: color.New(color.FgRed),
		check.WARN: color.New(color.FgYellow),
		check.INFO: color.New(color.FgBlue),
	}
)

func runChecks(t check.NodeType) {
	var summary check.Summary
	var file string

	// Set up for config file check.
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/apiserver")
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/scheduler")
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/controller-manager")
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/config")
	kubeMasterConf = append(kubeMasterConf, viper.Get("etcdConfDir").(string)+"/etcd.conf")
	kubeMasterConf = append(kubeMasterConf, viper.Get("flanneldConfDir").(string)+"/flanneld")
	kubeNodeConf = append(kubeNodeConf, viper.Get("kubeConfDir").(string)+"/kubelet")
	kubeNodeConf = append(kubeNodeConf, viper.Get("kubeConfDir").(string)+"/proxy")

	verifyNodeType(t)

	switch t {
	case check.MASTER:
		file = masterFile
	case check.NODE:
		file = nodeFile
	case check.FEDERATED:
		file = federatedFile
	}

	in, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error opening %s controls file: %s\n", t, err)
		os.Exit(1)
	}

	// Variable substitutions. Replace all occurrences of variables in controls file.
	s := strings.Replace(string(in), "$kubeConfDir", viper.Get("kubeConfDir").(string), -1)
	s = strings.Replace(s, "$etcdConfDir", viper.Get("etcdConfDir").(string), -1)
	s = strings.Replace(s, "$flanneldConfDir", viper.Get("flanneldConfDir").(string), -1)

	controls := check.NewControls(t, []byte(s))

	if groupList != "" && checkList == "" {
		// log.Println("group: set, checks: not set")
		ids := cleanIDs(groupList)
		summary = controls.RunGroup(ids...)

	} else if checkList != "" && groupList == "" {
		// log.Println("group: not set, checks: set")
		ids := cleanIDs(checkList)
		summary = controls.RunChecks(ids...)

	} else if checkList != "" && groupList != "" {
		// log.Println("group: set, checks: set")
		fmt.Fprintf(os.Stderr, "group option and check option can't be used together\n")
		os.Exit(1)

	} else {
		summary = controls.RunGroup()
	}

	if jsonFmt {
		out, err := controls.JSON()
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to output in JSON format: %v\n", err)
			os.Exit(1)
		}

		fmt.Println(string(out))
	} else {
		prettyPrint(controls, summary)
	}
}

func cleanIDs(list string) []string {
	list = strings.Trim(list, ",")
	ids := strings.Split(list, ",")

	for _, id := range ids {
		id = strings.Trim(id, " ")
	}

	return ids
}

func verifyNodeType(t check.NodeType) {
	var binPath []string
	var confPath []string
	var out []byte

	switch t {
	case check.MASTER:
		binPath = kubeMasterBin
		confPath = kubeMasterConf
	case check.NODE:
		binPath = kubeNodeBin
		confPath = kubeNodeConf
	case check.FEDERATED:
		binPath = kubeFederatedBin
		confPath = kubeFederatedConf
	}

	// These executables might not be on the user's path.
	// TODO! Check the version number using kubectl, which is more likely to be on the path.
	for _, b := range binPath {
		_, err := exec.LookPath(b)
		if err != nil {
			colorPrint(check.WARN, fmt.Sprintf("%s: command not found on path - version check skipped\n", b))
			continue
		}

		// Check version
		cmd := exec.Command(b, "--version")
		out, _ = cmd.Output()
		if matched, _ := regexp.MatchString(kubeVersion, string(out)); !matched {
			colorPrint(check.FAIL,
				fmt.Sprintf(
					"%s unsupported version, expected %s, got %s\n",
					b,
					kubeVersion,
					string(out),
				))
			os.Exit(1)
		}
	}

	for _, b := range binPath {
		// Check if running.
		cmd := exec.Command("ps", "-ef")
		out, _ = cmd.Output()
		if matched, _ := regexp.MatchString(".*"+b, string(out)); !matched {
			colorPrint(check.FAIL, fmt.Sprintf("%s is not running\n", b))
			os.Exit(1)
		}
	}

	for _, c := range confPath {
		if _, err := os.Stat(c); os.IsNotExist(err) {
			colorPrint(check.WARN, fmt.Sprintf("config file %s does not exist\n", c))
		}
	}
}

// colorPrint outputs the state in a specific colour, along with a message string
func colorPrint(state check.State, s string) {
	colors[state].Printf("[%s] ", state)
	fmt.Printf("%s", s)
}

func prettyPrint(r *check.Controls, summary check.Summary) {
	// Print checks and results.
	colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
	for _, g := range r.Groups {
		colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
		for _, c := range g.Checks {
			colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
		}
	}

	fmt.Println()

	// Print remediations.
	if summary.Fail > 0 || summary.Warn > 0 {
		colors[check.WARN].Printf("== Remediations ==\n")
		for _, g := range r.Groups {
			for _, c := range g.Checks {
				if c.State != check.PASS {
					fmt.Printf("%s %s\n", c.ID, c.Remediation)
				}
			}
		}
		fmt.Println()
	}

	// Print summary setting output color to highest severity.
	var res check.State
	if summary.Fail > 0 {
		res = check.FAIL
	} else if summary.Warn > 0 {
		res = check.WARN
	} else {
		res = check.PASS
	}

	colors[res].Printf("== Summary ==\n")
	fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n",
		summary.Pass, summary.Fail, summary.Warn,
	)
}
<commit_msg>Don’t output warnings as text if we’re generating JSON output. Add error handling in a few missing cases. Some comment tidying. <commit_after>// Copyright © 2017 Aqua Security Software Ltd. <info@aquasec.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"github.com/aquasecurity/kube-bench/check"
	"github.com/fatih/color"
	"github.com/spf13/viper"
)

var (
	kubeMasterBin  = []string{"kube-apiserver", "kube-scheduler", "kube-controller-manager"}
	kubeMasterConf = []string{}

	kubeNodeBin  = []string{"kubelet"}
	kubeNodeConf = []string{}

	kubeFederatedBin  = []string{"federation-apiserver", "federation-controller-manager"}
	kubeFederatedConf = []string{}

	// TODO: Consider specifying this in config file.
	kubeVersion = "Kubernetes v1.6"

	// Used for variable substitution
	symbols = map[string]string{}

	// Print colors
	colors = map[check.State]*color.Color{
		check.PASS: color.New(color.FgGreen),
		check.FAIL: color.New(color.FgRed),
		check.WARN: color.New(color.FgYellow),
		check.INFO: color.New(color.FgBlue),
	}
)

func runChecks(t check.NodeType) {
	var summary check.Summary
	var warnings []string
	var file string

	// Set up for config file check.
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/apiserver")
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/scheduler")
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/controller-manager")
	kubeMasterConf = append(kubeMasterConf, viper.Get("kubeConfDir").(string)+"/config")
	kubeMasterConf = append(kubeMasterConf, viper.Get("etcdConfDir").(string)+"/etcd.conf")
	kubeMasterConf = append(kubeMasterConf, viper.Get("flanneldConfDir").(string)+"/flanneld")
	kubeNodeConf = append(kubeNodeConf, viper.Get("kubeConfDir").(string)+"/kubelet")
	kubeNodeConf = append(kubeNodeConf, viper.Get("kubeConfDir").(string)+"/proxy")

	warnings, err := verifyNodeType(t, warnings)
	if err != nil {
		for _, w := range warnings {
			colorPrint(check.WARN, w)
		}

		fmt.Fprintf(os.Stderr, "failed to verify node type: %v\n", err)
		os.Exit(1)
	}

	switch t {
	case check.MASTER:
		file = masterFile
	case check.NODE:
		file = nodeFile
	case check.FEDERATED:
		file = federatedFile
	}

	in, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error opening %s controls file: %s\n", t, err)
		os.Exit(1)
	}

	// Variable substitutions. Replace all occurrences of variables in controls file.
	s := strings.Replace(string(in), "$kubeConfDir", viper.Get("kubeConfDir").(string), -1)
	s = strings.Replace(s, "$etcdConfDir", viper.Get("etcdConfDir").(string), -1)
	s = strings.Replace(s, "$flanneldConfDir", viper.Get("flanneldConfDir").(string), -1)

	controls := check.NewControls(t, []byte(s))

	if groupList != "" && checkList == "" {
		ids := cleanIDs(groupList)
		summary = controls.RunGroup(ids...)

	} else if checkList != "" && groupList == "" {
		ids := cleanIDs(checkList)
		summary = controls.RunChecks(ids...)

	} else if checkList != "" && groupList != "" {
		fmt.Fprintf(os.Stderr, "group option and check option can't be used together\n")
		os.Exit(1)

	} else {
		summary = controls.RunGroup()
	}

	// if we successfully ran some tests and it's json format, ignore the warnings
	if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0) && jsonFmt {
		out, err := controls.JSON()
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to output in JSON format: %v\n", err)
			os.Exit(1)
		}

		fmt.Println(string(out))
	} else {
		prettyPrint(warnings, controls, summary)
	}
}

func cleanIDs(list string) []string {
	list = strings.Trim(list, ",")
	ids := strings.Split(list, ",")

	for _, id := range ids {
		id = strings.Trim(id, " ")
	}

	return ids
}

// verifyNodeType checks the executables and config files are as expected for the specified tests (master, node or federated)
func verifyNodeType(t check.NodeType, w []string) ([]string, error) {
	var binPath []string
	var confPath []string
	var out []byte

	switch t {
	case check.MASTER:
		binPath = kubeMasterBin
		confPath = kubeMasterConf
	case check.NODE:
		binPath = kubeNodeBin
		confPath = kubeNodeConf
	case check.FEDERATED:
		binPath = kubeFederatedBin
		confPath = kubeFederatedConf
	}

	// These executables might not be on the user's path.
	// TODO! Check the version number using kubectl, which is more likely to be on the path.
	for _, b := range binPath {
		_, err := exec.LookPath(b)
		if err != nil {
			w = append(w, fmt.Sprintf("%s: command not found on path - version check skipped\n", b))
			continue
		}

		// Check version
		cmd := exec.Command(b, "--version")
		out, err = cmd.Output()
		if err != nil {
			return w, fmt.Errorf("failed executing %s --version: %v", b, err)
		}

		matched, err := regexp.MatchString(kubeVersion, string(out))
		if err != nil {
			return w, fmt.Errorf("regexp match for version failed: %v", err)
		}

		if !matched {
			return w, fmt.Errorf(
				"%s unsupported version, expected %s, got %s",
				b,
				kubeVersion,
				string(out),
			)
		}
	}

	// Check if the executables for this type of node are running.
	for _, b := range binPath {
		cmd := exec.Command("ps", "-ef")
		out, err := cmd.Output()
		if err != nil {
			return w, fmt.Errorf("failed executing ps -ef: %v", err)
		}

		matched, err := regexp.MatchString(".*"+b, string(out))
		if err != nil {
			return w, fmt.Errorf("regexp match for ps output failed: %v", err)
		}

		if !matched {
			return w, fmt.Errorf("%s is not running", b)
		}
	}

	// Check whether the config files for this type of node are in the expected location
	for _, c := range confPath {
		if _, err := os.Stat(c); os.IsNotExist(err) {
			w = append(w, fmt.Sprintf("config file %s does not exist\n", c))
		}
	}

	return w, nil
}

// colorPrint outputs the state in a specific colour, along with a message string
func colorPrint(state check.State, s string) {
	colors[state].Printf("[%s] ", state)
	fmt.Printf("%s", s)
}

// prettyPrint outputs the results to stdout in human-readable format
func prettyPrint(warnings []string, r *check.Controls, summary check.Summary) {
	for _, w := range warnings {
		colorPrint(check.WARN, w)
	}

	colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
	for _, g := range r.Groups {
		colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
		for _, c := range g.Checks {
			colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
		}
	}

	fmt.Println()

	// Print remediations.
	if summary.Fail > 0 || summary.Warn > 0 {
		colors[check.WARN].Printf("== Remediations ==\n")
		for _, g := range r.Groups {
			for _, c := range g.Checks {
				if c.State != check.PASS {
					fmt.Printf("%s %s\n", c.ID, c.Remediation)
				}
			}
		}
		fmt.Println()
	}

	// Print summary setting output color to highest severity.
	var res check.State
	if summary.Fail > 0 {
		res = check.FAIL
	} else if summary.Warn > 0 {
		res = check.WARN
	} else {
		res = check.PASS
	}

	colors[res].Printf("== Summary ==\n")
	fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n",
		summary.Pass, summary.Fail, summary.Warn,
	)
}
<|endoftext|>


<commit_before>// Simple utility for counting messages on a Kafka topic.
//
// Copyright (C) 2017 ENEO Tecnologia SL
// Author: Diego Fernández Barrear <bigomby@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"errors"
	"reflect"
	"strconv"

	"github.com/Sirupsen/logrus"

	yaml "gopkg.in/yaml.v2"
)

// AppConfig contains the main application configuration.
type AppConfig struct {
	Counters struct {
		BatchTimeoutSeconds uint   `yaml:"batch_timeout_s" default:"5"`
		BatchMaxMessages    uint   `yaml:"batch_max_messages" default:"1000"`
		UUIDKey             string `yaml:"uuid_key" mandatory:"true"`
		Kafka               struct {
			ReadTopics      []string          `yaml:"read_topics" mandatory:"true"`
			WriteTopic      string            `yaml:"write_topic" mandatory:"true"`
			Attributes      map[string]string `yaml:"attributes"`
			TopicAttributes map[string]string `yaml:"topic_attributes"`
		}
	}

	// Monitor struct {
	// 	Timer struct {
	// 		Period uint `yaml:"period" default:"86400"`
	// 		Offset uint `yaml:"offset" default:"0"`
	// 	}
	// 	Kafka struct {
	// 		ReadTopics      []string          `yaml:"read_topics"`
	// 		WriteTopic      string            `yaml:"write_topic"`
	// 		Attributes      map[string]string `yaml:"attributes"`
	// 		TopicAttributes map[string]string `yaml:"topic_attributes"`
	// 	}
	// }

	// Limits struct {
	// 	UUIDS []struct {
	// 		UUID      string `yaml:"uuid"`
	// 		LimitType string `yaml:"type"`
	// 		Limit     int    `yaml:"limit"`
	// 	}
	// }
}

// verify checks for fields with "mandatory" struc tag set to "true" and if
// the field does not have a value set will fail.
func (config *AppConfig) verify() error {
	values, fields := deepFields(config)

	for i := range fields {
		if !values[i].IsValid() {
			return errors.New("Invalid field")
		}

		if !values[i].CanSet() {
			return errors.New("Can't set field for " + fields[i].Name)
		}

		if tag := fields[i].Tag.Get("mandatory"); tag != "" {
			mandatory, err := strconv.ParseBool(tag)
			if err != nil {
				return errors.New("Invalid mandatory value " + tag)
			}

			if mandatory {
				switch values[i].Kind() {
				case reflect.String:
					if values[i].String() == "" {
						return errors.New("Field \"" + fields[i].Name + "\" must be provided")
					}

				case reflect.Int:
					if values[i].Int() == 0 {
						return errors.New("Field \"" + fields[i].Name + "\" must be provided")
					}

				case reflect.Uint:
					if values[i].Uint() == 0 {
						return errors.New("Field \"" + fields[i].Name + "\" must be provided")
					}
				}
			}
		}
	}

	return nil
}

// setDefaults looks for struct tags "default="<val>"" and set value of the fields
// to <val> if does not have a previous value.
func (config *AppConfig) setDefaults() error {
	values, fields := deepFields(config)

	for i := range fields {
		if !values[i].IsValid() {
			return errors.New("Invalid field")
		}

		if !values[i].CanSet() {
			return errors.New("Can't set field for " + fields[i].Name)
		}

		if tag := fields[i].Tag.Get("default"); tag != "" {
			setDefaultField(values[i], fields[i], tag)
		}
	}

	return nil
}

// ParseConfig parse a YAML formatted string and returns a AppConfig struct
// containing the parsed configuration.
func ParseConfig(raw []byte) (*AppConfig, error) {
	config := &AppConfig{}
	err := yaml.Unmarshal(raw, &config)
	if err != nil {
		return config, errors.New("Error: " + err.Error())
	}

	if err := config.setDefaults(); err != nil {
		logrus.Fatal("Error reading configuration: " + err.Error())
	}
	if err := config.verify(); err != nil {
		logrus.Fatal("Error reading configuration: " + err.Error())
	}

	return config, nil
}

func setDefaultField(v reflect.Value, t reflect.StructField, value string) {
	switch v.Kind().String() {
	case "int":
		if defaultValue, err := strconv.ParseInt(value, 10, 64); v.Int() == 0 && err == nil {
			logrus.Warnf("Defaulting \"%s\" to %d", t.Name, defaultValue)
			v.SetInt(defaultValue)
		}

	case "uint":
		if defaultValue, err := strconv.ParseUint(value, 10, 64); v.Uint() == 0 && err == nil {
			logrus.Warnf("Defaulting \"%s\" to %d", t.Name, defaultValue)
			v.SetUint(defaultValue)
		}

	case "string":
		if len(value) > 0 {
			logrus.Warnf("Defaulting \"%s\" to %s", t.Name, value)
			v.SetString(value)
		}

	default:
		logrus.Warnln(v.Kind().String())
	}
}

func deepFields(iface interface{}) ([]reflect.Value, []reflect.StructField) {
	values := make([]reflect.Value, 0)
	fields := make([]reflect.StructField, 0)

	elem := reflect.ValueOf(iface)
	for elem.Kind() == reflect.Ptr {
		elem = elem.Elem()
	}

	for i := 0; i < elem.NumField(); i++ {
		v := elem.Field(i)
		t := elem.Type().Field(i)

		switch v.Kind() {
		case reflect.Struct:
			nv, nf := deepFields(v.Addr().Interface())
			for _, value := range nv {
				values = append(values, value)
			}
			for _, field := range nf {
				fields = append(fields, field)
			}
		default:
			values = append(values, v)
			fields = append(fields, t)
		}
	}

	return values, fields
}
<commit_msg>:bug: Fix not mandatory param<commit_after>// Simple utility for counting messages on a Kafka topic.
//
// Copyright (C) 2017 ENEO Tecnologia SL
// Author: Diego Fernández Barrear <bigomby@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"errors"
	"reflect"
	"strconv"

	"github.com/Sirupsen/logrus"

	yaml "gopkg.in/yaml.v2"
)

// AppConfig contains the main application configuration.
type AppConfig struct {
	Counters struct {
		BatchTimeoutSeconds uint   `yaml:"batch_timeout_s" default:"5"`
		BatchMaxMessages    uint   `yaml:"batch_max_messages" default:"1000"`
		UUIDKey             string `yaml:"uuid_key"`
		Kafka               struct {
			ReadTopics      []string          `yaml:"read_topics" mandatory:"true"`
			WriteTopic      string            `yaml:"write_topic" mandatory:"true"`
			Attributes      map[string]string `yaml:"attributes"`
			TopicAttributes map[string]string `yaml:"topic_attributes"`
		}
	}

	// Monitor struct {
	// 	Timer struct {
	// 		Period uint `yaml:"period" default:"86400"`
	// 		Offset uint `yaml:"offset" default:"0"`
	// 	}
	// 	Kafka struct {
	// 		ReadTopics      []string          `yaml:"read_topics"`
	// 		WriteTopic      string            `yaml:"write_topic"`
	// 		Attributes      map[string]string `yaml:"attributes"`
	// 		TopicAttributes map[string]string `yaml:"topic_attributes"`
	// 	}
	// }

	// Limits struct {
	// 	UUIDS []struct {
	// 		UUID      string `yaml:"uuid"`
	// 		LimitType string `yaml:"type"`
	// 		Limit     int    `yaml:"limit"`
	// 	}
	// }
}

// verify checks for fields with "mandatory" struc tag set to "true" and if
// the field does not have a value set will fail.
func (config *AppConfig) verify() error {
	values, fields := deepFields(config)

	for i := range fields {
		if !values[i].IsValid() {
			return errors.New("Invalid field")
		}

		if !values[i].CanSet() {
			return errors.New("Can't set field for " + fields[i].Name)
		}

		if tag := fields[i].Tag.Get("mandatory"); tag != "" {
			mandatory, err := strconv.ParseBool(tag)
			if err != nil {
				return errors.New("Invalid mandatory value " + tag)
			}

			if mandatory {
				switch values[i].Kind() {
				case reflect.String:
					if values[i].String() == "" {
						return errors.New("Field \"" + fields[i].Name + "\" must be provided")
					}

				case reflect.Int:
					if values[i].Int() == 0 {
						return errors.New("Field \"" + fields[i].Name + "\" must be provided")
					}

				case reflect.Uint:
					if values[i].Uint() == 0 {
						return errors.New("Field \"" + fields[i].Name + "\" must be provided")
					}
				}
			}
		}
	}

	return nil
}

// setDefaults looks for struct tags "default="<val>"" and set value of the fields
// to <val> if does not have a previous value.
func (config *AppConfig) setDefaults() error {
	values, fields := deepFields(config)

	for i := range fields {
		if !values[i].IsValid() {
			return errors.New("Invalid field")
		}

		if !values[i].CanSet() {
			return errors.New("Can't set field for " + fields[i].Name)
		}

		if tag := fields[i].Tag.Get("default"); tag != "" {
			setDefaultField(values[i], fields[i], tag)
		}
	}

	return nil
}

// ParseConfig parse a YAML formatted string and returns a AppConfig struct
// containing the parsed configuration.
func ParseConfig(raw []byte) (*AppConfig, error) {
	config := &AppConfig{}
	err := yaml.Unmarshal(raw, &config)
	if err != nil {
		return config, errors.New("Error: " + err.Error())
	}

	if err := config.setDefaults(); err != nil {
		logrus.Fatal("Error reading configuration: " + err.Error())
	}
	if err := config.verify(); err != nil {
		logrus.Fatal("Error reading configuration: " + err.Error())
	}

	return config, nil
}

func setDefaultField(v reflect.Value, t reflect.StructField, value string) {
	switch v.Kind().String() {
	case "int":
		if defaultValue, err := strconv.ParseInt(value, 10, 64); v.Int() == 0 && err == nil {
			logrus.Warnf("Defaulting \"%s\" to %d", t.Name, defaultValue)
			v.SetInt(defaultValue)
		}

	case "uint":
		if defaultValue, err := strconv.ParseUint(value, 10, 64); v.Uint() == 0 && err == nil {
			logrus.Warnf("Defaulting \"%s\" to %d", t.Name, defaultValue)
			v.SetUint(defaultValue)
		}

	case "string":
		if len(value) > 0 {
			logrus.Warnf("Defaulting \"%s\" to %s", t.Name, value)
			v.SetString(value)
		}

	default:
		logrus.Warnln(v.Kind().String())
	}
}

func deepFields(iface interface{}) ([]reflect.Value, []reflect.StructField) {
	values := make([]reflect.Value, 0)
	fields := make([]reflect.StructField, 0)

	elem := reflect.ValueOf(iface)
	for elem.Kind() == reflect.Ptr {
		elem = elem.Elem()
	}

	for i := 0; i < elem.NumField(); i++ {
		v := elem.Field(i)
		t := elem.Type().Field(i)

		switch v.Kind() {
		case reflect.Struct:
			nv, nf := deepFields(v.Addr().Interface())
			for _, value := range nv {
				values = append(values, value)
			}
			for _, field := range nf {
				fields = append(fields, field)
			}
		default:
			values = append(values, v)
			fields = append(fields, t)
		}
	}

	return values, fields
}
<|endoftext|>


<commit_before>/* Copyright (c) 2016 Jason Ish
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"fmt"
	"github.com/jasonish/evebox/cmd/agent"
	"github.com/jasonish/evebox/cmd/config"
	"github.com/jasonish/evebox/cmd/esimport"
	"github.com/jasonish/evebox/cmd/evereader"
	"github.com/jasonish/evebox/cmd/gencert"
	"github.com/jasonish/evebox/cmd/oneshot"
	"github.com/jasonish/evebox/cmd/pgimport"
	"github.com/jasonish/evebox/cmd/server"
	"github.com/jasonish/evebox/cmd/sqliteimport"
	"github.com/jasonish/evebox/core"
	"github.com/jasonish/evebox/log"
	"os"
	"runtime"
)

func VersionMain() {
	fmt.Printf("EveBox Version %s (rev %s); os=%s, arch=%s\n",
		core.BuildVersion, core.BuildRev, runtime.GOOS, runtime.GOARCH)
}

func Usage() {
	usage := fmt.Sprintf(`Usage: %s <command> [options]

Commands:
	server			Start the EveBox server
	config                  Server configuration tool
	version			Print the EveBox version
	esimport		Run the Elastic Search Eve import tool
	evereader		Run the Eve log reader tool
	oneshot                 Run one time with an eve.json file
	gencert                 Generate TLS certificate

`, os.Args[0])
	fmt.Fprint(os.Stderr, usage)
}

func main() {

	// Look for sub-commands, then fall back to server.
	if len(os.Args) > 1 && os.Args[1][0] != '-' {
		switch os.Args[1] {
		case "version":
			VersionMain()
			return
		case "esimport":
			esimport.Main(os.Args[1:])
			return
		case "agent":
			agent.Main(os.Args[2:])
			return
		case "evereader":
			evereader.Main(os.Args[1:])
			return
		case "server":
			server.Main(os.Args[2:])
			return
		case "oneshot":
			oneshot.Main(os.Args[2:])
			return
		case "pgimport":
			pgimport.Main(os.Args[2:])
			return
		case "sqliteimport":
			sqliteimport.Main(os.Args[2:])
			return
		case "config":
			config.Main(os.Args[2:])
			return
		case "gencert":
			gencert.Main(os.Args[2:])
			return
		default:
			log.Fatalf("Unknown command: %s", os.Args[1])
		}
	} else if len(os.Args) > 1 {
		switch os.Args[1] {
		case "-h":
			Usage()
			os.Exit(0)
		}
	}

	log.Info("No command provided, defaulting to server.")
	server.Main(os.Args[1:])
}
<commit_msg>evebox: add agent to list of commands<commit_after>/* Copyright (c) 2016 Jason Ish
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"fmt"
	"github.com/jasonish/evebox/cmd/agent"
	"github.com/jasonish/evebox/cmd/config"
	"github.com/jasonish/evebox/cmd/esimport"
	"github.com/jasonish/evebox/cmd/evereader"
	"github.com/jasonish/evebox/cmd/gencert"
	"github.com/jasonish/evebox/cmd/oneshot"
	"github.com/jasonish/evebox/cmd/pgimport"
	"github.com/jasonish/evebox/cmd/server"
	"github.com/jasonish/evebox/cmd/sqliteimport"
	"github.com/jasonish/evebox/core"
	"github.com/jasonish/evebox/log"
	"os"
	"runtime"
)

func VersionMain() {
	fmt.Printf("EveBox Version %s (rev %s); os=%s, arch=%s\n",
		core.BuildVersion, core.BuildRev, runtime.GOOS, runtime.GOARCH)
}

func Usage() {
	usage := fmt.Sprintf(`Usage: %s <command> [options]

Commands:
    server          Start the EveBox server
    agent           Start the EveBox agent
    config          Server configuration tool
    version         Print the EveBox version
    esimport        Run the Elastic Search Eve import tool
    evereader       Run the Eve log reader tool
    oneshot         Run one time with an eve.json file
    gencert         Generate TLS certificate

`, os.Args[0])
	fmt.Fprint(os.Stderr, usage)
}

func main() {

	// Look for sub-commands, then fall back to server.
	if len(os.Args) > 1 && os.Args[1][0] != '-' {
		switch os.Args[1] {
		case "version":
			VersionMain()
			return
		case "esimport":
			esimport.Main(os.Args[1:])
			return
		case "agent":
			agent.Main(os.Args[2:])
			return
		case "evereader":
			evereader.Main(os.Args[1:])
			return
		case "server":
			server.Main(os.Args[2:])
			return
		case "oneshot":
			oneshot.Main(os.Args[2:])
			return
		case "pgimport":
			pgimport.Main(os.Args[2:])
			return
		case "sqliteimport":
			sqliteimport.Main(os.Args[2:])
			return
		case "config":
			config.Main(os.Args[2:])
			return
		case "gencert":
			gencert.Main(os.Args[2:])
			return
		default:
			log.Fatalf("Unknown command: %s", os.Args[1])
		}
	} else if len(os.Args) > 1 {
		switch os.Args[1] {
		case "-h":
			Usage()
			os.Exit(0)
		}
	}

	log.Info("No command provided, defaulting to server.")
	server.Main(os.Args[1:])
}
<|endoftext|>


<commit_before>package runtime

// Version is the current version of the buffalo binary
var Version = "v0.18.0"
<commit_msg>bump up version<commit_after>package runtime

// Version is the current version of the buffalo binary
var Version = "v0.18.1"
<|endoftext|>


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

package cmd

import (
	"os"
	"fmt"
	"strings"
	"bufio"
	service "github.com/txzdream/agenda-go/entity/service"
	"github.com/spf13/cobra"
	"strconv"
	log "github.com/txzdream/agenda-go/entity/tools"
)

// manageCmd represents the manage command
var manageCmd = &cobra.Command{
	Use:   "manage",
	Short: "Manage meeting",
	Long: `Create meeting.`,
	Run: func(cmd *cobra.Command, args []string) {
		var Service service.Service
		service.StartAgenda(&Service)
		// check whether other user logged in
		ok, name := Service.AutoUserLogin()
		if ok == true {
			fmt.Println(strings.Join([]string{name,"@:"}, ""))
		}
		if !ok {
			fmt.Fprintln(os.Stderr, "error: No current logged user.")
			log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Manage meeting with no user login."))
			os.Exit(0)
		}

		if meetingName == "" {
			fmt.Fprintln(os.Stderr, "error: Meeting theme is required.")
			log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Manage  meeting %s with no title.", meetingName))
			os.Exit(0)
		}

		meetingList := Service.MeetingQueryByTitle(name, meetingName)
		if len(meetingList) == 0 {
			fmt.Println("No matching meeting with the given theme.")
			os.Exit(1)
		}

		// delete users
		if isDelete {
			var participator []string
			fmt.Println("Participators:")
			for i, v := range meetingList[0].GetParticipators() {
				participator = append(participator, v)
				fmt.Printf("%d. %s\n", i + 1, v)
			}
			fmt.Print("Please input the number you want to remove: ")
			var inputNums string
			reader := bufio.NewReader(os.Stdin)
			data, _, _ := reader.ReadLine()
			inputNums = string(data)
			chosenList := strings.Split(inputNums, " ")
			var toBeRemovedParticipators []string
			for _, v := range chosenList {
				num, err := strconv.Atoi(v)
				if err != nil {
					fmt.Fprintln(os.Stderr, "error: Invalid input")
					os.Exit(1)
				}
				toBeRemovedParticipators = append(toBeRemovedParticipators, participator[num - 1])
			}
			for _, v := range toBeRemovedParticipators {
				ok := Service.DeleteParticipatorByTitle(name, meetingName, v)
				if ok {
					fmt.Printf("%s was removed.\n", v)
					log.LogInfoOrErrorIntoFile(name, true, fmt.Sprintf("Remove %s from meeting %s.", v, meetingName))
				} else {
					fmt.Printf("%s can not be removed.\n", v)
					log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Can not remove %s from meeting %s.", v, meetingName))
				}
			}
		} else {
			// add users
			fmt.Println("You can choose some of them to add to your meeting:")
			userList := Service.ListAllUsers()
			for i, v := range userList {
				fmt.Printf("%d. %s\n", i + 1, v.GetUserName())
			}
			fmt.Print("Please input the number of users you want to add(separate with blank): ")
			var userNums string
			reader := bufio.NewReader(os.Stdin)
			data, _, _ := reader.ReadLine()
			userNums = string(data)
			userNumList := strings.Split(userNums, " ")
			for _, v := range userNumList {
				i, ok := strconv.Atoi(v)
				if ok != nil || i > len(userList) {
					fmt.Fprintln(os.Stderr, "error: Invalid input.")
					os.Exit(0)
				}
				if Service.AddParticipatorByTitle(name, meetingName, userList[i - 1].GetUserName()) {
					fmt.Printf("%s was added.\n", userList[i - 1].GetUserName())
					log.LogInfoOrErrorIntoFile(name, true, fmt.Sprintf("Add %s to meeting %s.", userList[i - 1].GetUserName(), meetingName))
				} else {
					fmt.Printf("%s can not be added.\n", userList[i - 1].GetUserName())
					log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Can not add %s to meeting %s.", userList[i - 1].GetUserName(), meetingName))
				}
			}
		}
	},
}

func init() {
	meetingCmd.AddCommand(manageCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// manageCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// manageCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
	manageCmd.Flags().StringVarP(&meetingName, "name", "", "", "the name of meeting to be managed")
	manageCmd.Flags().BoolVarP(&isDelete, "", "d", false, "Delete a meeting")
}
<commit_msg>[edit] repair help message<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"os"
	"fmt"
	"strings"
	"bufio"
	service "github.com/txzdream/agenda-go/entity/service"
	"github.com/spf13/cobra"
	"strconv"
	log "github.com/txzdream/agenda-go/entity/tools"
)

// manageCmd represents the manage command
var manageCmd = &cobra.Command{
	Use:   "manage",
	Short: "Manage meeting",
	Long: `Create meeting.`,
	Run: func(cmd *cobra.Command, args []string) {
		var Service service.Service
		service.StartAgenda(&Service)
		// check whether other user logged in
		ok, name := Service.AutoUserLogin()
		if ok == true {
			fmt.Println(strings.Join([]string{name,"@:"}, ""))
		}
		if !ok {
			fmt.Fprintln(os.Stderr, "error: No current logged user.")
			log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Manage meeting with no user login."))
			os.Exit(0)
		}

		if meetingName == "" {
			fmt.Fprintln(os.Stderr, "error: Meeting theme is required.")
			log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Manage  meeting %s with no title.", meetingName))
			os.Exit(0)
		}

		meetingList := Service.MeetingQueryByTitle(name, meetingName)
		if len(meetingList) == 0 {
			fmt.Println("No matching meeting with the given theme.")
			os.Exit(1)
		}

		// delete users
		if isDelete {
			var participator []string
			fmt.Println("Participators:")
			for i, v := range meetingList[0].GetParticipators() {
				participator = append(participator, v)
				fmt.Printf("%d. %s\n", i + 1, v)
			}
			fmt.Print("Please input the number you want to remove: ")
			var inputNums string
			reader := bufio.NewReader(os.Stdin)
			data, _, _ := reader.ReadLine()
			inputNums = string(data)
			chosenList := strings.Split(inputNums, " ")
			var toBeRemovedParticipators []string
			for _, v := range chosenList {
				num, err := strconv.Atoi(v)
				if err != nil {
					fmt.Fprintln(os.Stderr, "error: Invalid input")
					os.Exit(1)
				}
				toBeRemovedParticipators = append(toBeRemovedParticipators, participator[num - 1])
			}
			for _, v := range toBeRemovedParticipators {
				ok := Service.DeleteParticipatorByTitle(name, meetingName, v)
				if ok {
					fmt.Printf("%s was removed.\n", v)
					log.LogInfoOrErrorIntoFile(name, true, fmt.Sprintf("Remove %s from meeting %s.", v, meetingName))
				} else {
					fmt.Printf("%s can not be removed.\n", v)
					log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Can not remove %s from meeting %s.", v, meetingName))
				}
			}
		} else {
			// add users
			fmt.Println("You can choose some of them to add to your meeting:")
			userList := Service.ListAllUsers()
			for i, v := range userList {
				fmt.Printf("%d. %s\n", i + 1, v.GetUserName())
			}
			fmt.Print("Please input the number of users you want to add(separate with blank): ")
			var userNums string
			reader := bufio.NewReader(os.Stdin)
			data, _, _ := reader.ReadLine()
			userNums = string(data)
			userNumList := strings.Split(userNums, " ")
			for _, v := range userNumList {
				i, ok := strconv.Atoi(v)
				if ok != nil || i > len(userList) {
					fmt.Fprintln(os.Stderr, "error: Invalid input.")
					os.Exit(0)
				}
				if Service.AddParticipatorByTitle(name, meetingName, userList[i - 1].GetUserName()) {
					fmt.Printf("%s was added.\n", userList[i - 1].GetUserName())
					log.LogInfoOrErrorIntoFile(name, true, fmt.Sprintf("Add %s to meeting %s.", userList[i - 1].GetUserName(), meetingName))
				} else {
					fmt.Printf("%s can not be added.\n", userList[i - 1].GetUserName())
					log.LogInfoOrErrorIntoFile(name, false, fmt.Sprintf("Can not add %s to meeting %s.", userList[i - 1].GetUserName(), meetingName))
				}
			}
		}
	},
}

func init() {
	meetingCmd.AddCommand(manageCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// manageCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// manageCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
	manageCmd.Flags().StringVarP(&meetingName, "name", "", "", "the name of meeting to be managed")
	manageCmd.Flags().BoolVarP(&isDelete, "", "d", false, "Delete user(s) from a meeting")
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io/ioutil"

	"github.com/MDrollette/i2p-tools/reseed"
	"github.com/MDrollette/i2p-tools/su3"
	"github.com/codegangsta/cli"
)

func NewSu3VerifyCommand() cli.Command {
	return cli.Command{
		Name:        "verify",
		Usage:       "Verify a Su3 file",
		Description: "Verify a Su3 file",
		Action:      su3VerifyAction,
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "extract",
				Usage: "Also extract the contents of the su3",
			},
		},
	}
}

func su3VerifyAction(c *cli.Context) {
	su3File := su3.Su3File{}

	data, err := ioutil.ReadFile(c.Args().Get(0))
	if nil != err {
		panic(err)
	}
	if err := su3File.UnmarshalBinary(data); err != nil {
		panic(err)
	}

	fmt.Println(su3File.String())

	// get the reseeder key
	ks := reseed.KeyStore{Path: "./certificates"}
	cert, err := ks.ReseederCertificate(su3File.SignerId)
	if nil != err {
		fmt.Println(err)
		return
	}

	if err := su3File.VerifySignature(cert); nil != err {
		panic(err)
	}

	fmt.Printf("Signature is valid for signer '%s'\n", su3File.SignerId)

	if c.Bool("extract") {
		// @todo: don't assume zip
		ioutil.WriteFile("extracted.zip", su3File.BodyBytes(), 0755)
	}
}
<commit_msg>Update verify.go<commit_after>package cmd

import (
	"fmt"
	"io/ioutil"

	"github.com/martin61/i2p-tools/reseed"
	"github.com/martin61/i2p-tools/su3"
	"github.com/codegangsta/cli"
)

func NewSu3VerifyCommand() cli.Command {
	return cli.Command{
		Name:        "verify",
		Usage:       "Verify a Su3 file",
		Description: "Verify a Su3 file",
		Action:      su3VerifyAction,
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "extract",
				Usage: "Also extract the contents of the su3",
			},
		},
	}
}

func su3VerifyAction(c *cli.Context) {
	su3File := su3.Su3File{}

	data, err := ioutil.ReadFile(c.Args().Get(0))
	if nil != err {
		panic(err)
	}
	if err := su3File.UnmarshalBinary(data); err != nil {
		panic(err)
	}

	fmt.Println(su3File.String())

	// get the reseeder key
	ks := reseed.KeyStore{Path: "./certificates"}
	cert, err := ks.ReseederCertificate(su3File.SignerId)
	if nil != err {
		fmt.Println(err)
		return
	}

	if err := su3File.VerifySignature(cert); nil != err {
		panic(err)
	}

	fmt.Printf("Signature is valid for signer '%s'\n", su3File.SignerId)

	if c.Bool("extract") {
		// @todo: don't assume zip
		ioutil.WriteFile("extracted.zip", su3File.BodyBytes(), 0755)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func lbpkr_make_cmd_update() *commander.Command {
	cmd := &commander.Command{
		Run:       lbpkr_run_cmd_update,
		UsageLine: "update [options]",
		Short:     "update RPMs from the yum repository",
		Long: `
update updates RPMs from the yum repository.

ex:
 $ lbpkr update
`,
		Flag: *flag.NewFlagSet("lbpkr-update", flag.ExitOnError),
	}
	add_default_options(cmd)
	cmd.Flag.Bool("dry-run", false, "dry run. do not actually run the command")
	return cmd
}

func lbpkr_run_cmd_update(cmd *commander.Command, args []string) error {
	var err error

	siteroot := cmd.Flag.Lookup("siteroot").Value.Get().(string)
	debug := cmd.Flag.Lookup("v").Value.Get().(bool)
	dry := cmd.Flag.Lookup("dry-run").Value.Get().(bool)

	switch len(args) {
	case 0:
		// no-op
	default:
		return fmt.Errorf("lbpkr: invalid number of arguments. expected none. got=%d (%v)",
			len(args),
			args,
		)
	}

	cfg := NewConfig(siteroot)
	ctx, err := New(cfg, Debug(debug), EnableDryRun(dry))
	if err != nil {
		return err
	}
	defer ctx.Close()

	ctx.msg.Infof("updating RPMs\n")
	checkOnly := false
	err = ctx.Update(checkOnly)
	return err
}
<commit_msg>cmd-update: add -nodeps and -justdb<commit_after>package main

import (
	"fmt"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func lbpkr_make_cmd_update() *commander.Command {
	cmd := &commander.Command{
		Run:       lbpkr_run_cmd_update,
		UsageLine: "update [options]",
		Short:     "update RPMs from the yum repository",
		Long: `
update updates RPMs from the yum repository.

ex:
 $ lbpkr update
`,
		Flag: *flag.NewFlagSet("lbpkr-update", flag.ExitOnError),
	}
	add_default_options(cmd)
	cmd.Flag.Bool("dry-run", false, "dry run. do not actually run the command")
	cmd.Flag.Bool("nodeps", false, "do not install package dependencies")
	cmd.Flag.Bool("justdb", false, "update the database, but do not modify the filesystem")
	return cmd
}

func lbpkr_run_cmd_update(cmd *commander.Command, args []string) error {
	var err error

	siteroot := cmd.Flag.Lookup("siteroot").Value.Get().(string)
	debug := cmd.Flag.Lookup("v").Value.Get().(bool)
	dry := cmd.Flag.Lookup("dry-run").Value.Get().(bool)
	nodeps := cmd.Flag.Lookup("nodeps").Value.Get().(bool)
	justdb := cmd.Flag.Lookup("justdb").Value.Get().(bool)

	switch len(args) {
	case 0:
		// no-op
	default:
		return fmt.Errorf("lbpkr: invalid number of arguments. expected none. got=%d (%v)",
			len(args),
			args,
		)
	}

	cfg := NewConfig(siteroot)
	ctx, err := New(cfg,
		Debug(debug),
		EnableDryRun(dry),
		EnableNoDeps(nodeps),
		EnableJustDb(justdb),
	)
	if err != nil {
		return err
	}
	defer ctx.Close()

	ctx.msg.Infof("updating RPMs\n")
	checkOnly := false
	err = ctx.Update(checkOnly)
	return err
}
<|endoftext|>


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

package safehttp

import (
	"errors"
	"net/http"
	"net/textproto"
)

// Header represents the key-value pairs in an HTTP header.
// The keys will be in canonical form, as returned by
// textproto.CanonicalMIMEHeaderKey.
type Header struct {
	wrapped http.Header
	claimed map[string]bool
}

// NewHeader creates a new Header.
func NewHeader(h http.Header) Header {
	if h == nil {
		h = http.Header{}
	}
	return Header{
		wrapped: h,
		claimed: map[string]bool{},
	}
}

// Claim claims the header with the given name and returns a function
// which can be used to set the header. The name is first canonicalized
// using textproto.CanonicalMIMEHeaderKey. Other methods in
// the struct can't write to, change or delete the header with this
// name. These methods will instead panic when applied on a claimed
// header. The only way to modify the header is to use the returned
// function. The Set-Cookie header can't be claimed.
func (h Header) Claim(name string) (set func([]string)) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.claimed[name] = true
	return func(v []string) {
		if v == nil {
			return
		}
		h.wrapped[name] = v
	}
}

// IsClaimed reports whether the provided header is already claimed. The name is
// first canonicalized using textproto.CanonicalMIMEHeaderKey. The Set-Cookie header
// is treated as claimed.
func (h Header) IsClaimed(name string) bool {
	name = textproto.CanonicalMIMEHeaderKey(name)
	err := h.writableHeader(name)
	return err != nil
}

// Set sets the header with the given name to the given value.
// The name is first canonicalized using textproto.CanonicalMIMEHeaderKey.
// This method first removes all other values associated with this
// header before setting the new value. It panics when applied on claimed headers
// or on the Set-Cookie header.
func (h Header) Set(name, value string) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.wrapped.Set(name, value)
}

// Add adds a new header with the given name and the given value to
// the collection of headers. The name is first canonicalized using
// textproto.CanonicalMIMEHeaderKey. It panics when applied
// on claimed headers or on the Set-Cookie header.
func (h Header) Add(name, value string) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.wrapped.Add(name, value)
}

// Del deletes all headers with the given name. The name is first canonicalized
// using textproto.CanonicalMIMEHeaderKey. It panics when applied on claimed headers
// or on the Set-Cookie header.
func (h Header) Del(name string) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.wrapped.Del(name)
}

// Get returns the value of the first header with the given name.
// The name is first canonicalized using textproto.CanonicalMIMEHeaderKey.
// If no header exists with the given name then "" is returned.
func (h Header) Get(name string) string {
	return h.wrapped.Get(name)
}

// Values returns all the values of all the headers with the given name.
// The name is first canonicalized using textproto.CanonicalMIMEHeaderKey.
// The values are returned in the same order as they were sent in the request.
// The values are returned as a copy of the original slice of strings in
// the internal header map. This is to prevent modification of the original
// slice. If no header exists with the given name then an empty slice is
// returned.
func (h Header) Values(name string) []string {
	v := h.wrapped.Values(name)
	clone := make([]string, len(v))
	copy(clone, v)
	return clone
}

// addCookie adds the cookie provided as a Set-Cookie header in the header
// collection. If the cookie is nil or cookie.Name() is invalid, no header is
// added and an error is returned. This is the only method that can modify the
// Set-Cookie header. If other methods try to modify the header they will return
// errors.
func (h Header) addCookie(c *Cookie) error {
	v := c.String()
	if v == "" {
		return errors.New("invalid cookie name")
	}
	h.wrapped.Add("Set-Cookie", v)
	return nil
}

// TODO: Add Write, WriteSubset and Clone when needed.

// writableHeader assumes that the given name already has been canonicalized
// using textproto.CanonicalMIMEHeaderKey.
func (h Header) writableHeader(name string) error {
	// TODO(@mattiasgrenfeldt, @kele, @empijei): Think about how this should
	// work during legacy conversions.
	if name == "Set-Cookie" {
		return errors.New("can't write to Set-Cookie header")
	}
	if h.claimed[name] {
		return errors.New("claimed header")
	}
	return nil
}
<commit_msg>Add claimed header to error message.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package safehttp

import (
	"errors"
	"fmt"
	"net/http"
	"net/textproto"
)

// Header represents the key-value pairs in an HTTP header.
// The keys will be in canonical form, as returned by
// textproto.CanonicalMIMEHeaderKey.
type Header struct {
	wrapped http.Header
	claimed map[string]bool
}

// NewHeader creates a new Header.
func NewHeader(h http.Header) Header {
	if h == nil {
		h = http.Header{}
	}
	return Header{
		wrapped: h,
		claimed: map[string]bool{},
	}
}

// Claim claims the header with the given name and returns a function
// which can be used to set the header. The name is first canonicalized
// using textproto.CanonicalMIMEHeaderKey. Other methods in
// the struct can't write to, change or delete the header with this
// name. These methods will instead panic when applied on a claimed
// header. The only way to modify the header is to use the returned
// function. The Set-Cookie header can't be claimed.
func (h Header) Claim(name string) (set func([]string)) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.claimed[name] = true
	return func(v []string) {
		if v == nil {
			return
		}
		h.wrapped[name] = v
	}
}

// IsClaimed reports whether the provided header is already claimed. The name is
// first canonicalized using textproto.CanonicalMIMEHeaderKey. The Set-Cookie header
// is treated as claimed.
func (h Header) IsClaimed(name string) bool {
	name = textproto.CanonicalMIMEHeaderKey(name)
	err := h.writableHeader(name)
	return err != nil
}

// Set sets the header with the given name to the given value.
// The name is first canonicalized using textproto.CanonicalMIMEHeaderKey.
// This method first removes all other values associated with this
// header before setting the new value. It panics when applied on claimed headers
// or on the Set-Cookie header.
func (h Header) Set(name, value string) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.wrapped.Set(name, value)
}

// Add adds a new header with the given name and the given value to
// the collection of headers. The name is first canonicalized using
// textproto.CanonicalMIMEHeaderKey. It panics when applied
// on claimed headers or on the Set-Cookie header.
func (h Header) Add(name, value string) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.wrapped.Add(name, value)
}

// Del deletes all headers with the given name. The name is first canonicalized
// using textproto.CanonicalMIMEHeaderKey. It panics when applied on claimed headers
// or on the Set-Cookie header.
func (h Header) Del(name string) {
	name = textproto.CanonicalMIMEHeaderKey(name)
	if err := h.writableHeader(name); err != nil {
		panic(err)
	}
	h.wrapped.Del(name)
}

// Get returns the value of the first header with the given name.
// The name is first canonicalized using textproto.CanonicalMIMEHeaderKey.
// If no header exists with the given name then "" is returned.
func (h Header) Get(name string) string {
	return h.wrapped.Get(name)
}

// Values returns all the values of all the headers with the given name.
// The name is first canonicalized using textproto.CanonicalMIMEHeaderKey.
// The values are returned in the same order as they were sent in the request.
// The values are returned as a copy of the original slice of strings in
// the internal header map. This is to prevent modification of the original
// slice. If no header exists with the given name then an empty slice is
// returned.
func (h Header) Values(name string) []string {
	v := h.wrapped.Values(name)
	clone := make([]string, len(v))
	copy(clone, v)
	return clone
}

// addCookie adds the cookie provided as a Set-Cookie header in the header
// collection. If the cookie is nil or cookie.Name() is invalid, no header is
// added and an error is returned. This is the only method that can modify the
// Set-Cookie header. If other methods try to modify the header they will return
// errors.
func (h Header) addCookie(c *Cookie) error {
	v := c.String()
	if v == "" {
		return errors.New("invalid cookie name")
	}
	h.wrapped.Add("Set-Cookie", v)
	return nil
}

// TODO: Add Write, WriteSubset and Clone when needed.

// writableHeader assumes that the given name already has been canonicalized
// using textproto.CanonicalMIMEHeaderKey.
func (h Header) writableHeader(name string) error {
	// TODO(@mattiasgrenfeldt, @kele, @empijei): Think about how this should
	// work during legacy conversions.
	if name == "Set-Cookie" {
		return errors.New("can't write to Set-Cookie header")
	}
	if h.claimed[name] {
		return fmt.Errorf("claimed header: %s", name)
	}
	return nil
}
<|endoftext|>


<commit_before>package ebpf

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

	"github.com/pkg/errors"
)

// CollectionSpec describes a collection.
type CollectionSpec struct {
	Maps     map[string]*MapSpec
	Programs map[string]*ProgramSpec
}

// LoadCollectionSpec parse an object file and convert it to a collection
func LoadCollectionSpec(file string) (*CollectionSpec, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return LoadCollectionSpecFromReader(f)
}

// Collection is a collection of Programs and Maps associated
// with their symbols
type Collection struct {
	Programs map[string]*Program
	Maps     map[string]*Map
}

// NewCollection creates a Collection from a specification
func NewCollection(spec *CollectionSpec) (*Collection, error) {
	maps := make(map[string]*Map)
	for k, spec := range spec.Maps {
		m, err := NewMap(spec)
		if err != nil {
			return nil, errors.Wrapf(err, "map %s", k)
		}
		maps[k] = m
	}
	progs := make(map[string]*Program)
	for k, spec := range spec.Programs {
		ed := Edit(&spec.Instructions)

		// Rewrite any Symbol which is a valid Map.
		for _, sym := range ed.ReferencedSymbols() {
			m, ok := maps[sym]
			if !ok {
				continue
			}
			if err := ed.RewriteMap(sym, m); err != nil {
				return nil, errors.Wrapf(err, "program %s", k)
			}
		}
		prog, err := NewProgram(spec)
		if err != nil {
			return nil, errors.Wrapf(err, "program %s", k)
		}
		progs[k] = prog
	}
	return &Collection{
		progs,
		maps,
	}, nil
}

// LoadCollection parses an object file and converts it to a collection.
func LoadCollection(file string) (*Collection, error) {
	spec, err := LoadCollectionSpec(file)
	if err != nil {
		return nil, err
	}
	return NewCollection(spec)
}

// Close frees all maps and programs associated with the collection.
//
// The collection mustn't be used afterwards.
func (coll *Collection) Close() {
	for _, prog := range coll.Programs {
		prog.Close()
	}
	for _, m := range coll.Maps {
		m.Close()
	}
}

// Pin persits a Collection beyond the lifetime of the process that created it
//
// This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional
func (coll *Collection) Pin(dirName string, fileMode os.FileMode) error {
	err := mkdirIfNotExists(dirName, fileMode)
	if err != nil {
		return err
	}
	if len(coll.Maps) > 0 {
		mapPath := filepath.Join(dirName, "maps")
		err = mkdirIfNotExists(mapPath, fileMode)
		if err != nil {
			return err
		}
		for k, v := range coll.Maps {
			err := v.Pin(filepath.Join(mapPath, k))
			if err != nil {
				return errors.Wrapf(err, "map %s", k)
			}
		}
	}
	if len(coll.Programs) > 0 {
		progPath := filepath.Join(dirName, "programs")
		err = mkdirIfNotExists(progPath, fileMode)
		if err != nil {
			return err
		}
		for k, v := range coll.Programs {
			err = v.Pin(filepath.Join(progPath, k))
			if err != nil {
				return errors.Wrapf(err, "program %s", k)
			}
		}
	}
	return nil
}

func mkdirIfNotExists(dirName string, fileMode os.FileMode) error {
	_, err := os.Stat(dirName)
	if err != nil && os.IsNotExist(err) {
		err = os.Mkdir(dirName, fileMode)
	}
	if err != nil {
		return err
	}
	return nil
}

// LoadPinnedCollection loads a Collection from the pinned directory.
//
// Requires at least Linux 4.13, use LoadPinnedCollectionExplicit on
// earlier versions.
func LoadPinnedCollection(dirName string) (*Collection, error) {
	return loadCollection(
		dirName,
		func(_ string, path string) (*Map, error) {
			return LoadPinnedMap(path)
		},
		func(_ string, path string) (*Program, error) {
			return LoadPinnedProgram(path)
		},
	)
}

// LoadPinnedCollectionExplicit loads a Collection from the pinned directory with explicit parameters.
func LoadPinnedCollectionExplicit(dirName string, maps map[string]*MapSpec, progs map[string]ProgType) (*Collection, error) {
	return loadCollection(
		dirName,
		func(name string, path string) (*Map, error) {
			return LoadPinnedMapExplicit(path, maps[name])
		},
		func(name string, path string) (*Program, error) {
			return LoadPinnedProgramExplicit(path, progs[name])
		},
	)
}

func loadCollection(dirName string, loadMap func(string, string) (*Map, error), loadProgram func(string, string) (*Program, error)) (*Collection, error) {
	maps, err := readFileNames(filepath.Join(dirName, "maps"))
	if err != nil {
		return nil, err
	}
	progs, err := readFileNames(filepath.Join(dirName, "programs"))
	if err != nil {
		return nil, err
	}
	bpfColl := &Collection{
		Maps:     make(map[string]*Map),
		Programs: make(map[string]*Program),
	}
	for _, mf := range maps {
		name := filepath.Base(mf)
		m, err := loadMap(name, mf)
		if err != nil {
			return nil, errors.Wrapf(err, "map %s", name)
		}
		bpfColl.Maps[name] = m
	}
	for _, pf := range progs {
		name := filepath.Base(pf)
		prog, err := loadProgram(name, pf)
		if err != nil {
			return nil, errors.Wrapf(err, "program %s", name)
		}
		bpfColl.Programs[name] = prog
	}
	return bpfColl, nil
}

func readFileNames(dirName string) ([]string, error) {
	var fileNames []string
	files, err := ioutil.ReadDir(dirName)
	if err != nil && err != os.ErrNotExist {
		return nil, err
	}
	for _, fi := range files {
		fileNames = append(fileNames, fi.Name())
	}
	return fileNames, nil
}
<commit_msg>don't instatiate unused maps when creating a collection<commit_after>package ebpf

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

	"github.com/pkg/errors"
)

// CollectionSpec describes a collection.
type CollectionSpec struct {
	Maps     map[string]*MapSpec
	Programs map[string]*ProgramSpec
}

// LoadCollectionSpec parse an object file and convert it to a collection
func LoadCollectionSpec(file string) (*CollectionSpec, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return LoadCollectionSpecFromReader(f)
}

// Collection is a collection of Programs and Maps associated
// with their symbols
type Collection struct {
	Programs map[string]*Program
	Maps     map[string]*Map
}

// NewCollection creates a Collection from a specification.
//
// Only maps referenced by at least one of the programs are initialized.
func NewCollection(spec *CollectionSpec) (*Collection, error) {
	maps := make(map[string]*Map)
	progs := make(map[string]*Program)
	for progName, progSpec := range spec.Programs {
		editor := Edit(&progSpec.Instructions)

		// Rewrite any Symbol which is a valid Map.
		for _, sym := range editor.ReferencedSymbols() {
			mapSpec, ok := spec.Maps[sym]
			if !ok {
				continue
			}

			m := maps[sym]
			if m == nil {
				var err error
				m, err = NewMap(mapSpec)
				if err != nil {
					return nil, err
				}
				maps[sym] = m
			}

			if err := editor.RewriteMap(sym, m); err != nil {
				return nil, errors.Wrapf(err, "program %s", progName)
			}
		}

		prog, err := NewProgram(progSpec)
		if err != nil {
			return nil, errors.Wrapf(err, "program %s", progName)
		}
		progs[progName] = prog
	}
	return &Collection{
		progs,
		maps,
	}, nil
}

// LoadCollection parses an object file and converts it to a collection.
func LoadCollection(file string) (*Collection, error) {
	spec, err := LoadCollectionSpec(file)
	if err != nil {
		return nil, err
	}
	return NewCollection(spec)
}

// Close frees all maps and programs associated with the collection.
//
// The collection mustn't be used afterwards.
func (coll *Collection) Close() {
	for _, prog := range coll.Programs {
		prog.Close()
	}
	for _, m := range coll.Maps {
		m.Close()
	}
}

// Pin persits a Collection beyond the lifetime of the process that created it
//
// This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional
func (coll *Collection) Pin(dirName string, fileMode os.FileMode) error {
	err := mkdirIfNotExists(dirName, fileMode)
	if err != nil {
		return err
	}
	if len(coll.Maps) > 0 {
		mapPath := filepath.Join(dirName, "maps")
		err = mkdirIfNotExists(mapPath, fileMode)
		if err != nil {
			return err
		}
		for k, v := range coll.Maps {
			err := v.Pin(filepath.Join(mapPath, k))
			if err != nil {
				return errors.Wrapf(err, "map %s", k)
			}
		}
	}
	if len(coll.Programs) > 0 {
		progPath := filepath.Join(dirName, "programs")
		err = mkdirIfNotExists(progPath, fileMode)
		if err != nil {
			return err
		}
		for k, v := range coll.Programs {
			err = v.Pin(filepath.Join(progPath, k))
			if err != nil {
				return errors.Wrapf(err, "program %s", k)
			}
		}
	}
	return nil
}

func mkdirIfNotExists(dirName string, fileMode os.FileMode) error {
	_, err := os.Stat(dirName)
	if err != nil && os.IsNotExist(err) {
		err = os.Mkdir(dirName, fileMode)
	}
	if err != nil {
		return err
	}
	return nil
}

// LoadPinnedCollection loads a Collection from the pinned directory.
//
// Requires at least Linux 4.13, use LoadPinnedCollectionExplicit on
// earlier versions.
func LoadPinnedCollection(dirName string) (*Collection, error) {
	return loadCollection(
		dirName,
		func(_ string, path string) (*Map, error) {
			return LoadPinnedMap(path)
		},
		func(_ string, path string) (*Program, error) {
			return LoadPinnedProgram(path)
		},
	)
}

// LoadPinnedCollectionExplicit loads a Collection from the pinned directory with explicit parameters.
func LoadPinnedCollectionExplicit(dirName string, maps map[string]*MapSpec, progs map[string]ProgType) (*Collection, error) {
	return loadCollection(
		dirName,
		func(name string, path string) (*Map, error) {
			return LoadPinnedMapExplicit(path, maps[name])
		},
		func(name string, path string) (*Program, error) {
			return LoadPinnedProgramExplicit(path, progs[name])
		},
	)
}

func loadCollection(dirName string, loadMap func(string, string) (*Map, error), loadProgram func(string, string) (*Program, error)) (*Collection, error) {
	maps, err := readFileNames(filepath.Join(dirName, "maps"))
	if err != nil {
		return nil, err
	}
	progs, err := readFileNames(filepath.Join(dirName, "programs"))
	if err != nil {
		return nil, err
	}
	bpfColl := &Collection{
		Maps:     make(map[string]*Map),
		Programs: make(map[string]*Program),
	}
	for _, mf := range maps {
		name := filepath.Base(mf)
		m, err := loadMap(name, mf)
		if err != nil {
			return nil, errors.Wrapf(err, "map %s", name)
		}
		bpfColl.Maps[name] = m
	}
	for _, pf := range progs {
		name := filepath.Base(pf)
		prog, err := loadProgram(name, pf)
		if err != nil {
			return nil, errors.Wrapf(err, "program %s", name)
		}
		bpfColl.Programs[name] = prog
	}
	return bpfColl, nil
}

func readFileNames(dirName string) ([]string, error) {
	var fileNames []string
	files, err := ioutil.ReadDir(dirName)
	if err != nil && err != os.ErrNotExist {
		return nil, err
	}
	for _, fi := range files {
		fileNames = append(fileNames, fi.Name())
	}
	return fileNames, nil
}
<|endoftext|>