<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"gopkg.in/yaml.v2"
	"github.com/deckarep/golang-set"
	"net/http"
	"strconv"
	"strings"
	"regexp"
	"io/ioutil"
	"log"
)

//Structure of config file
type conf struct {
	Regex string `yaml:"regex"`
	Metrics []Metric `yaml:"metrics"`
}

//Structure of a metric in config
type Metric struct{
	KeyName string `yaml:"keyname"`
	MetricType string `yaml:"metrictype"`
	MetricName string `yaml:"metricname"`
	Help string `yaml:"help"`
	Labels []string `yaml:"labels"`
}

type MapStringInterface map[string]interface{}

//Function to get configuration from yaml
func (c *conf) getConf() *conf {
	yamlFile, err := ioutil.ReadFile("logex.yml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
	}
	err = yaml.Unmarshal(yamlFile, c)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}
	return c
}

//Function to handle a log message received on /post
func parseGhPost(rw http.ResponseWriter, request *http.Request) {
	//A temporary map to store the values for each label
	var labelvaluemap = make(map[string] string)
	//Decode the log message from JSON
	var mapstringinterface MapStringInterface
	decoder := json.NewDecoder(request.Body)
	err := decoder.Decode(&mapstringinterface)
	if err != nil {
		fmt.Println("Error JSON Decoding!", err.Error())
	}

	//Iterate through all labels and check if it is present in the log entry
	for _, label := range AllLabels.ToSlice() {
		if value, ok := mapstringinterface[label.(string)]; ok {
			fmt.Printf("\nLabel present : %+v", label)
			if _, ok := value.([]interface{}); ok {
				//Array of interfaces
			}else{
				//Adding label to the label-value map for this log entry
				labelvaluemap[label.(string)] = value.(string)
				fmt.Println(labelvaluemap[label.(string)])
			}
		}else if value, ok := mapstringinterface["request"]; ok {
			//Find out the API endpoint hit using the regex mentioned in "logex.yml"
			var RequestEndpoint string
			Regexp := regexp.MustCompile(con.Regex)
			if(string(value.(string))==""){
				//Request field empty
			}else
			{
				RequestEndpoint = Regexp.FindString(string(value.(string)))
			}
			RequestEndpoint = strings.Replace(RequestEndpoint, " ", "_", -1)
			labelvaluemap["request_endpoint"] = RequestEndpoint

		}else{
				//Label not present
		}
	}

	if value, ok := mapstringinterface["log_message"]; ok {
		fmt.Println("\nLabel present : log_message")
		if element, ok := value.([]interface{}); ok {
			//Array of interfaces
			for _, message := range element {
				if blahMap, ok := message.(map[string]interface{}); ok {
					var templabelarray []string
					for _, lname:= range LabelsMap[blahMap["key"].(string)]{
						templabelarray = append(templabelarray,labelvaluemap[lname])
					}
					if _, ok := CounterMap[blahMap["key"].(string)]; ok {
						CounterMap[blahMap["key"].(string)].WithLabelValues(templabelarray...).Inc()
				}else if _, ok := GaugeMap[blahMap["key"].(string)]; ok {
					setvalue, err := strconv.ParseFloat(blahMap["value"].(string), 64)
					if err != nil {
						panic(err)
					}
					GaugeMap[blahMap["key"].(string)].WithLabelValues(templabelarray...).Set(setvalue)
				}
				}else {
					fmt.Println("\nNot recognized as a monitoring message")
				}
			}
		}
	}
}

//Configuration object
var con *conf
//A map of Prometheus counters
var CounterMap = make(map[string] *prometheus.CounterVec)
//A map of Prometheus Gauges
var GaugeMap = make(map[string] *prometheus.GaugeVec)
//A map to store the labels each metric is associated with
var LabelsMap = make(map[string] []string)
//A string slice of all the keys names
var KeyNames []string
//A set to store all the labels that are there in the config
var AllLabels = mapset.NewSet()

func main() {
	//Get configuration
	con = new(conf)
	con.getConf()

	fmt.Println("Registering Prometheus Metrics...")
	//Traverse through metrics in "logex.yml" and Create Prometheus Counters and Gauges respectively
	for _,element := range con.Metrics {
		if (element.MetricType=="counter"){
			CounterMap[element.KeyName] = prometheus.NewCounterVec(prometheus.CounterOpts{Name : element.MetricName,Help: element.Help}, element.Labels)
			prometheus.MustRegister(CounterMap[element.KeyName])
			LabelsMap[element.KeyName]= element.Labels
			KeyNames=append(KeyNames,element.KeyName)
			old := element.Labels
			new := make([]interface{}, len(old))
			for i, v := range old {
				new[i] = v
			}
			AllLabels = AllLabels.Union(mapset.NewSetFromSlice(new))
		}else if(element.MetricType=="gauge"){
			GaugeMap[element.KeyName] = prometheus.NewGaugeVec(prometheus.GaugeOpts{Name : element.MetricName, Help: element.Help}, element.Labels)
			prometheus.MustRegister(GaugeMap[element.KeyName])
			LabelsMap[element.KeyName]= element.Labels
			KeyNames=append(KeyNames,element.KeyName)
			old := element.Labels
			new := make([]interface{}, len(old))
			for i, v := range old {
				new[i] = v
			}
			AllLabels = AllLabels.Union(mapset.NewSetFromSlice(new))
		}
	}

	fmt.Println("Metrics successfully registered!")
	fmt.Println("Starting Http server and listening on port 8000...")
	http.HandleFunc("/post", parseGhPost)
	http.Handle("/metrics", promhttp.Handler())
	if err := http.ListenAndServe("0.0.0.0:8000", nil); err != nil {
		fmt.Println("Failed to make connection" + err.Error())
	}
}<commit_msg>removed unnecessary prints<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"gopkg.in/yaml.v2"
	"github.com/deckarep/golang-set"
	"net/http"
	"strconv"
	"strings"
	"regexp"
	"io/ioutil"
	"log"
)

//Structure of config file
type conf struct {
	Regex string `yaml:"regex"`
	Metrics []Metric `yaml:"metrics"`
}

//Structure of a metric in config
type Metric struct{
	KeyName string `yaml:"keyname"`
	MetricType string `yaml:"metrictype"`
	MetricName string `yaml:"metricname"`
	Help string `yaml:"help"`
	Labels []string `yaml:"labels"`
}

type MapStringInterface map[string]interface{}

//Function to get configuration from yaml
func (c *conf) getConf() *conf {
	yamlFile, err := ioutil.ReadFile("logex.yml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
	}
	err = yaml.Unmarshal(yamlFile, c)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
	}
	return c
}

//Function to handle a log message received on /post
func parseGhPost(rw http.ResponseWriter, request *http.Request) {
	//A temporary map to store the values for each label
	var labelvaluemap = make(map[string] string)
	//Decode the log message from JSON
	var mapstringinterface MapStringInterface
	decoder := json.NewDecoder(request.Body)
	err := decoder.Decode(&mapstringinterface)
	if err != nil {
		fmt.Println("Error JSON Decoding!", err.Error())
	}

	//Iterate through all labels and check if it is present in the log entry
	for _, label := range AllLabels.ToSlice() {
		if value, ok := mapstringinterface[label.(string)]; ok {
			if _, ok := value.([]interface{}); ok {
				//Array of interfaces
			}else{
				//Adding label to the label-value map for this log entry
				labelvaluemap[label.(string)] = value.(string)
			}
		}else if value, ok := mapstringinterface["request"]; ok {
			//Find out the API endpoint hit using the regex mentioned in "logex.yml"
			var RequestEndpoint string
			Regexp := regexp.MustCompile(con.Regex)
			if(string(value.(string))==""){
				//Request field empty
			}else
			{
				RequestEndpoint = Regexp.FindString(string(value.(string)))
			}
			RequestEndpoint = strings.Replace(RequestEndpoint, " ", "_", -1)
			labelvaluemap["request_endpoint"] = RequestEndpoint

		}else{
				//Label not present
		}
	}

	if value, ok := mapstringinterface["log_message"]; ok {
		if element, ok := value.([]interface{}); ok {
			//Array of interfaces
			for _, message := range element {
				if blahMap, ok := message.(map[string]interface{}); ok {
					var templabelarray []string
					for _, lname:= range LabelsMap[blahMap["key"].(string)]{
						templabelarray = append(templabelarray,labelvaluemap[lname])
					}
					if _, ok := CounterMap[blahMap["key"].(string)]; ok {
						CounterMap[blahMap["key"].(string)].WithLabelValues(templabelarray...).Inc()
				}else if _, ok := GaugeMap[blahMap["key"].(string)]; ok {
					setvalue, err := strconv.ParseFloat(blahMap["value"].(string), 64)
					if err != nil {
						panic(err)
					}
					GaugeMap[blahMap["key"].(string)].WithLabelValues(templabelarray...).Set(setvalue)
				}
				}else {
					fmt.Println("\nNot recognized as a monitoring message")
				}
			}
		}
	}
}

//Configuration object
var con *conf
//A map of Prometheus counters
var CounterMap = make(map[string] *prometheus.CounterVec)
//A map of Prometheus Gauges
var GaugeMap = make(map[string] *prometheus.GaugeVec)
//A map to store the labels each metric is associated with
var LabelsMap = make(map[string] []string)
//A string slice of all the keys names
var KeyNames []string
//A set to store all the labels that are there in the config
var AllLabels = mapset.NewSet()

func main() {
	//Get configuration
	con = new(conf)
	con.getConf()

	fmt.Println("Registering Prometheus Metrics...")
	//Traverse through metrics in "logex.yml" and Create Prometheus Counters and Gauges respectively
	for _,element := range con.Metrics {
		if (element.MetricType=="counter"){
			CounterMap[element.KeyName] = prometheus.NewCounterVec(prometheus.CounterOpts{Name : element.MetricName,Help: element.Help}, element.Labels)
			prometheus.MustRegister(CounterMap[element.KeyName])
			LabelsMap[element.KeyName]= element.Labels
			KeyNames=append(KeyNames,element.KeyName)
			old := element.Labels
			new := make([]interface{}, len(old))
			for i, v := range old {
				new[i] = v
			}
			AllLabels = AllLabels.Union(mapset.NewSetFromSlice(new))
		}else if(element.MetricType=="gauge"){
			GaugeMap[element.KeyName] = prometheus.NewGaugeVec(prometheus.GaugeOpts{Name : element.MetricName, Help: element.Help}, element.Labels)
			prometheus.MustRegister(GaugeMap[element.KeyName])
			LabelsMap[element.KeyName]= element.Labels
			KeyNames=append(KeyNames,element.KeyName)
			old := element.Labels
			new := make([]interface{}, len(old))
			for i, v := range old {
				new[i] = v
			}
			AllLabels = AllLabels.Union(mapset.NewSetFromSlice(new))
		}
	}

	fmt.Println("Metrics successfully registered!")
	fmt.Println("Starting Http server and listening on port 8000...")
	http.HandleFunc("/post", parseGhPost)
	http.Handle("/metrics", promhttp.Handler())
	if err := http.ListenAndServe("0.0.0.0:8000", nil); err != nil {
		fmt.Println("Failed to make connection" + err.Error())
	}
}<|endoftext|>


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

package http

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/couchbaselabs/tuqtng/network"
	"github.com/couchbaselabs/tuqtng/query"
	"github.com/gorilla/mux"
)

type HttpResponse struct {
	w        http.ResponseWriter
	results  query.ValueChannel
	warnings []error
	err      error
}

func (this *HttpResponse) SendError(err error) {
	this.err = err
	showError(this.w, fmt.Sprintf(`{"error":"%v"}`, err), 500)
	close(this.results)
}

func (this *HttpResponse) SendWarning(warning error) {
	this.warnings = append(this.warnings, warning)
}

func (this *HttpResponse) SendResult(val query.Value) {
	this.results <- val
}

func (this *HttpResponse) NoMoreResults() {
	close(this.results)
}

type HttpEndpoint struct {
	queryChannel network.QueryChannel
}

func NewHttpEndpoint(address string) *HttpEndpoint {
	rv := &HttpEndpoint{}

	r := mux.NewRouter()

	r.HandleFunc("/", welcome).Methods("GET")
	r.Handle("/query", rv).Methods("GET", "POST")

	go func() {
		err := http.ListenAndServe(address, r)
		if err != nil {
			log.Fatal("ListenAndServe: ", err)
		}
	}()

	return rv
}

func (this *HttpEndpoint) SendQueriesTo(queryChannel network.QueryChannel) {
	this.queryChannel = queryChannel
}

func welcome(w http.ResponseWriter, r *http.Request) {
	mustEncode(w, map[string]interface{}{
		"tuqtng":  "where no query has relaxed before",
		"version": "tuqtng 0.0",
	})
}

func (this *HttpEndpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	startTime := time.Now()

	queryString := r.FormValue("q")
	if queryString == "" && r.Method == "POST" {
		queryStringBytes, err := ioutil.ReadAll(r.Body)
		if err == nil {
			queryString = string(queryStringBytes)
		}
	}

	if queryString == "" {
		showError(w, "Missing required query string", 500)
		return
	} else {
		log.Printf("Query String: %v", queryString)
	}

	response := HttpResponse{w: w, results: make(query.ValueChannel)}
	query := network.Query{
		Request:  network.UNQLStringQueryRequest{QueryString: queryString},
		Response: &response,
	}

	this.queryChannel <- query

	count := 0
	for val := range response.results {
		if count == 0 {
			// open up our response
			fmt.Fprint(w, "{\n")
			fmt.Fprint(w, "    \"resultset\": [\n")
		} else {
			fmt.Fprint(w, ",\n")
		}
		body, err := json.MarshalIndent(val, "        ", "    ")
		if err != nil {
			log.Printf("Unable to format result to display %#v, %v", val, err)
		} else {
			fmt.Fprintf(w, "        %v", string(body))
		}
		count++
	}

	if response.err == nil {
		if count == 0 {
			fmt.Fprint(w, "{\n")
			fmt.Fprint(w, "    \"resultset\": [")
		}
		fmt.Fprint(w, "\n    ],\n")
		fmt.Fprintf(w, "    \"total_rows\": %d\n", count)
		elapsed_duration := time.Since(startTime)
		fmt.Fprintf(w, "    \"total_elapsed_time\": \"%s\"\n", elapsed_duration)
		if len(response.warnings) > 0 {
			fmt.Fprintf(w, "    \"warnings\": [")
			for i, warning := range response.warnings {
				fmt.Fprintf(w, "\n        \"%v\"", warning)
				if i < len(response.warnings)-1 {
					fmt.Fprintf(w, ",")
				}
			}
			fmt.Fprintf(w, "\n    ],\n")
		}
		fmt.Fprint(w, "}\n")
	}
}

func mustEncode(w io.Writer, i interface{}) {
	if headered, ok := w.(http.ResponseWriter); ok {
		headered.Header().Set("Cache-Control", "no-cache")
		headered.Header().Set("Content-type", "application/json")
	}

	e := json.NewEncoder(w)
	if err := e.Encode(i); err != nil {
		panic(err)
	}
}

func showError(w http.ResponseWriter, msg string, code int) {
	log.Printf("Reporting error %v/%v", code, msg)
	http.Error(w, msg, code)
}
<commit_msg>Fix response data to be valid JSON<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package http

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/couchbaselabs/tuqtng/network"
	"github.com/couchbaselabs/tuqtng/query"
	"github.com/gorilla/mux"
)

type HttpResponse struct {
	w        http.ResponseWriter
	results  query.ValueChannel
	warnings []error
	err      error
}

func (this *HttpResponse) SendError(err error) {
	this.err = err
	showError(this.w, fmt.Sprintf(`{"error":"%v"}`, err), 500)
	close(this.results)
}

func (this *HttpResponse) SendWarning(warning error) {
	this.warnings = append(this.warnings, warning)
}

func (this *HttpResponse) SendResult(val query.Value) {
	this.results <- val
}

func (this *HttpResponse) NoMoreResults() {
	close(this.results)
}

type HttpEndpoint struct {
	queryChannel network.QueryChannel
}

func NewHttpEndpoint(address string) *HttpEndpoint {
	rv := &HttpEndpoint{}

	r := mux.NewRouter()

	r.HandleFunc("/", welcome).Methods("GET")
	r.Handle("/query", rv).Methods("GET", "POST")

	go func() {
		err := http.ListenAndServe(address, r)
		if err != nil {
			log.Fatal("ListenAndServe: ", err)
		}
	}()

	return rv
}

func (this *HttpEndpoint) SendQueriesTo(queryChannel network.QueryChannel) {
	this.queryChannel = queryChannel
}

func welcome(w http.ResponseWriter, r *http.Request) {
	mustEncode(w, map[string]interface{}{
		"tuqtng":  "where no query has relaxed before",
		"version": "tuqtng 0.0",
	})
}

func (this *HttpEndpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	startTime := time.Now()

	queryString := r.FormValue("q")
	if queryString == "" && r.Method == "POST" {
		queryStringBytes, err := ioutil.ReadAll(r.Body)
		if err == nil {
			queryString = string(queryStringBytes)
		}
	}

	if queryString == "" {
		showError(w, "Missing required query string", 500)
		return
	} else {
		log.Printf("Query String: %v", queryString)
	}

	response := HttpResponse{w: w, results: make(query.ValueChannel)}
	query := network.Query{
		Request:  network.UNQLStringQueryRequest{QueryString: queryString},
		Response: &response,
	}

	this.queryChannel <- query

	count := 0
	for val := range response.results {
		if count == 0 {
			// open up our response
			fmt.Fprint(w, "{\n")
			fmt.Fprint(w, "    \"resultset\": [\n")
		} else {
			fmt.Fprint(w, ",\n")
		}
		body, err := json.MarshalIndent(val, "        ", "    ")
		if err != nil {
			log.Printf("Unable to format result to display %#v, %v", val, err)
		} else {
			fmt.Fprintf(w, "        %v", string(body))
		}
		count++
	}

	if response.err == nil {
		if count == 0 {
			fmt.Fprint(w, "{\n")
			fmt.Fprint(w, "    \"resultset\": [")
		}
		fmt.Fprint(w, "\n    ]")
		fmt.Fprintf(w, ",\n    \"total_rows\": %d", count)
		elapsed_duration := time.Since(startTime)
		fmt.Fprintf(w, ",\n    \"total_elapsed_time\": \"%s\"", elapsed_duration)
		if len(response.warnings) > 0 {
			fmt.Fprintf(w, ",\n    \"warnings\": [")
			for i, warning := range response.warnings {
				fmt.Fprintf(w, "\n        \"%v\"", warning)
				if i < len(response.warnings)-1 {
					fmt.Fprintf(w, ",")
				}
			}
			fmt.Fprintf(w, "\n    ]")
		}
		fmt.Fprint(w, "\n}\n")
	}
}

func mustEncode(w io.Writer, i interface{}) {
	if headered, ok := w.(http.ResponseWriter); ok {
		headered.Header().Set("Cache-Control", "no-cache")
		headered.Header().Set("Content-type", "application/json")
	}

	e := json.NewEncoder(w)
	if err := e.Encode(i); err != nil {
		panic(err)
	}
}

func showError(w http.ResponseWriter, msg string, code int) {
	log.Printf("Reporting error %v/%v", code, msg)
	http.Error(w, msg, code)
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package builder

import (
	"fmt"
	"os"
	"path/filepath"

	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/util"
)

func (t *TargetBuilder) Load() error {

	err := t.PrepBuild()

	if err != nil {
		return err
	}

	if t.Loader != nil {
		err = t.App.Load(1)
		if err == nil {
			err = t.Loader.Load(0)
		}
	} else {
		err = t.App.Load(0)
	}

	return err
}

func (b *Builder) Load(image_slot int) error {
	if b.appPkg == nil {
		return util.NewNewtError("app package not specified")
	}

	/*
	 * Populate the package list and feature sets.
	 */
	err := b.target.PrepBuild()
	if err != nil {
		return err
	}

	if b.target.Bsp.DownloadScript == "" {
		/*
		 *
		 */
		util.StatusMessage(util.VERBOSITY_DEFAULT,
			"No download script for BSP %s\n", b.target.Bsp.Name())
		return nil
	}

	bspPath := b.target.Bsp.BasePath()
	downloadScript := filepath.Join(bspPath, b.target.Bsp.DownloadScript)
	binBaseName := b.AppBinBasePath()
	featureString := b.FeatureString()

	downloadCmd := fmt.Sprintf("%s %s %s %d %s",
		downloadScript, bspPath, binBaseName, image_slot, featureString)

	util.StatusMessage(util.VERBOSITY_DEFAULT,
		"Loading %s image int slot %d\n", b.buildName, image_slot)
	util.StatusMessage(util.VERBOSITY_VERBOSE, "Load command: %s\n",
		downloadCmd)
	rsp, err := util.ShellCommand(downloadCmd)
	if err != nil {
		util.StatusMessage(util.VERBOSITY_DEFAULT, "%s", rsp)
		return err
	}
	util.StatusMessage(util.VERBOSITY_VERBOSE, "Successfully loaded image.\n")

	return nil
}

func (t *TargetBuilder) Debug() error {
	//var additional_libs []string
	err := t.PrepBuild()

	if err != nil {
		return err
	}

	//	if t.Loader != nil {
	//		basename := t.Loader.AppElfPath()
	//		name := strings.TrimSuffix(basename, filepath.Ext(basename))
	//		additional_libs = append(additional_libs, name)
	//	}

	//	return t.App.Debug(additional_libs)
	if t.Loader == nil {
		return t.App.Debug(nil)
	}
	return t.Loader.Debug(nil)
}

func (b *Builder) Debug(addlibs []string) error {
	if b.appPkg == nil {
		return util.NewNewtError("app package not specified")
	}

	/*
	 * Populate the package list and feature sets.
	 */
	err := b.target.PrepBuild()
	if err != nil {
		return err
	}

	bspPath := b.target.Bsp.BasePath()
	debugScript := filepath.Join(bspPath, b.target.Bsp.DebugScript)
	binBaseName := b.AppBinBasePath()

	os.Chdir(project.GetProject().Path())

	cmdLine := []string{debugScript, bspPath, binBaseName}
	cmdLine = append(cmdLine, addlibs...)

	fmt.Printf("%s\n", cmdLine)
	return util.ShellInteractiveCommand(cmdLine)
}
<commit_msg>MYNEWT-377<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package builder

import (
	"fmt"
	"os"
	"path/filepath"

	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/util"
)

func (t *TargetBuilder) Load() error {

	err := t.PrepBuild()

	if err != nil {
		return err
	}

	if t.Loader != nil {
		err = t.App.Load(1)
		if err == nil {
			err = t.Loader.Load(0)
		}
	} else {
		err = t.App.Load(0)
	}

	return err
}

func (b *Builder) Load(image_slot int) error {
	if b.appPkg == nil {
		return util.NewNewtError("app package not specified")
	}

	/*
	 * Populate the package list and feature sets.
	 */
	err := b.target.PrepBuild()
	if err != nil {
		return err
	}

	if b.target.Bsp.DownloadScript == "" {
		/*
		 *
		 */
		util.StatusMessage(util.VERBOSITY_DEFAULT,
			"No download script for BSP %s\n", b.target.Bsp.Name())
		return nil
	}

	bspPath := b.target.Bsp.BasePath()
	downloadScript := filepath.Join(bspPath, b.target.Bsp.DownloadScript)
	binBaseName := b.AppBinBasePath()
	featureString := b.FeatureString()

	downloadCmd := fmt.Sprintf("%s %s %s %d %s",
		downloadScript, bspPath, binBaseName, image_slot, featureString)

	features := b.Features(nil)

	if _, ok := features["bootloader"]; ok {
		util.StatusMessage(util.VERBOSITY_DEFAULT,
			"Loading bootloader\n")
	} else {
		util.StatusMessage(util.VERBOSITY_DEFAULT,
			"Loading %s image into slot %d\n", b.buildName, image_slot+1)
	}

	util.StatusMessage(util.VERBOSITY_VERBOSE, "Load command: %s\n",
		downloadCmd)
	rsp, err := util.ShellCommand(downloadCmd)
	if err != nil {
		util.StatusMessage(util.VERBOSITY_DEFAULT, "%s", rsp)
		return err
	}
	util.StatusMessage(util.VERBOSITY_VERBOSE, "Successfully loaded image.\n")

	return nil
}

func (t *TargetBuilder) Debug() error {
	//var additional_libs []string
	err := t.PrepBuild()

	if err != nil {
		return err
	}

	//	if t.Loader != nil {
	//		basename := t.Loader.AppElfPath()
	//		name := strings.TrimSuffix(basename, filepath.Ext(basename))
	//		additional_libs = append(additional_libs, name)
	//	}

	//	return t.App.Debug(additional_libs)
	if t.Loader == nil {
		return t.App.Debug(nil)
	}
	return t.Loader.Debug(nil)
}

func (b *Builder) Debug(addlibs []string) error {
	if b.appPkg == nil {
		return util.NewNewtError("app package not specified")
	}

	/*
	 * Populate the package list and feature sets.
	 */
	err := b.target.PrepBuild()
	if err != nil {
		return err
	}

	bspPath := b.target.Bsp.BasePath()
	debugScript := filepath.Join(bspPath, b.target.Bsp.DebugScript)
	binBaseName := b.AppBinBasePath()

	os.Chdir(project.GetProject().Path())

	cmdLine := []string{debugScript, bspPath, binBaseName}
	cmdLine = append(cmdLine, addlibs...)

	fmt.Printf("%s\n", cmdLine)
	return util.ShellInteractiveCommand(cmdLine)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/lxc/lxd/shared/termios"
)

type cmdConfigTrust struct {
	global *cmdGlobal
	config *cmdConfig
}

func (c *cmdConfigTrust) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("trust")
	cmd.Short = i18n.G("Manage trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Manage trusted clients`))

	// Add
	configTrustAddCmd := cmdConfigTrustAdd{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustAddCmd.Command())

	// Edit
	configTrustEditCmd := cmdConfigTrustEdit{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustEditCmd.Command())

	// List
	configTrustListCmd := cmdConfigTrustList{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustListCmd.Command())

	// Remove
	configTrustRemoveCmd := cmdConfigTrustRemove{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustRemoveCmd.Command())

	// Show
	configTrustShowCmd := cmdConfigTrustShow{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustShowCmd.Command())

	// Workaround for subcommand usage errors. See: https://github.com/spf13/cobra/issues/706
	cmd.Args = cobra.NoArgs
	cmd.Run = func(cmd *cobra.Command, args []string) { cmd.Usage() }
	return cmd
}

// Add
type cmdConfigTrustAdd struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust

	flagName       string
	flagProjects   string
	flagRestricted bool
	flagType       string
}

func (c *cmdConfigTrustAdd) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("add", i18n.G("[<remote>:] <cert>"))
	cmd.Short = i18n.G("Add new trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Add new trusted clients

The following certificate types are supported:
- client (default)
- metrics
`))

	cmd.Flags().BoolVar(&c.flagRestricted, "restricted", false, i18n.G("Restrict the certificate to one or more projects"))
	cmd.Flags().StringVar(&c.flagProjects, "projects", "", i18n.G("List of projects to restrict the certificate to")+"``")
	cmd.Flags().StringVar(&c.flagName, "name", "", i18n.G("Alternative certificate name")+"``")
	cmd.Flags().StringVar(&c.flagType, "type", "client", i18n.G("Type of certificate")+"``")

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustAdd) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 2)
	if exit {
		return err
	}

	// Validate flags.
	if !shared.StringInSlice(c.flagType, []string{"client", "metrics"}) {
		return fmt.Errorf("Unknown certificate type %q", c.flagType)
	}

	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	resources, err := c.global.ParseServers(remote)
	if err != nil {
		return err
	}

	resource := resources[0]

	if c.flagType == "metrics" && !resource.server.HasExtension("metrics") {
		return errors.New("The server doesn't implement metrics")
	}

	// Load the certificate.
	fname := args[len(args)-1]
	if fname == "-" {
		fname = "/dev/stdin"
	} else {
		fname = shared.HostPathFollow(fname)
	}

	var name string
	if c.flagName != "" {
		name = c.flagName
	} else {
		name, _ = shared.SplitExt(fname)
	}

	// Add trust relationship.
	x509Cert, err := shared.ReadCert(fname)
	if err != nil {
		return err
	}

	cert := api.CertificatesPost{}
	cert.Certificate = base64.StdEncoding.EncodeToString(x509Cert.Raw)
	cert.Name = name

	if c.flagType == "client" {
		cert.Type = api.CertificateTypeClient
	} else if c.flagType == "metrics" {
		cert.Type = api.CertificateTypeMetrics
	}

	cert.Restricted = c.flagRestricted
	if c.flagProjects != "" {
		cert.Projects = strings.Split(c.flagProjects, ",")
	}

	return resource.server.CreateCertificate(cert)
}

// Edit
type cmdConfigTrustEdit struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust
}

func (c *cmdConfigTrustEdit) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("edit", i18n.G("[<remote>:]<fingerprint>"))
	cmd.Short = i18n.G("Edit trust configurations as YAML")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Edit trust configurations as YAML`))

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustEdit) helpTemplate() string {
	return i18n.G(
		`### This is a YAML representation of the certificate.
### Any line starting with a '# will be ignored.
###
### Note that the fingerprint is shown but cannot be changed`)
}

func (c *cmdConfigTrustEdit) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 1)
	if exit {
		return err
	}

	// Parse remote
	resources, err := c.global.ParseServers(args[0])
	if err != nil {
		return err
	}

	resource := resources[0]

	if resource.name == "" {
		return fmt.Errorf(i18n.G("Missing certificate fingerprint"))
	}

	// If stdin isn't a terminal, read text from it
	if !termios.IsTerminal(getStdinFd()) {
		contents, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return err
		}

		newdata := api.CertificatePut{}
		err = yaml.Unmarshal(contents, &newdata)
		if err != nil {
			return err
		}

		return resource.server.UpdateCertificate(resource.name, newdata, "")
	}

	// Extract the current value
	cert, etag, err := resource.server.GetCertificate(resource.name)
	if err != nil {
		return err
	}

	data, err := yaml.Marshal(&cert)
	if err != nil {
		return err
	}

	// Spawn the editor
	content, err := shared.TextEditor("", []byte(c.helpTemplate()+"\n\n"+string(data)))
	if err != nil {
		return err
	}

	for {
		// Parse the text received from the editor
		newdata := api.CertificatePut{}
		err = yaml.Unmarshal(content, &newdata)
		if err == nil {
			err = resource.server.UpdateCertificate(resource.name, newdata, etag)
		}

		// Respawn the editor
		if err != nil {
			fmt.Fprintf(os.Stderr, i18n.G("Config parsing error: %s")+"\n", err)
			fmt.Println(i18n.G("Press enter to open the editor again or ctrl+c to abort change"))

			_, err := os.Stdin.Read(make([]byte, 1))
			if err != nil {
				return err
			}

			content, err = shared.TextEditor("", content)
			if err != nil {
				return err
			}
			continue
		}
		break
	}

	return nil
}

// List
type cmdConfigTrustList struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust

	flagFormat string
}

func (c *cmdConfigTrustList) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("list", i18n.G("[<remote>:]"))
	cmd.Aliases = []string{"ls"}
	cmd.Short = i18n.G("List trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`List trusted clients`))
	cmd.Flags().StringVarP(&c.flagFormat, "format", "f", "table", i18n.G("Format (csv|json|table|yaml)")+"``")

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustList) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 0, 1)
	if exit {
		return err
	}

	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	resources, err := c.global.ParseServers(remote)
	if err != nil {
		return err
	}

	resource := resources[0]

	// List trust relationships
	trust, err := resource.server.GetCertificates()
	if err != nil {
		return err
	}

	data := [][]string{}
	for _, cert := range trust {
		fp := cert.Fingerprint[0:12]

		certBlock, _ := pem.Decode([]byte(cert.Certificate))
		if certBlock == nil {
			return fmt.Errorf(i18n.G("Invalid certificate"))
		}

		tlsCert, err := x509.ParseCertificate(certBlock.Bytes)
		if err != nil {
			return err
		}

		const layout = "Jan 2, 2006 at 3:04pm (MST)"
		issue := tlsCert.NotBefore.Format(layout)
		expiry := tlsCert.NotAfter.Format(layout)
		data = append(data, []string{cert.Type, cert.Name, tlsCert.Subject.CommonName, fp, issue, expiry})
	}
	sort.Sort(stringList(data))

	header := []string{
		i18n.G("TYPE"),
		i18n.G("NAME"),
		i18n.G("COMMON NAME"),
		i18n.G("FINGERPRINT"),
		i18n.G("ISSUE DATE"),
		i18n.G("EXPIRY DATE"),
	}

	return utils.RenderTable(c.flagFormat, header, data, trust)
}

// Remove
type cmdConfigTrustRemove struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust
}

func (c *cmdConfigTrustRemove) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("remove", i18n.G("[<remote>:] <fingerprint>"))
	cmd.Aliases = []string{"rm"}
	cmd.Short = i18n.G("Remove trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Remove trusted clients`))

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustRemove) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 2)
	if exit {
		return err
	}

	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	resources, err := c.global.ParseServers(remote)
	if err != nil {
		return err
	}

	resource := resources[0]

	// Remove trust relationship
	return resource.server.DeleteCertificate(args[len(args)-1])
}

// Show
type cmdConfigTrustShow struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust
}

func (c *cmdConfigTrustShow) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("show", i18n.G("[<remote>:]<fingerprint>"))
	cmd.Short = i18n.G("Show trust configurations")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Show trust configurations`))

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustShow) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 1)
	if exit {
		return err
	}

	// Parse remote
	resources, err := c.global.ParseServers(args[0])
	if err != nil {
		return err
	}

	resource := resources[0]
	client := resource.server

	if resource.name == "" {
		return fmt.Errorf(i18n.G("Missing certificate fingerprint"))
	}

	// Show the certificate configuration
	cert, _, err := client.GetCertificate(resource.name)
	if err != nil {
		return err
	}

	data, err := yaml.Marshal(&cert)
	if err != nil {
		return err
	}

	fmt.Printf("%s", data)

	return nil
}
<commit_msg>lxc/config_trust: Don't remove extension from cert<commit_after>package main

import (
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/lxc/lxd/shared/termios"
)

type cmdConfigTrust struct {
	global *cmdGlobal
	config *cmdConfig
}

func (c *cmdConfigTrust) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("trust")
	cmd.Short = i18n.G("Manage trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Manage trusted clients`))

	// Add
	configTrustAddCmd := cmdConfigTrustAdd{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustAddCmd.Command())

	// Edit
	configTrustEditCmd := cmdConfigTrustEdit{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustEditCmd.Command())

	// List
	configTrustListCmd := cmdConfigTrustList{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustListCmd.Command())

	// Remove
	configTrustRemoveCmd := cmdConfigTrustRemove{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustRemoveCmd.Command())

	// Show
	configTrustShowCmd := cmdConfigTrustShow{global: c.global, config: c.config, configTrust: c}
	cmd.AddCommand(configTrustShowCmd.Command())

	// Workaround for subcommand usage errors. See: https://github.com/spf13/cobra/issues/706
	cmd.Args = cobra.NoArgs
	cmd.Run = func(cmd *cobra.Command, args []string) { cmd.Usage() }
	return cmd
}

// Add
type cmdConfigTrustAdd struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust

	flagName       string
	flagProjects   string
	flagRestricted bool
	flagType       string
}

func (c *cmdConfigTrustAdd) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("add", i18n.G("[<remote>:] <cert>"))
	cmd.Short = i18n.G("Add new trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Add new trusted clients

The following certificate types are supported:
- client (default)
- metrics
`))

	cmd.Flags().BoolVar(&c.flagRestricted, "restricted", false, i18n.G("Restrict the certificate to one or more projects"))
	cmd.Flags().StringVar(&c.flagProjects, "projects", "", i18n.G("List of projects to restrict the certificate to")+"``")
	cmd.Flags().StringVar(&c.flagName, "name", "", i18n.G("Alternative certificate name")+"``")
	cmd.Flags().StringVar(&c.flagType, "type", "client", i18n.G("Type of certificate")+"``")

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustAdd) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 2)
	if exit {
		return err
	}

	// Validate flags.
	if !shared.StringInSlice(c.flagType, []string{"client", "metrics"}) {
		return fmt.Errorf("Unknown certificate type %q", c.flagType)
	}

	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	resources, err := c.global.ParseServers(remote)
	if err != nil {
		return err
	}

	resource := resources[0]

	if c.flagType == "metrics" && !resource.server.HasExtension("metrics") {
		return errors.New("The server doesn't implement metrics")
	}

	// Load the certificate.
	fname := args[len(args)-1]
	if fname == "-" {
		fname = "/dev/stdin"
	} else {
		fname = shared.HostPathFollow(fname)
	}

	var name string
	if c.flagName != "" {
		name = c.flagName
	} else {
		name = filepath.Base(fname)
	}

	// Add trust relationship.
	x509Cert, err := shared.ReadCert(fname)
	if err != nil {
		return err
	}

	cert := api.CertificatesPost{}
	cert.Certificate = base64.StdEncoding.EncodeToString(x509Cert.Raw)
	cert.Name = name

	if c.flagType == "client" {
		cert.Type = api.CertificateTypeClient
	} else if c.flagType == "metrics" {
		cert.Type = api.CertificateTypeMetrics
	}

	cert.Restricted = c.flagRestricted
	if c.flagProjects != "" {
		cert.Projects = strings.Split(c.flagProjects, ",")
	}

	return resource.server.CreateCertificate(cert)
}

// Edit
type cmdConfigTrustEdit struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust
}

func (c *cmdConfigTrustEdit) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("edit", i18n.G("[<remote>:]<fingerprint>"))
	cmd.Short = i18n.G("Edit trust configurations as YAML")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Edit trust configurations as YAML`))

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustEdit) helpTemplate() string {
	return i18n.G(
		`### This is a YAML representation of the certificate.
### Any line starting with a '# will be ignored.
###
### Note that the fingerprint is shown but cannot be changed`)
}

func (c *cmdConfigTrustEdit) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 1)
	if exit {
		return err
	}

	// Parse remote
	resources, err := c.global.ParseServers(args[0])
	if err != nil {
		return err
	}

	resource := resources[0]

	if resource.name == "" {
		return fmt.Errorf(i18n.G("Missing certificate fingerprint"))
	}

	// If stdin isn't a terminal, read text from it
	if !termios.IsTerminal(getStdinFd()) {
		contents, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			return err
		}

		newdata := api.CertificatePut{}
		err = yaml.Unmarshal(contents, &newdata)
		if err != nil {
			return err
		}

		return resource.server.UpdateCertificate(resource.name, newdata, "")
	}

	// Extract the current value
	cert, etag, err := resource.server.GetCertificate(resource.name)
	if err != nil {
		return err
	}

	data, err := yaml.Marshal(&cert)
	if err != nil {
		return err
	}

	// Spawn the editor
	content, err := shared.TextEditor("", []byte(c.helpTemplate()+"\n\n"+string(data)))
	if err != nil {
		return err
	}

	for {
		// Parse the text received from the editor
		newdata := api.CertificatePut{}
		err = yaml.Unmarshal(content, &newdata)
		if err == nil {
			err = resource.server.UpdateCertificate(resource.name, newdata, etag)
		}

		// Respawn the editor
		if err != nil {
			fmt.Fprintf(os.Stderr, i18n.G("Config parsing error: %s")+"\n", err)
			fmt.Println(i18n.G("Press enter to open the editor again or ctrl+c to abort change"))

			_, err := os.Stdin.Read(make([]byte, 1))
			if err != nil {
				return err
			}

			content, err = shared.TextEditor("", content)
			if err != nil {
				return err
			}
			continue
		}
		break
	}

	return nil
}

// List
type cmdConfigTrustList struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust

	flagFormat string
}

func (c *cmdConfigTrustList) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("list", i18n.G("[<remote>:]"))
	cmd.Aliases = []string{"ls"}
	cmd.Short = i18n.G("List trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`List trusted clients`))
	cmd.Flags().StringVarP(&c.flagFormat, "format", "f", "table", i18n.G("Format (csv|json|table|yaml)")+"``")

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustList) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 0, 1)
	if exit {
		return err
	}

	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	resources, err := c.global.ParseServers(remote)
	if err != nil {
		return err
	}

	resource := resources[0]

	// List trust relationships
	trust, err := resource.server.GetCertificates()
	if err != nil {
		return err
	}

	data := [][]string{}
	for _, cert := range trust {
		fp := cert.Fingerprint[0:12]

		certBlock, _ := pem.Decode([]byte(cert.Certificate))
		if certBlock == nil {
			return fmt.Errorf(i18n.G("Invalid certificate"))
		}

		tlsCert, err := x509.ParseCertificate(certBlock.Bytes)
		if err != nil {
			return err
		}

		const layout = "Jan 2, 2006 at 3:04pm (MST)"
		issue := tlsCert.NotBefore.Format(layout)
		expiry := tlsCert.NotAfter.Format(layout)
		data = append(data, []string{cert.Type, cert.Name, tlsCert.Subject.CommonName, fp, issue, expiry})
	}
	sort.Sort(stringList(data))

	header := []string{
		i18n.G("TYPE"),
		i18n.G("NAME"),
		i18n.G("COMMON NAME"),
		i18n.G("FINGERPRINT"),
		i18n.G("ISSUE DATE"),
		i18n.G("EXPIRY DATE"),
	}

	return utils.RenderTable(c.flagFormat, header, data, trust)
}

// Remove
type cmdConfigTrustRemove struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust
}

func (c *cmdConfigTrustRemove) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("remove", i18n.G("[<remote>:] <fingerprint>"))
	cmd.Aliases = []string{"rm"}
	cmd.Short = i18n.G("Remove trusted clients")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Remove trusted clients`))

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustRemove) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 2)
	if exit {
		return err
	}

	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	resources, err := c.global.ParseServers(remote)
	if err != nil {
		return err
	}

	resource := resources[0]

	// Remove trust relationship
	return resource.server.DeleteCertificate(args[len(args)-1])
}

// Show
type cmdConfigTrustShow struct {
	global      *cmdGlobal
	config      *cmdConfig
	configTrust *cmdConfigTrust
}

func (c *cmdConfigTrustShow) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("show", i18n.G("[<remote>:]<fingerprint>"))
	cmd.Short = i18n.G("Show trust configurations")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Show trust configurations`))

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdConfigTrustShow) Run(cmd *cobra.Command, args []string) error {
	// Quick checks.
	exit, err := c.global.CheckArgs(cmd, args, 1, 1)
	if exit {
		return err
	}

	// Parse remote
	resources, err := c.global.ParseServers(args[0])
	if err != nil {
		return err
	}

	resource := resources[0]
	client := resource.server

	if resource.name == "" {
		return fmt.Errorf(i18n.G("Missing certificate fingerprint"))
	}

	// Show the certificate configuration
	cert, _, err := client.GetCertificate(resource.name)
	if err != nil {
		return err
	}

	data, err := yaml.Marshal(&cert)
	if err != nil {
		return err
	}

	fmt.Printf("%s", data)

	return nil
}
<|endoftext|>


<commit_before>// Package admin desrcibes the admin view containing references to
// various managers and editors
package admin

import (
	"bytes"
	"encoding/json"
	"html/template"
	"net/http"

	"github.com/bosssauce/ponzu/content"
	"github.com/bosssauce/ponzu/system/admin/user"
	"github.com/bosssauce/ponzu/system/db"
)

var startAdminHTML = `<!doctype html>

        <title>{{ .Logo }}</title>

        <link rel="stylesheet" href="/admin/static/dashboard/css/material-icons.css" />
        <link rel="stylesheet" href="/admin/static/dashboard/css/materialize.min.css" />
        <link rel="stylesheet" href="/admin/static/editor/css/materialNote.css" />
        <link rel="stylesheet" href="/admin/static/dashboard/css/admin.css" />

        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">

                {{ .Logo }}

Logout

`

var mainAdminHTML = `

Content

                    {{ range $t, $f := .Types }}

playlist_add{{ $t }}

                    {{ end }}

System

settingsConfiguration

supervisor_accountUsers

            {{ if .Subview}}

                {{ .Subview }}

            {{ end }}`

var endAdminHTML = `

Powered by © Ponzu  |  open-sourced by Boss Sauce Creative

`

type admin struct {
	Logo    string
	Types   map[string]func() interface{}
	Subview template.HTML
}

// Admin ...
func Admin(view []byte) ([]byte, error) {
	cfg, err := db.Config("name")
	if err != nil {
		return nil, err
	}

	if cfg == nil {
		cfg = []byte("")
	}

	a := admin{
		Logo:    string(cfg),
		Types:   content.Types,
		Subview: template.HTML(view),
	}

	buf := &bytes.Buffer{}
	html := startAdminHTML + mainAdminHTML + endAdminHTML
	tmpl := template.Must(template.New("admin").Parse(html))
	err = tmpl.Execute(buf, a)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

var initAdminHTML = `

Welcome!

You need to initialize your system by filling out the form below. All of
    this information can be updated later on, but you will not be able to start
    without first completing this step.

    <form method="post" action="/admin/init" class="row">

Configuration

            <input placeholder="Enter the name of your site (interal use only)" class="validate required" type="text" id="name" name="name"/>
            Site Name

            <input placeholder="Used for acquiring SSL certificate (e.g. www.example.com or  example.com)" class="validate" type="text" id="domain" name="domain"/>
            Domain

Admin Details

            <input placeholder="Your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
            Email

            <input placeholder="Enter a strong password" class="validate required" type="password" id="password" name="password"/>
            Password

        <button class="btn waves-effect waves-light right">Start</button>
    </form>

`

// Init ...
func Init() ([]byte, error) {
	html := startAdminHTML + initAdminHTML + endAdminHTML

	cfg, err := db.Config("name")
	if err != nil {
		return nil, err
	}

	if cfg == nil {
		cfg = []byte("")
	}

	a := admin{
		Logo: string(cfg),
	}

	buf := &bytes.Buffer{}
	tmpl := template.Must(template.New("init").Parse(html))
	err = tmpl.Execute(buf, a)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

var loginAdminHTML = `

Welcome!

Please log in to the system using your email address and password.

    <form method="post" action="/admin/login" class="row">

            <input placeholder="Enter your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
            Email

            <input placeholder="Enter your password" class="validate required" type="password" id="password" name="password"/>
            Password

        <button class="btn waves-effect waves-light right">Log in</button>
    </form>

`

// Login ...
func Login() ([]byte, error) {
	html := startAdminHTML + loginAdminHTML + endAdminHTML

	cfg, err := db.Config("name")
	if err != nil {
		return nil, err
	}

	if cfg == nil {
		cfg = []byte("")
	}

	a := admin{
		Logo: string(cfg),
	}

	buf := &bytes.Buffer{}
	tmpl := template.Must(template.New("login").Parse(html))
	err = tmpl.Execute(buf, a)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// UsersList ...
func UsersList(req *http.Request) ([]byte, error) {
	html := `

        <form class="row" enctype="multipart/form-data" action="/admin/configure/users/edit" method="post">

Edit your account:

                Email Address
                <input type="email" name="email" value="{{ .User.Email }}"/>

To approve changes, enter your password:

                Current Password
                <input type="password" name="password"/>

                New Password: (leave blank if no password change needed)
                <input type="email" name="new_password" type="password"/>

            <button class="btn waves-effect waves-light green right" type="submit">Save</button>
        </form>

        <form class="row" enctype="multipart/form-data" action="/admin/configure/users" method="post">

Add a new user:

                Email Address
                <input type="email" name="email" value=""/>

                Password
                <input type="password" name="password"/>

            <button class="btn waves-effect waves-light green right" type="submit">Add User</button>
        </form>

            {{ range .Users }}

                {{ .Email }}
                <form enctype="multipart/form-data" class="delete-user __ponzu right" action="/admin/configure/users/delete" method="post">
                    Delete
                    <input type="hidden" name="email" value="{{ .Email }}"/>
                    <input type="hidden" name="id" value="{{ .ID }}"/>
                </form>

            {{ end }}

    `
	script := `

    `
	// get current user out to pass as data to execute template
	j, err := db.CurrentUser(req)
	if err != nil {
		return nil, err
	}

	var usr user.User
	err = json.Unmarshal(j, &usr)
	if err != nil {
		return nil, err
	}

	// get all users to list
	jj, err := db.UserAll()
	if err != nil {
		return nil, err
	}
	usrs := make([]user.User, len(jj), len(jj))
	for i := range jj {
		var u user.User
		err = json.Unmarshal(jj[i], &u)
		if err != nil {
			return nil, err
		}
		usrs = append(usrs, u)
	}

	// make buffer to execute html into then pass buffer's bytes to Admin
	buf := &bytes.Buffer{}
	tmpl := template.Must(template.New("users").Parse(html + script))
	data := map[string]interface{}{
		"User":  usr,
		"Users": usrs,
	}

	err = tmpl.Execute(buf, data)
	if err != nil {
		return nil, err
	}

	view, err := Admin(buf.Bytes())
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err400HTML = `

400 Error: Bad Request

Sorry, the request was unable to be completed.

`

// Error400 creates a subview for a 400 error page
func Error400() ([]byte, error) {
	view, err := Admin([]byte(err400HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err404HTML = `

404 Error: Not Found

Sorry, the page you requested could not be found.

`

// Error404 creates a subview for a 404 error page
func Error404() ([]byte, error) {
	view, err := Admin([]byte(err404HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err405HTML = `

405 Error: Method Not Allowed

Sorry, the page you requested could not be found.

`

// Error405 creates a subview for a 405 error page
func Error405() ([]byte, error) {
	view, err := Admin([]byte(err405HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err500HTML = `

500 Error: Internal Service Error

Sorry, something unexpectedly went wrong.

`

// Error500 creates a subview for a 500 error page
func Error500() ([]byte, error) {
	view, err := Admin([]byte(err500HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}
<commit_msg>adding initial support to edit and add admin users<commit_after>// Package admin desrcibes the admin view containing references to
// various managers and editors
package admin

import (
	"bytes"
	"encoding/json"
	"html/template"
	"net/http"

	"github.com/bosssauce/ponzu/content"
	"github.com/bosssauce/ponzu/system/admin/user"
	"github.com/bosssauce/ponzu/system/db"
)

var startAdminHTML = `<!doctype html>

        <title>{{ .Logo }}</title>

        <link rel="stylesheet" href="/admin/static/dashboard/css/material-icons.css" />
        <link rel="stylesheet" href="/admin/static/dashboard/css/materialize.min.css" />
        <link rel="stylesheet" href="/admin/static/editor/css/materialNote.css" />
        <link rel="stylesheet" href="/admin/static/dashboard/css/admin.css" />

        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">

                {{ .Logo }}

Logout

`

var mainAdminHTML = `

Content

                    {{ range $t, $f := .Types }}

playlist_add{{ $t }}

                    {{ end }}

System

settingsConfiguration

supervisor_accountUsers

            {{ if .Subview}}

                {{ .Subview }}

            {{ end }}`

var endAdminHTML = `

Powered by © Ponzu  |  open-sourced by Boss Sauce Creative

`

type admin struct {
	Logo    string
	Types   map[string]func() interface{}
	Subview template.HTML
}

// Admin ...
func Admin(view []byte) ([]byte, error) {
	cfg, err := db.Config("name")
	if err != nil {
		return nil, err
	}

	if cfg == nil {
		cfg = []byte("")
	}

	a := admin{
		Logo:    string(cfg),
		Types:   content.Types,
		Subview: template.HTML(view),
	}

	buf := &bytes.Buffer{}
	html := startAdminHTML + mainAdminHTML + endAdminHTML
	tmpl := template.Must(template.New("admin").Parse(html))
	err = tmpl.Execute(buf, a)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

var initAdminHTML = `

Welcome!

You need to initialize your system by filling out the form below. All of
    this information can be updated later on, but you will not be able to start
    without first completing this step.

    <form method="post" action="/admin/init" class="row">

Configuration

            <input placeholder="Enter the name of your site (interal use only)" class="validate required" type="text" id="name" name="name"/>
            Site Name

            <input placeholder="Used for acquiring SSL certificate (e.g. www.example.com or  example.com)" class="validate" type="text" id="domain" name="domain"/>
            Domain

Admin Details

            <input placeholder="Your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
            Email

            <input placeholder="Enter a strong password" class="validate required" type="password" id="password" name="password"/>
            Password

        <button class="btn waves-effect waves-light right">Start</button>
    </form>

`

// Init ...
func Init() ([]byte, error) {
	html := startAdminHTML + initAdminHTML + endAdminHTML

	cfg, err := db.Config("name")
	if err != nil {
		return nil, err
	}

	if cfg == nil {
		cfg = []byte("")
	}

	a := admin{
		Logo: string(cfg),
	}

	buf := &bytes.Buffer{}
	tmpl := template.Must(template.New("init").Parse(html))
	err = tmpl.Execute(buf, a)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

var loginAdminHTML = `

Welcome!

Please log in to the system using your email address and password.

    <form method="post" action="/admin/login" class="row">

            <input placeholder="Enter your email address e.g. you@example.com" class="validate required" type="email" id="email" name="email"/>
            Email

            <input placeholder="Enter your password" class="validate required" type="password" id="password" name="password"/>
            Password

        <button class="btn waves-effect waves-light right">Log in</button>
    </form>

`

// Login ...
func Login() ([]byte, error) {
	html := startAdminHTML + loginAdminHTML + endAdminHTML

	cfg, err := db.Config("name")
	if err != nil {
		return nil, err
	}

	if cfg == nil {
		cfg = []byte("")
	}

	a := admin{
		Logo: string(cfg),
	}

	buf := &bytes.Buffer{}
	tmpl := template.Must(template.New("login").Parse(html))
	err = tmpl.Execute(buf, a)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// UsersList ...
func UsersList(req *http.Request) ([]byte, error) {
	html := `

        <form class="row" enctype="multipart/form-data" action="/admin/configure/users/edit" method="post">

Edit your account:

                Email Address
                <input type="email" name="email" value="{{ .User.Email }}"/>

To approve changes, enter your password:

                Current Password
                <input type="password" name="password"/>

                New Password: (leave blank if no password change needed)
                <input name="new_password" type="password"/>

            <button class="btn waves-effect waves-light green right" type="submit">Save</button>
        </form>

        <form class="row" enctype="multipart/form-data" action="/admin/configure/users" method="post">

Add a new user:

                Email Address
                <input type="email" name="email" value=""/>

                Password
                <input type="password" name="password"/>

            <button class="btn waves-effect waves-light green right" type="submit">Add User</button>
        </form>

            {{ range .Users }}

                {{ .Email }}
                <form enctype="multipart/form-data" class="delete-user __ponzu right" action="/admin/configure/users/delete" method="post">
                    Delete
                    <input type="hidden" name="email" value="{{ .Email }}"/>
                    <input type="hidden" name="id" value="{{ .ID }}"/>
                </form>

            {{ end }}

    `
	script := `

    `
	// get current user out to pass as data to execute template
	j, err := db.CurrentUser(req)
	if err != nil {
		return nil, err
	}

	var usr user.User
	err = json.Unmarshal(j, &usr)
	if err != nil {
		return nil, err
	}

	// get all users to list
	jj, err := db.UserAll()
	if err != nil {
		return nil, err
	}

	var usrs []user.User
	for i := range jj {
		var u user.User
		err = json.Unmarshal(jj[i], &u)
		if err != nil {
			return nil, err
		}
		if u.Email != usr.Email {
			usrs = append(usrs, u)
		}
	}

	// make buffer to execute html into then pass buffer's bytes to Admin
	buf := &bytes.Buffer{}
	tmpl := template.Must(template.New("users").Parse(html + script))
	data := map[string]interface{}{
		"User":  usr,
		"Users": usrs,
	}

	err = tmpl.Execute(buf, data)
	if err != nil {
		return nil, err
	}

	view, err := Admin(buf.Bytes())
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err400HTML = `

400 Error: Bad Request

Sorry, the request was unable to be completed.

`

// Error400 creates a subview for a 400 error page
func Error400() ([]byte, error) {
	view, err := Admin([]byte(err400HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err404HTML = `

404 Error: Not Found

Sorry, the page you requested could not be found.

`

// Error404 creates a subview for a 404 error page
func Error404() ([]byte, error) {
	view, err := Admin([]byte(err404HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err405HTML = `

405 Error: Method Not Allowed

Sorry, the page you requested could not be found.

`

// Error405 creates a subview for a 405 error page
func Error405() ([]byte, error) {
	view, err := Admin([]byte(err405HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}

var err500HTML = `

500 Error: Internal Service Error

Sorry, something unexpectedly went wrong.

`

// Error500 creates a subview for a 500 error page
func Error500() ([]byte, error) {
	view, err := Admin([]byte(err500HTML))
	if err != nil {
		return nil, err
	}

	return view, nil
}
<|endoftext|>


<commit_before>package session

import (
	"fmt"
	"github.com/nickng/scribble-go/runtime/transport/tcp"
)

type Endpoint struct {
	roleId   int
	numRoles int
	conn     map[string][]*tcp.Conn
}

func NewEndpoint(roleId, numRoles int, conn map[string][]*tcp.Conn) *Endpoint {
	return &Endpoint{roleId, numRoles, conmn}
}

func (ept *Endpoint) Accept(rolename string, id int, addr, port string) error {
	cn, ok := ept.conn[rolename]
	if !ok {
		return fmt.Errorf("rolename '%s' does not exist", rolename)
	}
	if i < 1 || i > len(cn) {
		return fmt.Errorf("participant %d of role '%s' out of bounds", i, rolename)
	}
	go func(i int, addr, port string) {
		ept.conn[rolename][i-1] = tcp.NewConnection(addr, port).Accept().(*tcp.Conn)
	}(i, addr, port)
	return nil
}

func (ept *Endpoint) Connect(rolename string, id int, addr, port string) error {
	cn, ok := ept.conn[rolename]
	if !ok {
		return fmt.Errorf("rolename '%s' does not exist", rolename)
	}
	if i < 1 || i > len(cn) {
		return fmt.Errorf("participant %d of role '%s' out of bounds", i, rolename)
	}
	// Probably a good idea to use tcp.NewConnectionWithRetry
	ept.conn[rolename][i-1] = tcp.NewConnection(addr, port).Connect().(*tcp.Conn)
	return nil
}
<commit_msg>Fixed errors in code<commit_after>package session

import (
	"fmt"
	"github.com/nickng/scribble-go/runtime/transport/tcp"
)

type Endpoint struct {
	roleId   int
	numRoles int
	conn     map[string][]*tcp.Conn
}

func NewEndpoint(roleId, numRoles int, conn map[string][]*tcp.Conn) *Endpoint {
	return &Endpoint{roleId, numRoles, conn}
}

func (ept *Endpoint) Accept(rolename string, id int, addr, port string) error {
	cn, ok := ept.conn[rolename]
	if !ok {
		return fmt.Errorf("rolename '%s' does not exist", rolename)
	}
	if id < 1 || id > len(cn) {
		return fmt.Errorf("participant %d of role '%s' out of bounds", i, rolename)
	}
	go func(i int, addr, port string) {
		ept.conn[rolename][i-1] = tcp.NewConnection(addr, port).Accept().(*tcp.Conn)
	}(id, addr, port)
	return nil
}

func (ept *Endpoint) Connect(rolename string, id int, addr, port string) error {
	cn, ok := ept.conn[rolename]
	if !ok {
		return fmt.Errorf("rolename '%s' does not exist", rolename)
	}
	if id < 1 || id > len(cn) {
		return fmt.Errorf("participant %d of role '%s' out of bounds", id, rolename)
	}
	// Probably a good idea to use tcp.NewConnectionWithRetry
	ept.conn[rolename][id-1] = tcp.NewConnection(addr, port).Connect().(*tcp.Conn)
	return nil
}
<|endoftext|>


<commit_before>//   Copyright 2019 MSolution.IO
//
//   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 s3

import (
	"context"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/trackit/jsonlog"

	"github.com/trackit/trackit/aws/usageReports"
)

// getS3Tags formats []*bucket.Tag to map[string]string
func getS3Tags(ctx context.Context, bucket *s3.Bucket, svc *s3.S3) []utils.Tag {
	logger := jsonlog.LoggerFromContextOrDefault(ctx)
	res := make([]utils.Tag, 0)
	tags, err := svc.GetBucketTagging(&s3.GetBucketTaggingInput{
		Bucket: bucket.Name,
	})
	if err != nil {
		logger.Error("Failed to get S3 tags", err.Error())
		return res
	}

	for _, tag := range tags.TagSet {
		res = append(res, utils.Tag{
			Key:   aws.StringValue(tag.Key),
			Value: aws.StringValue(tag.Value),
		})
	}
	return res
}
<commit_msg>S3 usage reports: Avoid terminal flood when getting tags<commit_after>//   Copyright 2019 MSolution.IO
//
//   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 s3

import (
	"context"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/trackit/jsonlog"

	"github.com/trackit/trackit/aws/usageReports"
)

func isErrorAwsNoSuchTagSet(err error) bool {
	if awsErr, ok := err.(awserr.Error); ok {
		if awsErr.Code() == "NoSuchTagSet" {
			return true
		}
	}
	return false
}

// getS3Tags formats []*bucket.Tag to map[string]string
func getS3Tags(ctx context.Context, bucket *s3.Bucket, svc *s3.S3) []utils.Tag {
	logger := jsonlog.LoggerFromContextOrDefault(ctx)
	res := make([]utils.Tag, 0)
	tags, err := svc.GetBucketTagging(&s3.GetBucketTaggingInput{
		Bucket: bucket.Name,
	})

	// We do this to avoid error spam since a lot of buckets will have no tag set
	if err != nil {
		if !isErrorAwsNoSuchTagSet(err) {
			logger.Error("Failed to get S3 tags", err)
		}
		return res
	}

	for _, tag := range tags.TagSet {
		res = append(res, utils.Tag{
			Key:   aws.StringValue(tag.Key),
			Value: aws.StringValue(tag.Value),
		})
	}
	return res
}
<|endoftext|>


<commit_before>// +build integration_tests

package websession

// Integration tests; these operate against the test app in ../../internal/testapp

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"testing"
)

// Get the base URL for the test app from the environment. if the requisite environment
// variable is not set, skip the test.
func getAppUrl(t *testing.T) string {
	url := os.Getenv("GO_SANDSTORM_TEST_APP")
	if url == "" {
		t.Fatal("Integration test: GO_SANDSTORM_TEST_APP environment " +
			"variable not defined.")
	}
	return url
}

type echoBody struct {
	Method  string         `json:"method"`
	Url     *url.URL       `json:"url"`
	Headers http.Header    `json:"headers"`
	Body    []byte         `json:"body"`
	Cookies []*http.Cookie `json:"cookies"`
}

func chkfatal(t *testing.T, err error) {
	if err != nil {
		t.Fatal(err)
	}
}

func expectStatus(t *testing.T, want, got int) {
	if want != got {
		t.Fatal("Unexpected status code; expected", want, "but got", got)
	}
}

func TestBasicGetHead(t *testing.T) {
	baseUrl := getAppUrl(t)
	successfulResponse := func(resp *http.Response, err error) {
		if err != nil {
			t.Fatal("Making http request:", err)
		}
		if resp.StatusCode != 200 {
			t.Log("Response:", resp)
			t.Fatal("Got non-200 status code from app")
		}
	}
	successfulResponse(http.Get(baseUrl + "echo-request/hello"))
	successfulResponse(http.Head(baseUrl + "echo-request/hello"))
}

func TestGetCorrectInfo(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "echo-request/hello")
	chkfatal(t, err)
	defer func() {
		if t.Failed() {
			t.Log("Response:", resp)
		}
	}()
	if resp.StatusCode != 200 {
		t.Fatal("Non-zero status code")
	}
	body := &echoBody{}
	err = json.NewDecoder(resp.Body).Decode(body)
	chkfatal(t, err)

	if body.Method != "GET" {
		t.Error("Wrong method:", body.Method)
	}
	if body.Url.Path != "/echo-request/hello" {
		t.Error("Wrong path:", body.Url.Path)
	}
}

func testHeader(t *testing.T, name, sendVal, wantRecvVal string) {
	baseUrl := getAppUrl(t)

	req, err := http.NewRequest("GET", baseUrl+"echo-request/"+name+"-header", nil)
	chkfatal(t, err)
	req.Header.Set(name, sendVal)

	resp, err := http.DefaultClient.Do(req)
	chkfatal(t, err)
	defer func() {
		if t.Failed() {
			t.Log("Response:", resp)
		}
	}()

	if resp.StatusCode != 200 {
		t.Fatal("Bad status code.")
	}
	body := &echoBody{}
	err = json.NewDecoder(resp.Body).Decode(body)
	chkfatal(t, err)
	gotRecvVal := body.Headers.Get(name)
	if gotRecvVal != wantRecvVal {
		t.Fatalf("Server did not see correct value for %s header; "+
			"wanted %q but got %q", name, wantRecvVal, gotRecvVal)
	}
}

func TestAcceptHeader(t *testing.T) {
	testHeader(t, "Accept", "application/json", "application/json; q=1")
}

func TestAcceptEncodingHeader(t *testing.T) {
	testHeader(t, "Accept-Encoding", "something-non-standard", "something-non-standard;q=1")
	testHeader(t, "Accept-Encoding", "gzip", "gzip;q=1")
	testHeader(t, "Accept-Encoding", "*;q=1", "*;q=1")
}

func TestAdditionalHeaders(t *testing.T) {
	testHeader(t, "X-Foo-Disallowed-Header", "Bar", "")
	testHeader(t, "X-Sandstorm-App-Baz", "quux", "quux")
	testHeader(t, "OC-Total-Length", "234", "234")
}

func TestETagPrecondition(t *testing.T) {
	testHeader(t, "If-Match", "*", "*")
	testHeader(t, "If-None-Match", `"foobarbaz"`, `"foobarbaz"`)
	testHeader(t, "If-None-Match", `W/"foobarbaz"`, `W/"foobarbaz"`)
	testHeader(t, "If-None-Match", `W/"foobarbaz", "quux"`, `W/"foobarbaz", "quux"`)

	// "net/http" won't magically deal with the etag header unless we use
	// http.FileSystem, so even though the following should arguably
	// return "Precondition Failed," we can ignore it to check whether the
	// header is getting through:
	testHeader(t, "If-None-Match", "*", "*")
	testHeader(t, "If-Match", `"foobarbaz"`, `"foobarbaz"`)
	testHeader(t, "If-Match", `W/"foobarbaz"`, `W/"foobarbaz"`)
	testHeader(t, "If-Match", `W/"foobarbaz", "quux"`, `W/"foobarbaz", "quux"`)
}

func TestResponseContentType(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "echo-request/content-type")
	chkfatal(t, err)
	expectStatus(t, 200, resp.StatusCode)
	contentType := resp.Header.Get("Content-Type")
	if contentType != "application/json" {
		t.Fatalf("Expected content type application/json but got %q", contentType)
	}
}

func TestResponseContentEncoding(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "echo-request/content-encoding")
	chkfatal(t, err)
	expectStatus(t, 200, resp.StatusCode)

	encoding := resp.Header.Get("Content-Encoding")
	if encoding != "identity" {
		t.Fatalf("Expected content encoding identity, but got %q.", encoding)
	}
}

func TestResponseContentLength(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "content-length")
	chkfatal(t, err)
	expectStatus(t, 200, resp.StatusCode)

	contentLength := resp.Header.Get("Content-Length")
	reportLength, err := strconv.ParseUint(contentLength, 10, 64)
	chkfatal(t, err)

	body, err := ioutil.ReadAll(resp.Body)
	chkfatal(t, err)

	realLength := uint64(len(body))
	if realLength != reportLength {
		t.Fatal("Content-Header indicated a length of %d, but body was ",
			"actually %d bytes long.", reportLength, realLength)
	}
}

func TestWantStatus(t *testing.T) {
	baseUrl := getAppUrl(t)

	for _, wantStatus := range []int{200, 201, 202, 204, 205} {
		resp, err := http.Get(fmt.Sprintf(
			"%secho-request/status?want-status=%d", baseUrl, wantStatus,
		))
		if err != nil {
			t.Error(err)
		}
		expectStatus(t, wantStatus, resp.StatusCode)
	}
}

func TestWantLanguage(t *testing.T) {
	baseUrl := getAppUrl(t)

	for _, wantLang := range []string{"en-US", "de-DE"} {
		resp, err := http.Get(
			baseUrl + "echo-request/lang?want-lang=" + wantLang,
		)
		if err != nil {
			t.Fatal(err)
		}
		expectStatus(t, 200, resp.StatusCode)
		gotLang := resp.Header.Get("Content-Language")
		if wantLang != gotLang {
			t.Fatalf("Unexpected Content-Language; wanted %q but got %q.",
				wantLang, gotLang)
		}
	}
}

func TestNoOpHandler(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "no-op-handler")
	chkfatal(t, err)
	if resp.StatusCode != 200 {
		t.Fatal("Non-200 status. Response:", resp)
	}
}
<commit_msg>Use expectStatus and chkfatal consistently.<commit_after>// +build integration_tests

package websession

// Integration tests; these operate against the test app in ../../internal/testapp

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"testing"
)

// Get the base URL for the test app from the environment. if the requisite environment
// variable is not set, skip the test.
func getAppUrl(t *testing.T) string {
	url := os.Getenv("GO_SANDSTORM_TEST_APP")
	if url == "" {
		t.Fatal("Integration test: GO_SANDSTORM_TEST_APP environment " +
			"variable not defined.")
	}
	return url
}

type echoBody struct {
	Method  string         `json:"method"`
	Url     *url.URL       `json:"url"`
	Headers http.Header    `json:"headers"`
	Body    []byte         `json:"body"`
	Cookies []*http.Cookie `json:"cookies"`
}

func chkfatal(t *testing.T, err error) {
	if err != nil {
		t.Fatal(err)
	}
}

func expectStatus(t *testing.T, want, got int) {
	if want != got {
		t.Fatal("Unexpected status code; expected", want, "but got", got)
	}
}

func TestBasicGetHead(t *testing.T) {
	baseUrl := getAppUrl(t)
	successfulResponse := func(resp *http.Response, err error) {
		chkfatal(t, err)
		expectStatus(t, 200, resp.StatusCode)
	}
	successfulResponse(http.Get(baseUrl + "echo-request/hello"))
	successfulResponse(http.Head(baseUrl + "echo-request/hello"))
}

func TestGetCorrectInfo(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "echo-request/hello")
	chkfatal(t, err)
	defer func() {
		if t.Failed() {
			t.Log("Response:", resp)
		}
	}()
	expectStatus(t, 200, resp.StatusCode)
	body := &echoBody{}
	err = json.NewDecoder(resp.Body).Decode(body)
	chkfatal(t, err)

	if body.Method != "GET" {
		t.Error("Wrong method:", body.Method)
	}
	if body.Url.Path != "/echo-request/hello" {
		t.Error("Wrong path:", body.Url.Path)
	}
}

func testHeader(t *testing.T, name, sendVal, wantRecvVal string) {
	baseUrl := getAppUrl(t)

	req, err := http.NewRequest("GET", baseUrl+"echo-request/"+name+"-header", nil)
	chkfatal(t, err)
	req.Header.Set(name, sendVal)

	resp, err := http.DefaultClient.Do(req)
	chkfatal(t, err)
	defer func() {
		if t.Failed() {
			t.Log("Response:", resp)
		}
	}()

	expectStatus(t, 200, resp.StatusCode)
	body := &echoBody{}
	err = json.NewDecoder(resp.Body).Decode(body)
	chkfatal(t, err)
	gotRecvVal := body.Headers.Get(name)
	if gotRecvVal != wantRecvVal {
		t.Fatalf("Server did not see correct value for %s header; "+
			"wanted %q but got %q", name, wantRecvVal, gotRecvVal)
	}
}

func TestAcceptHeader(t *testing.T) {
	testHeader(t, "Accept", "application/json", "application/json; q=1")
}

func TestAcceptEncodingHeader(t *testing.T) {
	testHeader(t, "Accept-Encoding", "something-non-standard", "something-non-standard;q=1")
	testHeader(t, "Accept-Encoding", "gzip", "gzip;q=1")
	testHeader(t, "Accept-Encoding", "*;q=1", "*;q=1")
}

func TestAdditionalHeaders(t *testing.T) {
	testHeader(t, "X-Foo-Disallowed-Header", "Bar", "")
	testHeader(t, "X-Sandstorm-App-Baz", "quux", "quux")
	testHeader(t, "OC-Total-Length", "234", "234")
}

func TestETagPrecondition(t *testing.T) {
	testHeader(t, "If-Match", "*", "*")
	testHeader(t, "If-None-Match", `"foobarbaz"`, `"foobarbaz"`)
	testHeader(t, "If-None-Match", `W/"foobarbaz"`, `W/"foobarbaz"`)
	testHeader(t, "If-None-Match", `W/"foobarbaz", "quux"`, `W/"foobarbaz", "quux"`)

	// "net/http" won't magically deal with the etag header unless we use
	// http.FileSystem, so even though the following should arguably
	// return "Precondition Failed," we can ignore it to check whether the
	// header is getting through:
	testHeader(t, "If-None-Match", "*", "*")
	testHeader(t, "If-Match", `"foobarbaz"`, `"foobarbaz"`)
	testHeader(t, "If-Match", `W/"foobarbaz"`, `W/"foobarbaz"`)
	testHeader(t, "If-Match", `W/"foobarbaz", "quux"`, `W/"foobarbaz", "quux"`)
}

func TestResponseContentType(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "echo-request/content-type")
	chkfatal(t, err)
	expectStatus(t, 200, resp.StatusCode)
	contentType := resp.Header.Get("Content-Type")
	if contentType != "application/json" {
		t.Fatalf("Expected content type application/json but got %q", contentType)
	}
}

func TestResponseContentEncoding(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "echo-request/content-encoding")
	chkfatal(t, err)
	expectStatus(t, 200, resp.StatusCode)

	encoding := resp.Header.Get("Content-Encoding")
	if encoding != "identity" {
		t.Fatalf("Expected content encoding identity, but got %q.", encoding)
	}
}

func TestResponseContentLength(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "content-length")
	chkfatal(t, err)
	expectStatus(t, 200, resp.StatusCode)

	contentLength := resp.Header.Get("Content-Length")
	reportLength, err := strconv.ParseUint(contentLength, 10, 64)
	chkfatal(t, err)

	body, err := ioutil.ReadAll(resp.Body)
	chkfatal(t, err)

	realLength := uint64(len(body))
	if realLength != reportLength {
		t.Fatal("Content-Header indicated a length of %d, but body was ",
			"actually %d bytes long.", reportLength, realLength)
	}
}

func TestWantStatus(t *testing.T) {
	baseUrl := getAppUrl(t)

	for _, wantStatus := range []int{200, 201, 202, 204, 205} {
		resp, err := http.Get(fmt.Sprintf(
			"%secho-request/status?want-status=%d", baseUrl, wantStatus,
		))
		chkfatal(t, err)
		expectStatus(t, wantStatus, resp.StatusCode)
	}
}

func TestWantLanguage(t *testing.T) {
	baseUrl := getAppUrl(t)

	for _, wantLang := range []string{"en-US", "de-DE"} {
		resp, err := http.Get(
			baseUrl + "echo-request/lang?want-lang=" + wantLang,
		)
		chkfatal(t, err)
		expectStatus(t, 200, resp.StatusCode)
		gotLang := resp.Header.Get("Content-Language")
		if wantLang != gotLang {
			t.Fatalf("Unexpected Content-Language; wanted %q but got %q.",
				wantLang, gotLang)
		}
	}
}

func TestNoOpHandler(t *testing.T) {
	baseUrl := getAppUrl(t)

	resp, err := http.Get(baseUrl + "no-op-handler")
	chkfatal(t, err)
	expectStatus(t, 200, resp.StatusCode)
}
<|endoftext|>


<commit_before>package video

import "github.com/32bitkid/bitreader"

const (
	_ uint32 = iota
	PictureStructure_TopField
	PictureStructure_BottomField
	PictureStructure_FramePicture
)

type FCode [2][2]uint32

type PictureCodingExtension struct {
	f_code                     FCode
	intra_dc_precision         uint32 // 2 uimsbf
	picture_structure          uint32 // 2 uimsbf
	top_field_first            bool   // 1 uimsbf
	frame_pred_frame_dct       uint32 // 1 uimsbf
	concealment_motion_vectors bool   // 1 uimsbf
	q_scale_type               uint32 // 1 uimsbf
	intra_vlc_format           uint32 // 1 uimsbf
	alternate_scan             uint32 // 1 uimsbf
	repeat_first_field         bool   // 1 uimsbf
	chroma_420_type            bool   // 1 uimsbf
	progressive_frame          bool   // 1 uimsbf
	composite_display_flag     bool   // 1 uimsbf

	v_axis            bool   // 1 uimsbf
	field_sequence    uint32 // 3 uimsbf
	sub_carrier       bool   // 1 uimsbf
	burst_amplitude   uint32 // 7 uimsbf
	sub_carrier_phase uint32 // 8 uimsbf
}

func picture_coding_extension(br bitreader.BitReader) (*PictureCodingExtension, error) {

	err := ExtensionStartCode.assert(br)
	if err != nil {
		return nil, err
	}

	err = PictureCodingExtensionID.assert(br)
	if err != nil {
		return nil, err
	}

	pce := PictureCodingExtension{}

	pce.f_code[0][0], err = br.Read32(4)
	if err != nil {
		return nil, err
	}
	pce.f_code[0][1], err = br.Read32(4)
	if err != nil {
		return nil, err
	}
	pce.f_code[1][0], err = br.Read32(4)
	if err != nil {
		return nil, err
	}
	pce.f_code[1][1], err = br.Read32(4)
	if err != nil {
		return nil, err
	}

	pce.intra_dc_precision, err = br.Read32(2)
	if err != nil {
		return nil, err
	}

	pce.picture_structure, err = br.Read32(2)
	if err != nil {
		return nil, err
	}

	pce.top_field_first, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.frame_pred_frame_dct, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.concealment_motion_vectors, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.q_scale_type, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.intra_vlc_format, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.alternate_scan, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.repeat_first_field, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.chroma_420_type, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.progressive_frame, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.composite_display_flag, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	if pce.composite_display_flag {
		pce.v_axis, err = br.ReadBit()
		if err != nil {
			return nil, err
		}
		pce.field_sequence, err = br.Read32(3)
		if err != nil {
			return nil, err
		}
		pce.sub_carrier, err = br.ReadBit()
		if err != nil {
			return nil, err
		}
		pce.burst_amplitude, err = br.Read32(7)
		if err != nil {
			return nil, err
		}
		pce.sub_carrier_phase, err = br.Read32(8)
		if err != nil {
			return nil, err
		}
	}

	return &pce, next_start_code(br)
}
<commit_msg>making picture structure private<commit_after>package video

import "github.com/32bitkid/bitreader"

type PictureStructure uint32

const (
	_ PictureStructure = iota
	PictureStructure_TopField
	PictureStructure_BottomField
	PictureStructure_FramePicture
)

type FCode [2][2]uint32

type PictureCodingExtension struct {
	f_code                     FCode
	intra_dc_precision         uint32           // 2 uimsbf
	picture_structure          PictureStructure // 2 uimsbf
	top_field_first            bool             // 1 uimsbf
	frame_pred_frame_dct       uint32           // 1 uimsbf
	concealment_motion_vectors bool             // 1 uimsbf
	q_scale_type               uint32           // 1 uimsbf
	intra_vlc_format           uint32           // 1 uimsbf
	alternate_scan             uint32           // 1 uimsbf
	repeat_first_field         bool             // 1 uimsbf
	chroma_420_type            bool             // 1 uimsbf
	progressive_frame          bool             // 1 uimsbf
	composite_display_flag     bool             // 1 uimsbf

	v_axis            bool   // 1 uimsbf
	field_sequence    uint32 // 3 uimsbf
	sub_carrier       bool   // 1 uimsbf
	burst_amplitude   uint32 // 7 uimsbf
	sub_carrier_phase uint32 // 8 uimsbf
}

func picture_coding_extension(br bitreader.BitReader) (*PictureCodingExtension, error) {

	err := ExtensionStartCode.assert(br)
	if err != nil {
		return nil, err
	}

	err = PictureCodingExtensionID.assert(br)
	if err != nil {
		return nil, err
	}

	pce := PictureCodingExtension{}

	pce.f_code[0][0], err = br.Read32(4)
	if err != nil {
		return nil, err
	}
	pce.f_code[0][1], err = br.Read32(4)
	if err != nil {
		return nil, err
	}
	pce.f_code[1][0], err = br.Read32(4)
	if err != nil {
		return nil, err
	}
	pce.f_code[1][1], err = br.Read32(4)
	if err != nil {
		return nil, err
	}

	pce.intra_dc_precision, err = br.Read32(2)
	if err != nil {
		return nil, err
	}

	if picture_structure, err := br.Read32(2); err != nil {
		return nil, err
	} else {
		pce.picture_structure = PictureStructure(picture_structure)
	}

	pce.top_field_first, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.frame_pred_frame_dct, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.concealment_motion_vectors, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.q_scale_type, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.intra_vlc_format, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.alternate_scan, err = br.Read32(1)
	if err != nil {
		return nil, err
	}

	pce.repeat_first_field, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.chroma_420_type, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.progressive_frame, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	pce.composite_display_flag, err = br.ReadBit()
	if err != nil {
		return nil, err
	}

	if pce.composite_display_flag {
		pce.v_axis, err = br.ReadBit()
		if err != nil {
			return nil, err
		}
		pce.field_sequence, err = br.Read32(3)
		if err != nil {
			return nil, err
		}
		pce.sub_carrier, err = br.ReadBit()
		if err != nil {
			return nil, err
		}
		pce.burst_amplitude, err = br.Read32(7)
		if err != nil {
			return nil, err
		}
		pce.sub_carrier_phase, err = br.Read32(8)
		if err != nil {
			return nil, err
		}
	}

	return &pce, next_start_code(br)
}
<|endoftext|>


<commit_before>// Package gcs implements remote storage of state on Google Cloud Storage (GCS).
package gcs

import (
	"context"
	"fmt"
	"os"
	"strings"

	"cloud.google.com/go/storage"
	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"google.golang.org/api/option"
)

// gcsBackend implements "backend".Backend for GCS.
// Input(), Validate() and Configure() are implemented by embedding *schema.Backend.
// State(), DeleteState() and States() are implemented explicitly.
type gcsBackend struct {
	*schema.Backend

	storageClient  *storage.Client
	storageContext context.Context

	bucketName       string
	prefix           string
	defaultStateFile string

	projectID string
	region    string
}

func New() backend.Backend {
	be := &gcsBackend{}
	be.Backend = &schema.Backend{
		ConfigureFunc: be.configure,
		Schema: map[string]*schema.Schema{
			"bucket": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The name of the Google Cloud Storage bucket",
			},

			"path": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Path of the default state file",
				Deprecated:  "Use the \"prefix\" option instead",
			},

			"prefix": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The directory where state files will be saved inside the bucket",
			},

			"credentials": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Google Cloud JSON Account Key",
				Default:     "",
			},

			"project": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Google Cloud Project ID",
				Default:     "",
			},

			"region": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Region / location in which to create the bucket",
				Default:     "",
			},
		},
	}

	return be
}

func (b *gcsBackend) configure(ctx context.Context) error {
	if b.storageClient != nil {
		return nil
	}

	// ctx is a background context with the backend config added.
	// Since no context is passed to remoteClient.Get(), .Lock(), etc. but
	// one is required for calling the GCP API, we're holding on to this
	// context here and re-use it later.
	b.storageContext = ctx

	data := schema.FromContextBackendConfig(b.storageContext)

	b.bucketName = data.Get("bucket").(string)
	b.prefix = strings.TrimLeft(data.Get("prefix").(string), "/")

	b.defaultStateFile = strings.TrimLeft(data.Get("path").(string), "/")

	b.projectID = data.Get("project").(string)
	if id := os.Getenv("GOOGLE_PROJECT"); b.projectID == "" && id != "" {
		b.projectID = id
	}
	b.region = data.Get("region").(string)
	if r := os.Getenv("GOOGLE_REGION"); b.projectID == "" && r != "" {
		b.region = r
	}

	opts := []option.ClientOption{
		option.WithScopes(storage.ScopeReadWrite),
		option.WithUserAgent(terraform.UserAgentString()),
	}
	if credentialsFile := data.Get("credentials").(string); credentialsFile != "" {
		opts = append(opts, option.WithCredentialsFile(credentialsFile))
	} else if credentialsFile := os.Getenv("GOOGLE_CREDENTIALS"); credentialsFile != "" {
		opts = append(opts, option.WithCredentialsFile(credentialsFile))
	}

	client, err := storage.NewClient(b.storageContext, opts...)
	if err != nil {
		return fmt.Errorf("storage.NewClient() failed: %v", err)
	}

	b.storageClient = client

	return b.ensureBucketExists()
}

func (b *gcsBackend) ensureBucketExists() error {
	_, err := b.storageClient.Bucket(b.bucketName).Attrs(b.storageContext)
	if err != storage.ErrBucketNotExist {
		return err
	}

	if b.projectID == "" {
		return fmt.Errorf("bucket %q does not exist; specify the \"project\" option or create the bucket manually using `gsutil mb gs://%s`", b.bucketName, b.bucketName)
	}

	attrs := &storage.BucketAttrs{
		Location: b.region,
	}

	return b.storageClient.Bucket(b.bucketName).Create(b.storageContext, b.projectID, attrs)
}
<commit_msg>backend/remote-state/gcs: Sanitize bucket names.<commit_after>// Package gcs implements remote storage of state on Google Cloud Storage (GCS).
package gcs

import (
	"context"
	"fmt"
	"os"
	"strings"

	"cloud.google.com/go/storage"
	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"google.golang.org/api/option"
)

// gcsBackend implements "backend".Backend for GCS.
// Input(), Validate() and Configure() are implemented by embedding *schema.Backend.
// State(), DeleteState() and States() are implemented explicitly.
type gcsBackend struct {
	*schema.Backend

	storageClient  *storage.Client
	storageContext context.Context

	bucketName       string
	prefix           string
	defaultStateFile string

	projectID string
	region    string
}

func New() backend.Backend {
	be := &gcsBackend{}
	be.Backend = &schema.Backend{
		ConfigureFunc: be.configure,
		Schema: map[string]*schema.Schema{
			"bucket": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "The name of the Google Cloud Storage bucket",
			},

			"path": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Path of the default state file",
				Deprecated:  "Use the \"prefix\" option instead",
			},

			"prefix": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "The directory where state files will be saved inside the bucket",
			},

			"credentials": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Google Cloud JSON Account Key",
				Default:     "",
			},

			"project": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Google Cloud Project ID",
				Default:     "",
			},

			"region": {
				Type:        schema.TypeString,
				Optional:    true,
				Description: "Region / location in which to create the bucket",
				Default:     "",
			},
		},
	}

	return be
}

func (b *gcsBackend) configure(ctx context.Context) error {
	if b.storageClient != nil {
		return nil
	}

	// ctx is a background context with the backend config added.
	// Since no context is passed to remoteClient.Get(), .Lock(), etc. but
	// one is required for calling the GCP API, we're holding on to this
	// context here and re-use it later.
	b.storageContext = ctx

	data := schema.FromContextBackendConfig(b.storageContext)

	b.bucketName = toBucketName(data.Get("bucket").(string))
	b.prefix = strings.TrimLeft(data.Get("prefix").(string), "/")

	b.defaultStateFile = strings.TrimLeft(data.Get("path").(string), "/")

	b.projectID = data.Get("project").(string)
	if id := os.Getenv("GOOGLE_PROJECT"); b.projectID == "" && id != "" {
		b.projectID = id
	}
	b.region = data.Get("region").(string)
	if r := os.Getenv("GOOGLE_REGION"); b.projectID == "" && r != "" {
		b.region = r
	}

	opts := []option.ClientOption{
		option.WithScopes(storage.ScopeReadWrite),
		option.WithUserAgent(terraform.UserAgentString()),
	}
	if credentialsFile := data.Get("credentials").(string); credentialsFile != "" {
		opts = append(opts, option.WithCredentialsFile(credentialsFile))
	} else if credentialsFile := os.Getenv("GOOGLE_CREDENTIALS"); credentialsFile != "" {
		opts = append(opts, option.WithCredentialsFile(credentialsFile))
	}

	client, err := storage.NewClient(b.storageContext, opts...)
	if err != nil {
		return fmt.Errorf("storage.NewClient() failed: %v", err)
	}

	b.storageClient = client

	return b.ensureBucketExists()
}

func (b *gcsBackend) ensureBucketExists() error {
	_, err := b.storageClient.Bucket(b.bucketName).Attrs(b.storageContext)
	if err != storage.ErrBucketNotExist {
		return err
	}

	if b.projectID == "" {
		return fmt.Errorf("bucket %q does not exist; specify the \"project\" option or create the bucket manually using `gsutil mb gs://%s`", b.bucketName, b.bucketName)
	}

	attrs := &storage.BucketAttrs{
		Location: b.region,
	}

	return b.storageClient.Bucket(b.bucketName).Create(b.storageContext, b.projectID, attrs)
}

// toBucketName returns a copy of in that is suitable for use as a bucket name.
// All upper case characters are converted to lower case, other invalid
// characters are replaced by '_'.
func toBucketName(in string) string {
	// Bucket names must contain only lowercase letters, numbers, dashes
	// (-), and underscores (_).
	isValid := func(r rune) bool {
		switch {
		case r >= 'a' && r <= 'z':
			return true
		case r >= '0' && r <= '9':
			return true
		case r == '-' || r == '_':
			return true
		default:
			return false

		}
	}

	out := make([]rune, 0, len(in))
	for _, r := range strings.ToLower(in) {
		if !isValid(r) {
			r = '_'
		}
		out = append(out, r)
	}

	// Bucket names must contain 3 to 63 characters.
	if len(out) > 63 {
		out = out[:63]
	}

	return string(out)
}
<|endoftext|>