<commit_before>package storage

import (
	"fmt"
	"strings"
	"time"

	_ "github.com/jackc/pgx/v4/stdlib" // Load the PostgreSQL Driver used in the connection string.

	"github.com/authelia/authelia/v4/internal/configuration/schema"
)

// PostgreSQLProvider is a PostgreSQL provider.
type PostgreSQLProvider struct {
	SQLProvider
}

// NewPostgreSQLProvider a PostgreSQL provider.
func NewPostgreSQLProvider(config *schema.Configuration) (provider *PostgreSQLProvider) {
	provider = &PostgreSQLProvider{
		SQLProvider: NewSQLProvider(config, providerPostgres, "pgx", dataSourceNamePostgreSQL(*config.Storage.PostgreSQL)),
	}

	// All providers have differing SELECT existing table statements.
	provider.sqlSelectExistingTables = queryPostgreSelectExistingTables

	// Specific alterations to this provider.
	// PostgreSQL doesn't have a UPSERT statement but has an ON CONFLICT operation instead.
	provider.sqlUpsertU2FDevice = fmt.Sprintf(queryFmtPostgresUpsertU2FDevice, tableU2FDevices)
	provider.sqlUpsertDuoDevice = fmt.Sprintf(queryFmtPostgresUpsertDuoDevice, tableDuoDevices)
	provider.sqlUpsertTOTPConfig = fmt.Sprintf(queryFmtPostgresUpsertTOTPConfiguration, tableTOTPConfigurations)
	provider.sqlUpsertPreferred2FAMethod = fmt.Sprintf(queryFmtPostgresUpsertPreferred2FAMethod, tableUserPreferences)
	provider.sqlUpsertEncryptionValue = fmt.Sprintf(queryFmtPostgresUpsertEncryptionValue, tableEncryption)

	// PostgreSQL requires rebinding of any query that contains a '?' placeholder to use the '$#' notation placeholders.
	provider.sqlFmtRenameTable = provider.db.Rebind(provider.sqlFmtRenameTable)
	provider.sqlSelectPreferred2FAMethod = provider.db.Rebind(provider.sqlSelectPreferred2FAMethod)
	provider.sqlSelectUserInfo = provider.db.Rebind(provider.sqlSelectUserInfo)
	provider.sqlSelectExistsIdentityVerification = provider.db.Rebind(provider.sqlSelectExistsIdentityVerification)
	provider.sqlInsertIdentityVerification = provider.db.Rebind(provider.sqlInsertIdentityVerification)
	provider.sqlDeleteIdentityVerification = provider.db.Rebind(provider.sqlDeleteIdentityVerification)
	provider.sqlSelectTOTPConfig = provider.db.Rebind(provider.sqlSelectTOTPConfig)
	provider.sqlUpsertTOTPConfig = provider.db.Rebind(provider.sqlUpsertTOTPConfig)
	provider.sqlDeleteTOTPConfig = provider.db.Rebind(provider.sqlDeleteTOTPConfig)
	provider.sqlSelectTOTPConfigs = provider.db.Rebind(provider.sqlSelectTOTPConfigs)
	provider.sqlUpdateTOTPConfigSecret = provider.db.Rebind(provider.sqlUpdateTOTPConfigSecret)
	provider.sqlUpdateTOTPConfigSecretByUsername = provider.db.Rebind(provider.sqlUpdateTOTPConfigSecretByUsername)
	provider.sqlSelectU2FDevice = provider.db.Rebind(provider.sqlSelectU2FDevice)
	provider.sqlInsertAuthenticationAttempt = provider.db.Rebind(provider.sqlInsertAuthenticationAttempt)
	provider.sqlSelectAuthenticationAttemptsByUsername = provider.db.Rebind(provider.sqlSelectAuthenticationAttemptsByUsername)
	provider.sqlInsertMigration = provider.db.Rebind(provider.sqlInsertMigration)
	provider.sqlSelectEncryptionValue = provider.db.Rebind(provider.sqlSelectEncryptionValue)

	return provider
}

func dataSourceNamePostgreSQL(config schema.PostgreSQLStorageConfiguration) (dataSourceName string) {
	args := []string{
		fmt.Sprintf("host=%s", config.Host),
		fmt.Sprintf("user='%s'", config.Username),
		fmt.Sprintf("password='%s'", config.Password),
		fmt.Sprintf("dbname=%s", config.Database),
	}

	if config.Port > 0 {
		args = append(args, fmt.Sprintf("port=%d", config.Port))
	}

	if config.Schema != "" {
		args = append(args, fmt.Sprintf("search_path=%s", config.Schema))
	}

	if config.SSL.Mode != "" {
		args = append(args, fmt.Sprintf("sslmode=%s", config.SSL.Mode))
	}

	if config.SSL.RootCertificate != "" {
		args = append(args, fmt.Sprintf("sslrootcert=%s", config.SSL.RootCertificate))
	}

	if config.SSL.Certificate != "" {
		args = append(args, fmt.Sprintf("sslcert=%s", config.SSL.Certificate))
	}

	if config.SSL.Key != "" {
		args = append(args, fmt.Sprintf("sslkey=%s", config.SSL.Key))
	}

	args = append(args, fmt.Sprintf("connect_timeout=%d", int32(config.Timeout/time.Second)))

	return strings.Join(args, " ")
}
<commit_msg>fix(storage): rebind all queries (#2662)<commit_after>package storage

import (
	"fmt"
	"strings"
	"time"

	_ "github.com/jackc/pgx/v4/stdlib" // Load the PostgreSQL Driver used in the connection string.

	"github.com/authelia/authelia/v4/internal/configuration/schema"
)

// PostgreSQLProvider is a PostgreSQL provider.
type PostgreSQLProvider struct {
	SQLProvider
}

// NewPostgreSQLProvider a PostgreSQL provider.
func NewPostgreSQLProvider(config *schema.Configuration) (provider *PostgreSQLProvider) {
	provider = &PostgreSQLProvider{
		SQLProvider: NewSQLProvider(config, providerPostgres, "pgx", dataSourceNamePostgreSQL(*config.Storage.PostgreSQL)),
	}

	// All providers have differing SELECT existing table statements.
	provider.sqlSelectExistingTables = queryPostgreSelectExistingTables

	// Specific alterations to this provider.
	// PostgreSQL doesn't have a UPSERT statement but has an ON CONFLICT operation instead.
	provider.sqlUpsertU2FDevice = fmt.Sprintf(queryFmtPostgresUpsertU2FDevice, tableU2FDevices)
	provider.sqlUpsertDuoDevice = fmt.Sprintf(queryFmtPostgresUpsertDuoDevice, tableDuoDevices)
	provider.sqlUpsertTOTPConfig = fmt.Sprintf(queryFmtPostgresUpsertTOTPConfiguration, tableTOTPConfigurations)
	provider.sqlUpsertPreferred2FAMethod = fmt.Sprintf(queryFmtPostgresUpsertPreferred2FAMethod, tableUserPreferences)
	provider.sqlUpsertEncryptionValue = fmt.Sprintf(queryFmtPostgresUpsertEncryptionValue, tableEncryption)

	// PostgreSQL requires rebinding of any query that contains a '?' placeholder to use the '$#' notation placeholders.
	provider.sqlFmtRenameTable = provider.db.Rebind(provider.sqlFmtRenameTable)
	provider.sqlSelectPreferred2FAMethod = provider.db.Rebind(provider.sqlSelectPreferred2FAMethod)
	provider.sqlSelectUserInfo = provider.db.Rebind(provider.sqlSelectUserInfo)
	provider.sqlSelectExistsIdentityVerification = provider.db.Rebind(provider.sqlSelectExistsIdentityVerification)
	provider.sqlInsertIdentityVerification = provider.db.Rebind(provider.sqlInsertIdentityVerification)
	provider.sqlDeleteIdentityVerification = provider.db.Rebind(provider.sqlDeleteIdentityVerification)
	provider.sqlSelectTOTPConfig = provider.db.Rebind(provider.sqlSelectTOTPConfig)
	provider.sqlDeleteTOTPConfig = provider.db.Rebind(provider.sqlDeleteTOTPConfig)
	provider.sqlSelectTOTPConfigs = provider.db.Rebind(provider.sqlSelectTOTPConfigs)
	provider.sqlUpdateTOTPConfigSecret = provider.db.Rebind(provider.sqlUpdateTOTPConfigSecret)
	provider.sqlUpdateTOTPConfigSecretByUsername = provider.db.Rebind(provider.sqlUpdateTOTPConfigSecretByUsername)
	provider.sqlSelectU2FDevice = provider.db.Rebind(provider.sqlSelectU2FDevice)
	provider.sqlSelectDuoDevice = provider.db.Rebind(provider.sqlSelectDuoDevice)
	provider.sqlDeleteDuoDevice = provider.db.Rebind(provider.sqlDeleteDuoDevice)
	provider.sqlInsertAuthenticationAttempt = provider.db.Rebind(provider.sqlInsertAuthenticationAttempt)
	provider.sqlSelectAuthenticationAttemptsByUsername = provider.db.Rebind(provider.sqlSelectAuthenticationAttemptsByUsername)
	provider.sqlInsertMigration = provider.db.Rebind(provider.sqlInsertMigration)
	provider.sqlSelectMigrations = provider.db.Rebind(provider.sqlSelectMigrations)
	provider.sqlSelectLatestMigration = provider.db.Rebind(provider.sqlSelectLatestMigration)
	provider.sqlSelectEncryptionValue = provider.db.Rebind(provider.sqlSelectEncryptionValue)

	return provider
}

func dataSourceNamePostgreSQL(config schema.PostgreSQLStorageConfiguration) (dataSourceName string) {
	args := []string{
		fmt.Sprintf("host=%s", config.Host),
		fmt.Sprintf("user='%s'", config.Username),
		fmt.Sprintf("password='%s'", config.Password),
		fmt.Sprintf("dbname=%s", config.Database),
	}

	if config.Port > 0 {
		args = append(args, fmt.Sprintf("port=%d", config.Port))
	}

	if config.Schema != "" {
		args = append(args, fmt.Sprintf("search_path=%s", config.Schema))
	}

	if config.SSL.Mode != "" {
		args = append(args, fmt.Sprintf("sslmode=%s", config.SSL.Mode))
	}

	if config.SSL.RootCertificate != "" {
		args = append(args, fmt.Sprintf("sslrootcert=%s", config.SSL.RootCertificate))
	}

	if config.SSL.Certificate != "" {
		args = append(args, fmt.Sprintf("sslcert=%s", config.SSL.Certificate))
	}

	if config.SSL.Key != "" {
		args = append(args, fmt.Sprintf("sslkey=%s", config.SSL.Key))
	}

	args = append(args, fmt.Sprintf("connect_timeout=%d", int32(config.Timeout/time.Second)))

	return strings.Join(args, " ")
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"github.com/spf13/cobra"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/debug"
	"strings"
	"time"
)

var (
	Debugging    = false
	ErrorBuffer  = &bytes.Buffer{}
	ErrorWriter  = io.MultiWriter(os.Stderr, ErrorBuffer)
	OutputWriter = io.MultiWriter(os.Stdout, ErrorBuffer)
	RootCmd      = &cobra.Command{
		Use:   "git-media",
		Short: "Git Media provides large file support to Git.",
		Run: func(cmd *cobra.Command, args []string) {
			versionCommand(cmd, args)
			cmd.Usage()
		},
	}
)

// Error prints a formatted message to Stderr.  It also gets printed to the
// panic log if one is created for this command.
func Error(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(ErrorWriter, line)
}

// Print prints a formatted message to Stdout.  It also gets printed to the
// panic log if one is created for this command.
func Print(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(OutputWriter, line)
}

// Exit prints a formatted message and exits.
func Exit(format string, args ...interface{}) {
	Error(format, args...)
	os.Exit(2)
}

// Debug prints a formatted message if debugging is enabled.  The formatted
// message also shows up in the panic log, if created.
func Debug(format string, args ...interface{}) {
	if !Debugging {
		return
	}
	log.Printf(format, args...)
}

// Panic prints a formatted message, and writes a stack trace for the error to
// a log file before exiting.
func Panic(err error, format string, args ...interface{}) {
	Error(format, args...)
	file := handlePanic(err)

	if len(file) > 0 {
		fmt.Fprintf(os.Stderr, "\nErrors logged to %s.\nUse `git media logs last` to view the log.\n", file)
	}
	os.Exit(2)
}

func Run() {
	RootCmd.Execute()
}

func PipeMediaCommand(name string, args ...string) error {
	return PipeCommand("bin/"+name, args...)
}

func PipeCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

func handlePanic(err error) string {
	if err == nil {
		return ""
	}

	Debug(err.Error())
	return logPanic(err)
}

func logEnv(w io.Writer) {
	for _, env := range gitmedia.Environ() {
		fmt.Fprintln(w, env)
	}
}

func logPanic(loggedError error) string {
	var fmtWriter io.Writer = os.Stderr

	if err := os.MkdirAll(gitmedia.LocalLogDir, 0755); err != nil {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s: %s\n\n", gitmedia.LocalLogDir, err.Error())
		return ""
	}

	now := time.Now()
	name := now.Format("2006-01-02T15:04:05.999999999")
	full := filepath.Join(gitmedia.LocalLogDir, name+".log")

	file, err := os.Create(full)
	if err != nil {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s\n\n", full)
	} else {
		fmtWriter = file
		defer file.Close()
	}

	fmt.Fprintf(fmtWriter, "> %s", filepath.Base(os.Args[0]))
	if len(os.Args) > 0 {
		fmt.Fprintf(fmtWriter, " %s", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprint(fmtWriter, "\n")

	logEnv(fmtWriter)
	fmt.Fprint(fmtWriter, "\n")

	fmtWriter.Write(ErrorBuffer.Bytes())
	fmt.Fprint(fmtWriter, "\n")

	fmt.Fprintln(fmtWriter, loggedError.Error())
	fmtWriter.Write(debug.Stack())

	return full
}

func init() {
	log.SetOutput(ErrorWriter)
}
<commit_msg>アーア アアアア アーアー<commit_after>package commands

import (
	"bytes"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"github.com/spf13/cobra"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/debug"
	"strings"
	"time"
)

var (
	Debugging    = false
	ErrorBuffer  = &bytes.Buffer{}
	ErrorWriter  = io.MultiWriter(os.Stderr, ErrorBuffer)
	OutputWriter = io.MultiWriter(os.Stdout, ErrorBuffer)
	RootCmd      = &cobra.Command{
		Use:   "git-media",
		Short: "Git Media provides large file support to Git.",
		Run: func(cmd *cobra.Command, args []string) {
			versionCommand(cmd, args)
			cmd.Usage()
		},
	}
)

// Error prints a formatted message to Stderr.  It also gets printed to the
// panic log if one is created for this command.
func Error(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(ErrorWriter, line)
}

// Print prints a formatted message to Stdout.  It also gets printed to the
// panic log if one is created for this command.
func Print(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(OutputWriter, line)
}

// Exit prints a formatted message and exits.
func Exit(format string, args ...interface{}) {
	Error(format, args...)
	os.Exit(2)
}

// Debug prints a formatted message if debugging is enabled.  The formatted
// message also shows up in the panic log, if created.
func Debug(format string, args ...interface{}) {
	if !Debugging {
		return
	}
	log.Printf(format, args...)
}

// Panic prints a formatted message, and writes a stack trace for the error to
// a log file before exiting.
func Panic(err error, format string, args ...interface{}) {
	Error(format, args...)
	file := handlePanic(err)

	if len(file) > 0 {
		fmt.Fprintf(os.Stderr, "\nErrors logged to %s.\nUse `git media logs last` to view the log.\n", file)
	}
	os.Exit(2)
}

func Run() {
	RootCmd.Execute()
}

func PipeMediaCommand(name string, args ...string) error {
	return PipeCommand("bin/"+name, args...)
}

func PipeCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

func handlePanic(err error) string {
	if err == nil {
		return ""
	}

	Debug(err.Error())
	return logPanic(err, false)
}

func logEnv(w io.Writer) {
	for _, env := range gitmedia.Environ() {
		fmt.Fprintln(w, env)
	}
}

func logPanic(loggedError error, recursive bool) string {
	var fmtWriter io.Writer = os.Stderr

	if err := os.MkdirAll(gitmedia.LocalLogDir, 0755); err != nil {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s: %s\n\n", gitmedia.LocalLogDir, err.Error())
		return ""
	}

	now := time.Now()
	name := now.Format("2006-01-02T15:04:05.999999999")
	full := filepath.Join(gitmedia.LocalLogDir, name+".log")

	file, err := os.Create(full)
	if err == nil {
		fmtWriter = file
		defer file.Close()
	}

	fmt.Fprintf(fmtWriter, "> %s", filepath.Base(os.Args[0]))
	if len(os.Args) > 0 {
		fmt.Fprintf(fmtWriter, " %s", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprint(fmtWriter, "\n")

	logEnv(fmtWriter)
	fmt.Fprint(fmtWriter, "\n")

	fmtWriter.Write(ErrorBuffer.Bytes())
	fmt.Fprint(fmtWriter, "\n")

	fmt.Fprintln(fmtWriter, loggedError.Error())
	fmtWriter.Write(debug.Stack())

	if err != nil && !recursive {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s\n\n", full)
		logPanic(err, true)
	}

	return full
}

func init() {
	log.SetOutput(ErrorWriter)
}
<|endoftext|>


<commit_before>//
// Copyright © 2011-2017 Guy M. Allard
//
// 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 stompngo

import (
	"log"
	"os"
	"testing"
)

/*
	Test Logger Basic, confirm by observation.
*/
func TestLoggerBasic(t *testing.T) {
	n, _ = openConn(t)
	ch := check11(TEST_HEADERS)
	conn, _ = Connect(n, ch)
	//
	l := log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds)
	conn.SetLogger(l)
	//
	_ = conn.Disconnect(empty_headers)
	_ = closeConn(t, n)

}

/*
	Test Logger with a zero Byte Message, a corner case.  This is merely
	to demonstrate the basics of log output when a logger is set for the
	connection.
*/
func TestLoggerMiscBytes0(t *testing.T) {
	ll := log.New(os.Stdout, "TLM01 ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
	// Write phase
	n, _ = openConn(t)
	ch := check11(TEST_HEADERS)
	conn, _ = Connect(n, ch)
	conn.SetLogger(ll)
	//
	ms := "" // No data
	d := tdest("/queue/logger.zero.byte.msg")
	sh := Headers{HK_DESTINATION, d}
	e = conn.Send(sh, ms)
	if e != nil {
		t.Fatalf("Expected nil error, got [%v]\n", e)
	}
	//
	_ = conn.Disconnect(empty_headers)
	_ = closeConn(t, n)

	// Read phase
	n, _ = openConn(t)
	ch = check11(TEST_HEADERS)
	conn, _ = Connect(n, ch)
	ll = log.New(os.Stdout, "TLM02 ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
	conn.SetLogger(ll)
	//
	sbh := sh.Add(HK_ID, d)
	sc, e = conn.Subscribe(sbh)
	if e != nil {
		t.Fatalf("Expected no subscribe error, got [%v]\n", e)
	}
	if sc == nil {
		t.Fatalf("Expected subscribe channel, got [nil]\n")
	}

	// Read MessageData
	var md MessageData
	select {
	case md = <-sc:
	case md = <-conn.MessageData:
		t.Fatalf("read channel error:  expected [nil], got: [%v]\n",
			md.Message.Command)
	}

	if md.Error != nil {
		t.Fatalf("Expected no message data error, got [%v]\n", md.Error)
	}

	// The real tests here
	if len(md.Message.Body) != 0 {
		t.Fatalf("Expected body length 0, got [%v]\n", len(md.Message.Body))
	}
	if string(md.Message.Body) != ms {
		t.Fatalf("Expected [%v], got [%v]\n", ms, string(md.Message.Body))
	}
	//
	_ = conn.Disconnect(empty_headers)
	_ = closeConn(t, n)

}
<commit_msg>Rework logger tests for all protocols.<commit_after>//
// Copyright © 2011-2017 Guy M. Allard
//
// 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 stompngo

import (
	"log"
	"os"
	"testing"
)

/*
	Test Logger Basic, confirm by observation.
*/
func TestLoggerBasic(t *testing.T) {
	for _, _ = range Protocols() {
		n, _ = openConn(t)
		ch := check11(TEST_HEADERS)
		conn, _ = Connect(n, ch)
		//
		l := log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds)
		conn.SetLogger(l)
		//
		_ = conn.Disconnect(empty_headers)
		_ = closeConn(t, n)
	}

}

/*
	Test Logger with a zero Byte Message, a corner case.  This is merely
	to demonstrate the basics of log output when a logger is set for the
	connection.
*/
func TestLoggerMiscBytes0(t *testing.T) {
	for _, sp := range Protocols() {
		ll := log.New(os.Stdout, "TLM01 ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
		// Write phase
		n, _ = openConn(t)
		ch := login_headers
		ch = headersProtocol(ch, sp)
		conn, _ = Connect(n, ch)
		conn.SetLogger(ll)
		//
		ms := "" // No data
		d := tdest("/queue/logger.zero.byte.msg." + sp)
		sh := Headers{HK_DESTINATION, d}
		e = conn.Send(sh, ms)
		if e != nil {
			t.Fatalf("Expected nil error, got [%v]\n", e)
		}
		//
		_ = conn.Disconnect(empty_headers)
		_ = closeConn(t, n)

		// Read phase
		n, _ = openConn(t)
		ch = login_headers
		ch = headersProtocol(ch, sp)
		conn, _ = Connect(n, ch)
		ll = log.New(os.Stdout, "TLM02 ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
		conn.SetLogger(ll)
		//
		sbh := sh.Add(HK_ID, d)
		sc, e = conn.Subscribe(sbh)
		if e != nil {
			t.Fatalf("Expected no subscribe error, got [%v]\n", e)
		}
		if sc == nil {
			t.Fatalf("Expected subscribe channel, got [nil]\n")
		}

		// Read MessageData
		var md MessageData
		select {
		case md = <-sc:
		case md = <-conn.MessageData:
			t.Fatalf("read channel error:  expected [nil], got: [%v]\n",
				md.Message.Command)
		}

		if md.Error != nil {
			t.Fatalf("Expected no message data error, got [%v]\n", md.Error)
		}

		// The real tests here
		if len(md.Message.Body) != 0 {
			t.Fatalf("Expected body length 0, got [%v]\n", len(md.Message.Body))
		}
		if string(md.Message.Body) != ms {
			t.Fatalf("Expected [%v], got [%v]\n", ms, string(md.Message.Body))
		}
		//
		_ = conn.Disconnect(empty_headers)
		_ = closeConn(t, n)
	}

}
<|endoftext|>


<commit_before>package detailed

import (
	"fmt"
	"sort"
	"strconv"

	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
)

const (
	portKey    = "port"
	portLabel  = "Port"
	countKey   = "count"
	countLabel = "Count"
	number     = "number"
)

// Exported for testing
var (
	NormalColumns = []Column{
		{ID: portKey, Label: portLabel},
		{ID: countKey, Label: countLabel, DefaultSort: true},
	}
	InternetColumns = []Column{
		{ID: "foo", Label: "Remote"},
		{ID: portKey, Label: portLabel},
		{ID: countKey, Label: countLabel, DefaultSort: true},
	}
)

// ConnectionsSummary is the table of connection to/form a node
type ConnectionsSummary struct {
	ID          string       `json:"id"`
	TopologyID  string       `json:"topologyId"`
	Label       string       `json:"label"`
	Columns     []Column     `json:"columns"`
	Connections []Connection `json:"connections"`
}

// Connection is a row in the connections table.
type Connection struct {
	ID       string               `json:"id"`     // ID of this element in the UI.  Must be unique for a given ConnectionsSummary.
	NodeID   string               `json:"nodeId"` // ID of a node in the topology. Optional, must be set if linkable is true.
	Label    string               `json:"label"`
	Linkable bool                 `json:"linkable"`
	Metadata []report.MetadataRow `json:"metadata,omitempty"`
}

type connectionsByID []Connection

func (s connectionsByID) Len() int           { return len(s) }
func (s connectionsByID) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s connectionsByID) Less(i, j int) bool { return s[i].ID < s[j].ID }

// Intermediate type used as a key to dedupe rows
type connection struct {
	remoteNode, localNode *report.Node
	remoteAddr, localAddr string
	port                  string // always the server-side port
}

func (row connection) ID() string {
	return fmt.Sprintf("%s:%s-%s:%s-%s", row.remoteNode.ID, row.remoteAddr, row.localNode.ID, row.localAddr, row.port)
}

func incomingConnectionsSummary(topologyID string, r report.Report, n report.Node, ns report.Nodes) ConnectionsSummary {
	localEndpointIDs := endpointChildIDsOf(n)

	// For each node which has an edge TO me
	counts := map[connection]int{}
	for _, node := range ns {
		if !node.Adjacency.Contains(n.ID) {
			continue
		}
		// Shallow-copy the node to obtain a different pointer
		// on the remote side
		remoteNode := node

		// Work out what port they are talking to, and count the number of
		// connections to that port.
		// This is complicated as for internet nodes we break out individual
		// address, both when the internet node is remote (an incoming
		// connection from the internet) and 'local' (ie you are loading
		// details on the internet node)
		for _, child := range endpointChildrenOf(node) {
			for _, localEndpointID := range child.Adjacency.Intersection(localEndpointIDs) {
				_, localAddr, port, ok := report.ParseEndpointNodeID(localEndpointID)
				if !ok {
					continue
				}
				key := connection{
					localNode:  &n,
					remoteNode: &remoteNode,
					port:       port,
				}
				if isInternetNode(n) {
					endpointNode := r.Endpoint.Nodes[localEndpointID]
					key.localNode = &endpointNode
					key.localAddr = localAddr
				}
				counts[key] = counts[key] + 1
			}
		}
	}

	columnHeaders := NormalColumns
	if isInternetNode(n) {
		columnHeaders = InternetColumns
	}
	return ConnectionsSummary{
		ID:          "incoming-connections",
		TopologyID:  topologyID,
		Label:       "Inbound",
		Columns:     columnHeaders,
		Connections: connectionRows(r, counts, isInternetNode(n)),
	}
}

func outgoingConnectionsSummary(topologyID string, r report.Report, n report.Node, ns report.Nodes) ConnectionsSummary {
	localEndpoints := endpointChildrenOf(n)

	// For each node which has an edge FROM me
	counts := map[connection]int{}
	for _, id := range n.Adjacency {
		node, ok := ns[id]
		if !ok {
			continue
		}

		remoteEndpointIDs := endpointChildIDsOf(node)

		// Shallow-copy the node to obtain a different pointer
		// on the remote side
		remoteNode := node

		for _, localEndpoint := range localEndpoints {
			_, localAddr, _, ok := report.ParseEndpointNodeID(localEndpoint.ID)
			if !ok {
				continue
			}

			for _, remoteEndpointID := range localEndpoint.Adjacency.Intersection(remoteEndpointIDs) {
				_, _, port, ok := report.ParseEndpointNodeID(remoteEndpointID)
				if !ok {
					continue
				}
				key := connection{
					localNode:  &n,
					remoteNode: &remoteNode,
					port:       port,
				}
				if isInternetNode(n) {
					endpointNode := r.Endpoint.Nodes[remoteEndpointID]
					key.localNode = &endpointNode
					key.localAddr = localAddr
				}
				counts[key] = counts[key] + 1
			}
		}
	}

	columnHeaders := NormalColumns
	if isInternetNode(n) {
		columnHeaders = InternetColumns
	}
	return ConnectionsSummary{
		ID:          "outgoing-connections",
		TopologyID:  topologyID,
		Label:       "Outbound",
		Columns:     columnHeaders,
		Connections: connectionRows(r, counts, isInternetNode(n)),
	}
}

func endpointChildrenOf(n report.Node) []report.Node {
	result := []report.Node{}
	n.Children.ForEach(func(child report.Node) {
		if child.Topology == report.Endpoint {
			result = append(result, child)
		}
	})
	return result
}

func endpointChildIDsOf(n report.Node) report.IDList {
	result := report.MakeIDList()
	n.Children.ForEach(func(child report.Node) {
		if child.Topology == report.Endpoint {
			result = result.Add(child.ID)
		}
	})
	return result
}

func isInternetNode(n report.Node) bool {
	return n.ID == render.IncomingInternetID || n.ID == render.OutgoingInternetID
}

func connectionRows(r report.Report, in map[connection]int, includeLocal bool) []Connection {
	output := []Connection{}
	for row, count := range in {
		// Use MakeNodeSummary to render the id and label of this node
		// TODO(paulbellamy): Would be cleaner if we hade just a
		// MakeNodeID(*row.remoteode). As we don't need the whole summary.
		summary, ok := MakeNodeSummary(r, *row.remoteNode)
		connection := Connection{
			ID:       row.ID(),
			NodeID:   summary.ID,
			Label:    summary.Label,
			Linkable: true,
		}
		if !ok && row.remoteAddr != "" {
			connection.Label = row.remoteAddr
			connection.Linkable = false
		}
		if includeLocal {
			// Does localNode have a DNS record in it?
			label := row.localAddr
			if set, ok := row.localNode.Sets.Lookup(endpoint.ReverseDNSNames); ok && len(set) > 0 {
				label = fmt.Sprintf("%s (%s)", set[0], label)
			}
			connection.Metadata = append(connection.Metadata,
				report.MetadataRow{
					ID:       "foo",
					Value:    label,
					Datatype: number,
				})
		}
		connection.Metadata = append(connection.Metadata,
			report.MetadataRow{
				ID:       portKey,
				Value:    row.port,
				Datatype: number,
			},
			report.MetadataRow{
				ID:       countKey,
				Value:    strconv.Itoa(count),
				Datatype: number,
			},
		)
		output = append(output, connection)
	}
	sort.Sort(connectionsByID(output))
	return output
}
<commit_msg>fix internet connection counts<commit_after>package detailed

import (
	"fmt"
	"sort"
	"strconv"

	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
)

const (
	portKey    = "port"
	portLabel  = "Port"
	countKey   = "count"
	countLabel = "Count"
	number     = "number"
)

// Exported for testing
var (
	NormalColumns = []Column{
		{ID: portKey, Label: portLabel},
		{ID: countKey, Label: countLabel, DefaultSort: true},
	}
	InternetColumns = []Column{
		{ID: "foo", Label: "Remote"},
		{ID: portKey, Label: portLabel},
		{ID: countKey, Label: countLabel, DefaultSort: true},
	}
)

// ConnectionsSummary is the table of connection to/form a node
type ConnectionsSummary struct {
	ID          string       `json:"id"`
	TopologyID  string       `json:"topologyId"`
	Label       string       `json:"label"`
	Columns     []Column     `json:"columns"`
	Connections []Connection `json:"connections"`
}

// Connection is a row in the connections table.
type Connection struct {
	ID       string               `json:"id"`     // ID of this element in the UI.  Must be unique for a given ConnectionsSummary.
	NodeID   string               `json:"nodeId"` // ID of a node in the topology. Optional, must be set if linkable is true.
	Label    string               `json:"label"`
	Linkable bool                 `json:"linkable"`
	Metadata []report.MetadataRow `json:"metadata,omitempty"`
}

type connectionsByID []Connection

func (s connectionsByID) Len() int           { return len(s) }
func (s connectionsByID) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s connectionsByID) Less(i, j int) bool { return s[i].ID < s[j].ID }

// Intermediate type used as a key to dedupe rows
type connection struct {
	remoteNodeID, localNodeID string
	remoteAddr, localAddr     string
	port                      string // always the server-side port
}

func (row connection) ID() string {
	return fmt.Sprintf("%s:%s-%s:%s-%s", row.remoteNodeID, row.remoteAddr, row.localNodeID, row.localAddr, row.port)
}

func incomingConnectionsSummary(topologyID string, r report.Report, n report.Node, ns report.Nodes) ConnectionsSummary {
	localEndpointIDs := endpointChildIDsOf(n)

	// For each node which has an edge TO me
	counts := map[connection]int{}
	for _, node := range ns {
		if !node.Adjacency.Contains(n.ID) {
			continue
		}
		// Work out what port they are talking to, and count the number of
		// connections to that port.
		// This is complicated as for internet nodes we break out individual
		// address, both when the internet node is remote (an incoming
		// connection from the internet) and 'local' (ie you are loading
		// details on the internet node)
		for _, child := range endpointChildrenOf(node) {
			for _, localEndpointID := range child.Adjacency.Intersection(localEndpointIDs) {
				_, localAddr, port, ok := report.ParseEndpointNodeID(localEndpointID)
				if !ok {
					continue
				}
				key := connection{
					localNodeID:  n.ID,
					remoteNodeID: node.ID,
					port:         port,
				}
				if isInternetNode(n) {
					key.localNodeID = localEndpointID
					key.localAddr = localAddr
				}
				counts[key] = counts[key] + 1
			}
		}
	}

	columnHeaders := NormalColumns
	if isInternetNode(n) {
		columnHeaders = InternetColumns
	}
	return ConnectionsSummary{
		ID:          "incoming-connections",
		TopologyID:  topologyID,
		Label:       "Inbound",
		Columns:     columnHeaders,
		Connections: connectionRows(r, ns, counts, isInternetNode(n)),
	}
}

func outgoingConnectionsSummary(topologyID string, r report.Report, n report.Node, ns report.Nodes) ConnectionsSummary {
	localEndpoints := endpointChildrenOf(n)

	// For each node which has an edge FROM me
	counts := map[connection]int{}
	for _, id := range n.Adjacency {
		node, ok := ns[id]
		if !ok {
			continue
		}

		remoteEndpointIDs := endpointChildIDsOf(node)

		for _, localEndpoint := range localEndpoints {
			_, localAddr, _, ok := report.ParseEndpointNodeID(localEndpoint.ID)
			if !ok {
				continue
			}

			for _, remoteEndpointID := range localEndpoint.Adjacency.Intersection(remoteEndpointIDs) {
				_, _, port, ok := report.ParseEndpointNodeID(remoteEndpointID)
				if !ok {
					continue
				}
				key := connection{
					localNodeID:  n.ID,
					remoteNodeID: node.ID,
					port:         port,
				}
				if isInternetNode(n) {
					key.localNodeID = remoteEndpointID
					key.localAddr = localAddr
				}
				counts[key] = counts[key] + 1
			}
		}
	}

	columnHeaders := NormalColumns
	if isInternetNode(n) {
		columnHeaders = InternetColumns
	}
	return ConnectionsSummary{
		ID:          "outgoing-connections",
		TopologyID:  topologyID,
		Label:       "Outbound",
		Columns:     columnHeaders,
		Connections: connectionRows(r, ns, counts, isInternetNode(n)),
	}
}

func endpointChildrenOf(n report.Node) []report.Node {
	result := []report.Node{}
	n.Children.ForEach(func(child report.Node) {
		if child.Topology == report.Endpoint {
			result = append(result, child)
		}
	})
	return result
}

func endpointChildIDsOf(n report.Node) report.IDList {
	result := report.MakeIDList()
	n.Children.ForEach(func(child report.Node) {
		if child.Topology == report.Endpoint {
			result = result.Add(child.ID)
		}
	})
	return result
}

func isInternetNode(n report.Node) bool {
	return n.ID == render.IncomingInternetID || n.ID == render.OutgoingInternetID
}

func connectionRows(r report.Report, ns report.Nodes, in map[connection]int, includeLocal bool) []Connection {
	output := []Connection{}
	for row, count := range in {
		// Use MakeNodeSummary to render the id and label of this node
		// TODO(paulbellamy): Would be cleaner if we hade just a
		// MakeNodeID(ns[row.remoteNodeID]). As we don't need the whole summary.
		summary, ok := MakeNodeSummary(r, ns[row.remoteNodeID])
		connection := Connection{
			ID:       row.ID(),
			NodeID:   summary.ID,
			Label:    summary.Label,
			Linkable: true,
		}
		if !ok && row.remoteAddr != "" {
			connection.Label = row.remoteAddr
			connection.Linkable = false
		}
		if includeLocal {
			// Does localNode have a DNS record in it?
			label := row.localAddr
			if set, ok := ns[row.localNodeID].Sets.Lookup(endpoint.ReverseDNSNames); ok && len(set) > 0 {
				label = fmt.Sprintf("%s (%s)", set[0], label)
			}
			connection.Metadata = append(connection.Metadata,
				report.MetadataRow{
					ID:       "foo",
					Value:    label,
					Datatype: number,
				})
		}
		connection.Metadata = append(connection.Metadata,
			report.MetadataRow{
				ID:       portKey,
				Value:    row.port,
				Datatype: number,
			},
			report.MetadataRow{
				ID:       countKey,
				Value:    strconv.Itoa(count),
				Datatype: number,
			},
		)
		output = append(output, connection)
	}
	sort.Sort(connectionsByID(output))
	return output
}
<|endoftext|>


<commit_before>package commands

import (
	cli "github.com/urfave/cli"
)

var Commands = cli.Commands{
	{
		Name:   "add-http",
		Usage:  "Add endpoints to checkup",
		Action: addHTTPEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "name",
				Value: "",
				Usage: "Name of endpoint",
			},
			cli.StringFlag{
				Name:  "url",
				Value: "",
				Usage: "URL to check",
			},
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "add-tcp",
		Usage:  "Add tcp endpoints to checkup",
		Action: addTCPEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "name",
				Value: "",
				Usage: "Name of endpoint",
			},
			cli.StringFlag{
				Name:  "address",
				Value: "",
				Usage: "Address to check",
			},
			cli.BoolFlag{
				Name:  "tls",
				Usage: "Is it tls endpoint?",
			},
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "check",
		Usage:  "list and check endpoints",
		Action: checkEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "list",
		Usage:  "list endpoint",
		Action: listEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "delete",
		Usage:  "delete endpoint",
		Action: deleteEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
			cli.StringFlag{
				Name:  "name",
				Value: "",
				Usage: "endpoint name",
			},
		},
	},
}
<commit_msg>add setup status page in commands<commit_after>package commands

import (
	cli "github.com/urfave/cli"
)

var Commands = cli.Commands{
	{
		Name:   "add-http",
		Usage:  "Add endpoints to checkup",
		Action: addHTTPEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "name",
				Value: "",
				Usage: "Name of endpoint",
			},
			cli.StringFlag{
				Name:  "url",
				Value: "",
				Usage: "URL to check",
			},
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "add-tcp",
		Usage:  "Add tcp endpoints to checkup",
		Action: addTCPEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "name",
				Value: "",
				Usage: "Name of endpoint",
			},
			cli.StringFlag{
				Name:  "address",
				Value: "",
				Usage: "Address to check",
			},
			cli.BoolFlag{
				Name:  "tls",
				Usage: "Is it tls endpoint?",
			},
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "check",
		Usage:  "list and check endpoints",
		Action: checkEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "list",
		Usage:  "list endpoint",
		Action: listEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
		},
	},
	{
		Name:   "delete",
		Usage:  "delete endpoint",
		Action: deleteEndpoint,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "host",
				Value: ":9009",
				Usage: "grpc server address",
			},
			cli.StringFlag{
				Name:  "name",
				Value: "",
				Usage: "endpoint name",
			},
		},
	},
	{
		Name:   "setup-page",
		Usage:  "delete endpoint",
		Action: setupStatusPage,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "url",
				Value: "localhost:80",
				Usage: "url to serve the status page",
			},
			cli.StringFlag{
				Name:  "storage",
				Value: "fs",
				Usage: "storage type",
			},
		},
	},
}
<|endoftext|>


<commit_before>package client

import (
	"github.com/juju/loggo"
	"net/http"
	"net/url"
	"net/http/cookiejar"
	"strings"
)

type simpleWebClient struct {
	client *http.Client
	url    *url.URL
}

var loggerWeb = loggo.GetLogger("web")

func NewSimpleWebClient(ip string) (*simpleWebClient){
	client := http.DefaultClient
	cookieJar, _ := cookiejar.New(nil)
	client.Jar = cookieJar

	if !strings.HasPrefix(ip, "http://") && !strings.HasPrefix(ip, "https://") {
		loggerWeb.Warningf("No scheme for url " + ip + ". Setting scheme to http://" + ip)
		ip = "http://" + ip
	}

	url, err := url.Parse(ip)
	if err != nil {
		panic(err)
	}

	return &simpleWebClient{client, url}
}

func (w *simpleWebClient) Scrap() (*http.Response, error){
	scheme := w.url.Scheme
	host := w.url.Host
	path := w.url.Path

	res, err := w.client.Get(scheme + "://" + host + path)
	if err != nil {
		return nil, err
	}

	//output, err := httputil.DumpResponse(res, true)
	//loggerWeb.Debugf(string(output))

	return res, nil
}

func (w *simpleWebClient) ScrapWithParameter(path string, method string, values url.Values) (*http.Response, error){

	switch {
	case method == "POST" || method == "post" :
		res, err := w.client.PostForm(w.craftUrlPost(path), values)
		if err != nil {
			return nil, err
		}
		return res, nil
	case method == "GET" || method == "get" :
		res, err := w.client.Get(w.craftUrlGet(path, values))
		if err != nil {
			return nil, err
		}

		return res, nil
	default:
		loggerWeb.Criticalf("Method " + method + "does not exist.")
		return nil, nil
	}
}

func (w *simpleWebClient) ScrapWithNoParameter(path string, method string) (*http.Response, error){

	switch {
	case method == "POST" || method == "post" :
		res, err := w.client.PostForm(w.craftUrlPost(path), url.Values{})
		if err != nil {
			return nil, err
		}
		return res, nil
	case method == "GET" || method == "get" :
		res, err := w.client.PostForm(w.craftUrlPost(path), url.Values{})
		if err != nil {
			return nil, err
		}

		return res, nil
	default:
		loggerWeb.Criticalf("Method " + method + "does not exist.")
		return nil, nil
	}
}

func (w *simpleWebClient) craftUrlPost(path string) (string){
	scheme := w.url.Scheme
	host := w.url.Host

	urlToRequest := ""
	if strings.HasPrefix(path,"/") {
		urlToRequest = scheme + "://" + host + path
	}else{
		if  strings.HasPrefix(path,"http"){
			urlToRequest = path
		}else{
			urlToRequest = scheme + "://" + host + "/" + path
		}
	}

	return urlToRequest
}

func (w *simpleWebClient) craftUrlGet(path string, values url.Values) (string){
	scheme := w.url.Scheme
	host := w.url.Host

	urlToRequest := ""
	if strings.HasPrefix("/", path) {
		urlToRequest = scheme + "://" + host + path + "?" + values.Encode()
	}else{
		if  strings.HasPrefix(path,"http"){
			urlToRequest = path + "?" + values.Encode()
		}else{
			urlToRequest = scheme + "://" + host + "/" + path + "?" + values.Encode()
		}
	}

	return urlToRequest
}

func (w *simpleWebClient) GetUrl() (*url.URL) {
	return w.url
}<commit_msg>Use internal craft url function<commit_after>package client

import (
	"github.com/juju/loggo"
	"net/http"
	"net/url"
	"net/http/cookiejar"
	"strings"
)

type simpleWebClient struct {
	client *http.Client
	url    *url.URL
}

var loggerWeb = loggo.GetLogger("web")

func NewSimpleWebClient(ip string) (*simpleWebClient){
	client := http.DefaultClient
	cookieJar, _ := cookiejar.New(nil)
	client.Jar = cookieJar

	if !strings.HasPrefix(ip, "http://") && !strings.HasPrefix(ip, "https://") {
		loggerWeb.Warningf("No scheme for url " + ip + ". Setting scheme to http://" + ip)
		ip = "http://" + ip
	}

	url, err := url.Parse(ip)
	if err != nil {
		panic(err)
	}

	return &simpleWebClient{client, url}
}

func (w *simpleWebClient) Scrap() (*http.Response, error){
	res, err := w.client.Get(w.craftUrlGet(w.url.Path, url.Values{}))
	if err != nil {
		return nil, err
	}

	//output, err := httputil.DumpResponse(res, true)
	//loggerWeb.Debugf(string(output))

	return res, nil
}

func (w *simpleWebClient) ScrapWithParameter(path string, method string, values url.Values) (*http.Response, error){

	switch {
	case method == "POST" || method == "post" :
		res, err := w.client.PostForm(w.craftUrlPost(path), values)
		if err != nil {
			return nil, err
		}
		return res, nil
	case method == "GET" || method == "get" :
		res, err := w.client.Get(w.craftUrlGet(path, values))
		if err != nil {
			return nil, err
		}

		return res, nil
	default:
		loggerWeb.Criticalf("Method " + method + "does not exist.")
		return nil, nil
	}
}

func (w *simpleWebClient) ScrapWithNoParameter(path string, method string) (*http.Response, error){

	switch {
	case method == "POST" || method == "post" :
		res, err := w.client.PostForm(w.craftUrlPost(path), url.Values{})
		if err != nil {
			return nil, err
		}
		return res, nil
	case method == "GET" || method == "get" :
		res, err := w.client.PostForm(w.craftUrlPost(path), url.Values{})
		if err != nil {
			return nil, err
		}

		return res, nil
	default:
		loggerWeb.Criticalf("Method " + method + "does not exist.")
		return nil, nil
	}
}

func (w *simpleWebClient) craftUrlPost(path string) (string){
	scheme := w.url.Scheme
	host := w.url.Host

	urlToRequest := ""
	if strings.HasPrefix(path,"/") {
		urlToRequest = scheme + "://" + host + path
	}else{
		if  strings.HasPrefix(path,"http"){
			urlToRequest = path
		}else{
			urlToRequest = scheme + "://" + host + "/" + path
		}
	}

	return urlToRequest
}

func (w *simpleWebClient) craftUrlGet(path string, values url.Values) (string){
	scheme := w.url.Scheme
	host := w.url.Host

	urlToRequest := ""
	if strings.HasPrefix("/", path) {
		urlToRequest = scheme + "://" + host + path + "?" + values.Encode()
	}else{
		if  strings.HasPrefix(path,"http"){
			urlToRequest = path + "?" + values.Encode()
		}else{
			urlToRequest = scheme + "://" + host + "/" + path + "?" + values.Encode()
		}
	}

	return urlToRequest
}

func (w *simpleWebClient) GetUrl() (*url.URL) {
	return w.url
}<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"strings"
)

// ErrorType signfies a category of errors
type ErrorType uint

// ErrorTypes convey what category of error ocurred
const (
	ErrNormal ErrorType = iota // general errors
	ErrClient                  // error was caused by the client, (e.g. invalid CLI usage)
	// TODO: add more types of errors for better error-specific handling
)

// Error is a struct for marshalling errors
type Error struct {
	Message string
	Code    ErrorType
}

func (e Error) Error() string {
	return e.Message
}

// EncodingType defines a supported encoding
type EncodingType string

// Supported EncodingType constants.
const (
	JSON = "json"
	XML  = "xml"
	Text = "text"
	// TODO: support more encoding types
)

var marshallers = map[EncodingType]Marshaller{
	JSON: func(res Response) ([]byte, error) {
		if res.Error() != nil {
			return json.MarshalIndent(res.Error(), "", "  ")
		}
		return json.MarshalIndent(res.Output(), "", "  ")
	},
	XML: func(res Response) ([]byte, error) {
		if res.Error() != nil {
			return xml.Marshal(res.Error())
		}
		return xml.Marshal(res.Output())
	},
}

// Response is the result of a command request. Handlers write to the response,
// setting Error or Value. Response is returned to the client.
type Response interface {
	Request() Request

	// Set/Return the response Error
	SetError(err error, code ErrorType)
	Error() *Error

	// Sets/Returns the response value
	SetOutput(interface{})
	Output() interface{}

	// Marshal marshals out the response into a buffer. It uses the EncodingType
	// on the Request to chose a Marshaller (Codec).
	Marshal() ([]byte, error)

	// Gets a io.Reader that reads the marshalled output
	Reader() (io.Reader, error)
}

type response struct {
	req   Request
	err   *Error
	value interface{}
	out   io.Reader
}

func (r *response) Request() Request {
	return r.req
}

func (r *response) Output() interface{} {
	return r.value
}

func (r *response) SetOutput(v interface{}) {
	r.value = v
}

func (r *response) Error() *Error {
	return r.err
}

func (r *response) SetError(err error, code ErrorType) {
	r.err = &Error{Message: err.Error(), Code: code}
}

func (r *response) Marshal() ([]byte, error) {
	if r.err == nil && r.value == nil {
		return []byte{}, nil
	}

	fmt.Println(r.req, r.req.Option(EncShort))
	if !r.req.Option(EncShort).Found() {
		return nil, fmt.Errorf("No encoding type was specified")
	}
	enc, err := r.req.Option(EncShort).String()
	if err != nil {
		return nil, err
	}
	encType := EncodingType(strings.ToLower(enc))

	var marshaller Marshaller
	if r.req.Command() != nil && r.req.Command().Marshallers != nil {
		marshaller = r.req.Command().Marshallers[encType]
	}
	if marshaller == nil {
		var ok bool
		marshaller, ok = marshallers[encType]
		if !ok {
			return nil, fmt.Errorf("No marshaller found for encoding type '%s'", enc)
		}
	}

	return marshaller(r)
}

// Reader returns an `io.Reader` representing marshalled output of this Response
// Note that multiple calls to this will return a reference to the same io.Reader
func (r *response) Reader() (io.Reader, error) {
	// if command set value to a io.Reader, use that as our reader
	if r.out == nil {
		if out, ok := r.value.(io.Reader); ok {
			r.out = out
		}
	}

	if r.out == nil {
		// no reader set, so marshal the error or value
		marshalled, err := r.Marshal()
		if err != nil {
			return nil, err
		}

		// create a Reader from the marshalled data
		r.out = bytes.NewReader(marshalled)
	}

	return r.out, nil
}

// NewResponse returns a response to match given Request
func NewResponse(req Request) Response {
	return &response{req: req}
}
<commit_msg>commands: Removed a fmt.Println<commit_after>package commands

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io"
	"strings"
)

// ErrorType signfies a category of errors
type ErrorType uint

// ErrorTypes convey what category of error ocurred
const (
	ErrNormal ErrorType = iota // general errors
	ErrClient                  // error was caused by the client, (e.g. invalid CLI usage)
	// TODO: add more types of errors for better error-specific handling
)

// Error is a struct for marshalling errors
type Error struct {
	Message string
	Code    ErrorType
}

func (e Error) Error() string {
	return e.Message
}

// EncodingType defines a supported encoding
type EncodingType string

// Supported EncodingType constants.
const (
	JSON = "json"
	XML  = "xml"
	Text = "text"
	// TODO: support more encoding types
)

var marshallers = map[EncodingType]Marshaller{
	JSON: func(res Response) ([]byte, error) {
		if res.Error() != nil {
			return json.MarshalIndent(res.Error(), "", "  ")
		}
		return json.MarshalIndent(res.Output(), "", "  ")
	},
	XML: func(res Response) ([]byte, error) {
		if res.Error() != nil {
			return xml.Marshal(res.Error())
		}
		return xml.Marshal(res.Output())
	},
}

// Response is the result of a command request. Handlers write to the response,
// setting Error or Value. Response is returned to the client.
type Response interface {
	Request() Request

	// Set/Return the response Error
	SetError(err error, code ErrorType)
	Error() *Error

	// Sets/Returns the response value
	SetOutput(interface{})
	Output() interface{}

	// Marshal marshals out the response into a buffer. It uses the EncodingType
	// on the Request to chose a Marshaller (Codec).
	Marshal() ([]byte, error)

	// Gets a io.Reader that reads the marshalled output
	Reader() (io.Reader, error)
}

type response struct {
	req   Request
	err   *Error
	value interface{}
	out   io.Reader
}

func (r *response) Request() Request {
	return r.req
}

func (r *response) Output() interface{} {
	return r.value
}

func (r *response) SetOutput(v interface{}) {
	r.value = v
}

func (r *response) Error() *Error {
	return r.err
}

func (r *response) SetError(err error, code ErrorType) {
	r.err = &Error{Message: err.Error(), Code: code}
}

func (r *response) Marshal() ([]byte, error) {
	if r.err == nil && r.value == nil {
		return []byte{}, nil
	}

	if !r.req.Option(EncShort).Found() {
		return nil, fmt.Errorf("No encoding type was specified")
	}
	enc, err := r.req.Option(EncShort).String()
	if err != nil {
		return nil, err
	}
	encType := EncodingType(strings.ToLower(enc))

	var marshaller Marshaller
	if r.req.Command() != nil && r.req.Command().Marshallers != nil {
		marshaller = r.req.Command().Marshallers[encType]
	}
	if marshaller == nil {
		var ok bool
		marshaller, ok = marshallers[encType]
		if !ok {
			return nil, fmt.Errorf("No marshaller found for encoding type '%s'", enc)
		}
	}

	return marshaller(r)
}

// Reader returns an `io.Reader` representing marshalled output of this Response
// Note that multiple calls to this will return a reference to the same io.Reader
func (r *response) Reader() (io.Reader, error) {
	// if command set value to a io.Reader, use that as our reader
	if r.out == nil {
		if out, ok := r.value.(io.Reader); ok {
			r.out = out
		}
	}

	if r.out == nil {
		// no reader set, so marshal the error or value
		marshalled, err := r.Marshal()
		if err != nil {
			return nil, err
		}

		// create a Reader from the marshalled data
		r.out = bytes.NewReader(marshalled)
	}

	return r.out, nil
}

// NewResponse returns a response to match given Request
func NewResponse(req Request) Response {
	return &response{req: req}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Tigera, Inc. All rights reserved.

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

package api

import (
	"github.com/projectcalico/libcalico-go/lib/net"
	"github.com/projectcalico/libcalico-go/lib/numorstring"
)

// A Rule encapsulates a set of match criteria and an action.  Both selector-based security Policy
// and security Profiles reference rules - separated out as a list of rules for both
// ingress and egress packet matching.
//
// Each positive match criteria has a negated version, prefixed with ”Not”. All the match
// criteria within a rule must be satisfied for a packet to match. A single rule can contain
// the positive and negative version of a match and both must be satisfied for the rule to match.
type Rule struct {
	Action string `json:"action" validate:"action"`

	// IPVersion is an optional field that restricts the rule to only match a specific IP
	// version.
	IPVersion *int `json:"ipVersion,omitempty" validate:"omitempty,ipversion"`

	// Protocol is an optional field that restricts the rule to only apply to traffic of
	// a specific IP protocol. Required if any of the EntityRules contain Ports
	// (because ports only apply to certain protocols).
	//
	// Must be one of these string values: "tcp", "udp", "icmp", "icmpv6", "sctp", "udplite"
	// or an integer in the range 1-255.
	Protocol *numorstring.Protocol `json:"protocol,omitempty" validate:"omitempty"`

	// ICMP is an optional field that restricts the rule to apply to a specific type and
	// code of ICMP traffic.  This should only be specified if the Protocol field is set to
	// "icmp" or "icmpv6".
	ICMP *ICMPFields `json:"icmp,omitempty" validate:"omitempty"`

	// NotProtocol is the negated version of the Protocol field.
	NotProtocol *numorstring.Protocol `json:"notProtocol,omitempty" validate:"omitempty"`

	// NotICMP is the negated version of the ICMP field.
	NotICMP *ICMPFields `json:"notICMP,omitempty" validate:"omitempty"`

	// Source contains the match criteria that apply to source entity.
	Source EntityRule `json:"source,omitempty" validate:"omitempty"`

	// Destination contains the match criteria that apply to destination entity.
	Destination EntityRule `json:"destination,omitempty" validate:"omitempty"`
}

// ICMPFields defines structure for ICMP and NotICMP sub-struct for ICMP code and type
type ICMPFields struct {
	// Match on a specific ICMP type.  For example a value of 8 refers to ICMP Echo Request
	// (i.e. pings).
	Type *int `json:"type,omitempty" validate:"omitempty,gte=0,lte=254"`

	// Match on a specific ICMP code.  If specified, the Type value must also be specified.
	// This is a technical limitation imposed by the kernel’s iptables firewall, which
	// Calico uses to enforce the rule.
	Code *int `json:"code,omitempty" validate:"omitempty,gte=0,lte=255"`
}

// An EntityRule is a sub-component of a Rule comprising the match criteria specific
// to a particular entity (that is either the source or destination).
//
// A source EntityRule matches the source endpoint and originating traffic.
// A destination EntityRule matches the destination endpoint and terminating traffic.
type EntityRule struct {
	// Tag is an optional field that restricts the rule to only apply to traffic that
	// originates from (or terminates at) endpoints that have profiles with the given tag
	// in them.
	Tag string `json:"tag,omitempty" validate:"omitempty,tag"`

	// Net is an optional field that restricts the rule to only apply to traffic that
	// originates from (or terminates at) IP addresses in the given subnet.
	// Deprecated: superseded by the Nets field.
	Net *net.IPNet `json:"net,omitempty" validate:"omitempty"`

	// Nets is an optional field that restricts the rule to only apply to traffic that
	// originates from (or terminates at) IP addresses in any of the given subnets.
	Nets []*net.IPNet `json:"nets,omitempty" validate:"omitempty"`

	// Selector is an optional field that contains a selector expression (see Policy for
	// sample syntax).  Only traffic that originates from (terminates at) endpoints matching
	// the selector will be matched.
	//
	// Note that: in addition to the negated version of the Selector (see NotSelector below), the
	// selector expression syntax itself supports negation.  The two types of negation are subtly
	// different. One negates the set of matched endpoints, the other negates the whole match:
	//
	//	Selector = "!has(my_label)" matches packets that are from other Calico-controlled
	// 	endpoints that do not have the label “my_label”.
	//
	// 	NotSelector = "has(my_label)" matches packets that are not from Calico-controlled
	// 	endpoints that do have the label “my_label”.
	//
	// The effect is that the latter will accept packets from non-Calico sources whereas the
	// former is limited to packets from Calico-controlled endpoints.
	Selector string `json:"selector,omitempty" validate:"omitempty,selector"`

	// Ports is an optional field that restricts the rule to only apply to traffic that has a
	// source (destination) port that matches one of these ranges/values. This value is a
	// list of integers or strings that represent ranges of ports.
	//
	// Since only some protocols have ports, if any ports are specified it requires the
	// Protocol match in the Rule to be set to "tcp" or "udp".
	Ports []numorstring.Port `json:"ports,omitempty" validate:"omitempty,dive"`

	// NotTag is the negated version of the Tag field.
	NotTag string `json:"notTag,omitempty" validate:"omitempty,tag"`

	// NotNet is an optional field that restricts the rule to only apply to traffic that
	// does not originate from (or terminate at) an IP address in the given subnet.
	// Deprecated: superseded by NotNets.
	NotNet *net.IPNet `json:"notNet,omitempty" validate:"omitempty"`

	// NotNets is an optional field that restricts the rule to only apply to traffic that
	// does not originate from (or terminate at) an IP address in any of the given subnets.
	NotNets []*net.IPNet `json:"nets,omitempty" validate:"omitempty"`

	// NotSelector is the negated version of the Selector field.  See Selector field for
	// subtleties with negated selectors.
	NotSelector string `json:"notSelector,omitempty" validate:"omitempty,selector"`

	// NotPorts is the negated version of the Ports field.
	//
	// Since only some protocols have ports, if any ports are specified it requires the
	// Protocol match in the Rule to be set to "tcp" or "udp".
	NotPorts []numorstring.Port `json:"notPorts,omitempty" validate:"omitempty,dive"`
}

func combineNets(n *net.IPNet, nets []*net.IPNet) []*net.IPNet {
	if n == nil {
		return nets
	}
	if len(nets) == 0 {
		return []*net.IPNet{n}
	}
	combined := make([]*net.IPNet, len(nets)+1)
	copy(combined, nets)
	combined[len(combined)-1] = n
	return combined
}

// GetNets returns either r.Nets or a slice containing r.Net.  It is useful for unifying the
// two representations.
func (r EntityRule) GetNets() []*net.IPNet {
	return combineNets(r.Net, r.Nets)
}

// GetNets returns either r.NotNets or a slice containing NotNet.  It is useful for unifying the
// two representations.
func (r EntityRule) GetNotNets() []*net.IPNet {
	return combineNets(r.NotNet, r.NotNets)
}
<commit_msg>Fix JSON name of notNets field.<commit_after>// Copyright (c) 2016-2017 Tigera, Inc. All rights reserved.

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

package api

import (
	"github.com/projectcalico/libcalico-go/lib/net"
	"github.com/projectcalico/libcalico-go/lib/numorstring"
)

// A Rule encapsulates a set of match criteria and an action.  Both selector-based security Policy
// and security Profiles reference rules - separated out as a list of rules for both
// ingress and egress packet matching.
//
// Each positive match criteria has a negated version, prefixed with ”Not”. All the match
// criteria within a rule must be satisfied for a packet to match. A single rule can contain
// the positive and negative version of a match and both must be satisfied for the rule to match.
type Rule struct {
	Action string `json:"action" validate:"action"`

	// IPVersion is an optional field that restricts the rule to only match a specific IP
	// version.
	IPVersion *int `json:"ipVersion,omitempty" validate:"omitempty,ipversion"`

	// Protocol is an optional field that restricts the rule to only apply to traffic of
	// a specific IP protocol. Required if any of the EntityRules contain Ports
	// (because ports only apply to certain protocols).
	//
	// Must be one of these string values: "tcp", "udp", "icmp", "icmpv6", "sctp", "udplite"
	// or an integer in the range 1-255.
	Protocol *numorstring.Protocol `json:"protocol,omitempty" validate:"omitempty"`

	// ICMP is an optional field that restricts the rule to apply to a specific type and
	// code of ICMP traffic.  This should only be specified if the Protocol field is set to
	// "icmp" or "icmpv6".
	ICMP *ICMPFields `json:"icmp,omitempty" validate:"omitempty"`

	// NotProtocol is the negated version of the Protocol field.
	NotProtocol *numorstring.Protocol `json:"notProtocol,omitempty" validate:"omitempty"`

	// NotICMP is the negated version of the ICMP field.
	NotICMP *ICMPFields `json:"notICMP,omitempty" validate:"omitempty"`

	// Source contains the match criteria that apply to source entity.
	Source EntityRule `json:"source,omitempty" validate:"omitempty"`

	// Destination contains the match criteria that apply to destination entity.
	Destination EntityRule `json:"destination,omitempty" validate:"omitempty"`
}

// ICMPFields defines structure for ICMP and NotICMP sub-struct for ICMP code and type
type ICMPFields struct {
	// Match on a specific ICMP type.  For example a value of 8 refers to ICMP Echo Request
	// (i.e. pings).
	Type *int `json:"type,omitempty" validate:"omitempty,gte=0,lte=254"`

	// Match on a specific ICMP code.  If specified, the Type value must also be specified.
	// This is a technical limitation imposed by the kernel’s iptables firewall, which
	// Calico uses to enforce the rule.
	Code *int `json:"code,omitempty" validate:"omitempty,gte=0,lte=255"`
}

// An EntityRule is a sub-component of a Rule comprising the match criteria specific
// to a particular entity (that is either the source or destination).
//
// A source EntityRule matches the source endpoint and originating traffic.
// A destination EntityRule matches the destination endpoint and terminating traffic.
type EntityRule struct {
	// Tag is an optional field that restricts the rule to only apply to traffic that
	// originates from (or terminates at) endpoints that have profiles with the given tag
	// in them.
	Tag string `json:"tag,omitempty" validate:"omitempty,tag"`

	// Net is an optional field that restricts the rule to only apply to traffic that
	// originates from (or terminates at) IP addresses in the given subnet.
	// Deprecated: superseded by the Nets field.
	Net *net.IPNet `json:"net,omitempty" validate:"omitempty"`

	// Nets is an optional field that restricts the rule to only apply to traffic that
	// originates from (or terminates at) IP addresses in any of the given subnets.
	Nets []*net.IPNet `json:"nets,omitempty" validate:"omitempty"`

	// Selector is an optional field that contains a selector expression (see Policy for
	// sample syntax).  Only traffic that originates from (terminates at) endpoints matching
	// the selector will be matched.
	//
	// Note that: in addition to the negated version of the Selector (see NotSelector below), the
	// selector expression syntax itself supports negation.  The two types of negation are subtly
	// different. One negates the set of matched endpoints, the other negates the whole match:
	//
	//	Selector = "!has(my_label)" matches packets that are from other Calico-controlled
	// 	endpoints that do not have the label “my_label”.
	//
	// 	NotSelector = "has(my_label)" matches packets that are not from Calico-controlled
	// 	endpoints that do have the label “my_label”.
	//
	// The effect is that the latter will accept packets from non-Calico sources whereas the
	// former is limited to packets from Calico-controlled endpoints.
	Selector string `json:"selector,omitempty" validate:"omitempty,selector"`

	// Ports is an optional field that restricts the rule to only apply to traffic that has a
	// source (destination) port that matches one of these ranges/values. This value is a
	// list of integers or strings that represent ranges of ports.
	//
	// Since only some protocols have ports, if any ports are specified it requires the
	// Protocol match in the Rule to be set to "tcp" or "udp".
	Ports []numorstring.Port `json:"ports,omitempty" validate:"omitempty,dive"`

	// NotTag is the negated version of the Tag field.
	NotTag string `json:"notTag,omitempty" validate:"omitempty,tag"`

	// NotNet is an optional field that restricts the rule to only apply to traffic that
	// does not originate from (or terminate at) an IP address in the given subnet.
	// Deprecated: superseded by NotNets.
	NotNet *net.IPNet `json:"notNet,omitempty" validate:"omitempty"`

	// NotNets is an optional field that restricts the rule to only apply to traffic that
	// does not originate from (or terminate at) an IP address in any of the given subnets.
	NotNets []*net.IPNet `json:"notNets,omitempty" validate:"omitempty"`

	// NotSelector is the negated version of the Selector field.  See Selector field for
	// subtleties with negated selectors.
	NotSelector string `json:"notSelector,omitempty" validate:"omitempty,selector"`

	// NotPorts is the negated version of the Ports field.
	//
	// Since only some protocols have ports, if any ports are specified it requires the
	// Protocol match in the Rule to be set to "tcp" or "udp".
	NotPorts []numorstring.Port `json:"notPorts,omitempty" validate:"omitempty,dive"`
}

func combineNets(n *net.IPNet, nets []*net.IPNet) []*net.IPNet {
	if n == nil {
		return nets
	}
	if len(nets) == 0 {
		return []*net.IPNet{n}
	}
	combined := make([]*net.IPNet, len(nets)+1)
	copy(combined, nets)
	combined[len(combined)-1] = n
	return combined
}

// GetNets returns either r.Nets or a slice containing r.Net.  It is useful for unifying the
// two representations.
func (r EntityRule) GetNets() []*net.IPNet {
	return combineNets(r.Net, r.Nets)
}

// GetNets returns either r.NotNets or a slice containing NotNet.  It is useful for unifying the
// two representations.
func (r EntityRule) GetNotNets() []*net.IPNet {
	return combineNets(r.NotNet, r.NotNets)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sort"
	"strings"

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

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

type warningColumn struct {
	Name string
	Data func(api.Warning) string
}

type cmdWarning struct {
	global *cmdGlobal
}

func (c *cmdWarning) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("warning")
	cmd.Short = i18n.G("Manage warnings")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Manage warnings`))

	// List
	warningListCmd := cmdWarningList{global: c.global, warning: c}
	cmd.AddCommand(warningListCmd.Command())

	// Acknowledge
	warningAcknowledgeCmd := cmdWarningAcknowledge{global: c.global, warning: c}
	cmd.AddCommand(warningAcknowledgeCmd.Command())

	// Show
	warningShowCmd := cmdWarningShow{global: c.global, warning: c}
	cmd.AddCommand(warningShowCmd.Command())

	// Delete
	warningDeleteCmd := cmdWarningDelete{global: c.global, warning: c}
	cmd.AddCommand(warningDeleteCmd.Command())

	return cmd
}

// List
type cmdWarningList struct {
	global  *cmdGlobal
	warning *cmdWarning

	flagColumns string
	flagFormat  string
	flagAll     bool
}

const defaultWarningColumns = "utSscpLl"

func (c *cmdWarningList) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("list", i18n.G("[<remote>:]"))
	cmd.Aliases = []string{"ls"}
	cmd.Short = i18n.G("List warnings")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`List warnings

The -c option takes a (optionally comma-separated) list of arguments
that control which warning attributes to output when displaying in table
or csv format.

Default column layout is: utSscpLl

Column shorthand chars:

    c - Count
    l - Last seen
    L - Location
    f - First seen
    p - Project
    s - Severity
    S - Status
    u - UUID
    t - Type`))

	cmd.Flags().StringVarP(&c.flagColumns, "columns", "c", defaultWarningColumns, i18n.G("Columns")+"``")
	cmd.Flags().StringVarP(&c.flagFormat, "format", "f", "table", i18n.G("Format (csv|json|table|yaml)")+"``")
	cmd.Flags().BoolVarP(&c.flagAll, "all", "a", false, i18n.G("List all warnings")+"``")

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdWarningList) Run(cmd *cobra.Command, args []string) error {
	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	remoteName, _, err := c.global.conf.ParseRemote(remote)
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	allWarnings, err := remoteServer.GetWarnings()
	if err != nil {
		return err
	}

	// Per default, acknowledged and resolved warnings are not shown. Using the --all flag will show
	// those as well.
	var warnings []api.Warning

	if c.flagAll {
		warnings = allWarnings
	} else {
		for _, warning := range allWarnings {
			if warning.Status == "acknowledged" || warning.Status == "resolved" {
				continue
			}

			warnings = append(warnings, warning)
		}
	}

	// Process the columns
	columns, err := c.parseColumns(remoteServer.IsClustered())
	if err != nil {
		return err
	}

	// Render the table
	data := [][]string{}
	for _, warning := range warnings {
		row := []string{}
		for _, column := range columns {
			row = append(row, column.Data(warning))
		}
		data = append(data, row)
	}
	sort.Sort(stringList(data))

	rawData := make([]*api.Warning, len(warnings))
	for i := range warnings {
		rawData[i] = &warnings[i]
	}

	headers := []string{}
	for _, column := range columns {
		headers = append(headers, column.Name)
	}

	return utils.RenderTable(c.flagFormat, headers, data, rawData)
}

func (c *cmdWarningList) countColumnData(warning api.Warning) string {
	return fmt.Sprintf("%d", warning.Count)
}

func (c *cmdWarningList) firstSeenColumnData(warning api.Warning) string {
	return warning.FirstSeenAt.UTC().Format("Jan 2, 2006 at 3:04pm (MST)")
}

func (c *cmdWarningList) lastSeenColumnData(warning api.Warning) string {
	return warning.LastSeenAt.UTC().Format("Jan 2, 2006 at 3:04pm (MST)")
}

func (c *cmdWarningList) locationColumnData(warning api.Warning) string {
	return warning.Location
}

func (c *cmdWarningList) projectColumnData(warning api.Warning) string {
	return warning.Project
}

func (c *cmdWarningList) severityColumnData(warning api.Warning) string {
	return strings.ToUpper(warning.Severity)
}

func (c *cmdWarningList) statusColumnData(warning api.Warning) string {
	return strings.ToUpper(warning.Status)
}

func (c *cmdWarningList) typeColumnData(warning api.Warning) string {
	return warning.Type
}

func (c *cmdWarningList) uuidColumnData(warning api.Warning) string {
	return warning.UUID
}

func (c *cmdWarningList) parseColumns(clustered bool) ([]warningColumn, error) {
	columnsShorthandMap := map[rune]warningColumn{
		'c': {i18n.G("COUNT"), c.countColumnData},
		'f': {i18n.G("FIRST SEEN"), c.firstSeenColumnData},
		'l': {i18n.G("LAST SEEN"), c.lastSeenColumnData},
		'p': {i18n.G("PROJECT"), c.projectColumnData},
		's': {i18n.G("SEVERITY"), c.severityColumnData},
		'S': {i18n.G("STATUS"), c.statusColumnData},
		't': {i18n.G("TYPE"), c.typeColumnData},
		'u': {i18n.G("UUID"), c.uuidColumnData},
	}

	if clustered {
		columnsShorthandMap['L'] = warningColumn{i18n.G("LOCATION"), c.locationColumnData}
	} else {
		if c.flagColumns != defaultWarningColumns {
			if strings.ContainsAny(c.flagColumns, "L") {
				return nil, fmt.Errorf(i18n.G("Can't specify column L when not clustered"))
			}
		}
		c.flagColumns = strings.Replace(c.flagColumns, "L", "", -1)
	}

	columnList := strings.Split(c.flagColumns, ",")

	columns := []warningColumn{}
	for _, columnEntry := range columnList {
		if columnEntry == "" {
			return nil, fmt.Errorf(i18n.G("Empty column entry (redundant, leading or trailing command) in '%s'"), c.flagColumns)
		}

		for _, columnRune := range columnEntry {
			if column, ok := columnsShorthandMap[columnRune]; ok {
				columns = append(columns, column)
			} else {
				return nil, fmt.Errorf(i18n.G("Unknown column shorthand char '%c' in '%s'"), columnRune, columnEntry)
			}
		}
	}

	return columns, nil
}

// Acknowledge
type cmdWarningAcknowledge struct {
	global  *cmdGlobal
	warning *cmdWarning

	flagAll bool
}

func (c *cmdWarningAcknowledge) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("acknowledge", i18n.G("[<remote>:]<warning-uuid>"))
	cmd.Aliases = []string{"ack"}
	cmd.Short = i18n.G("Acknowledge warning")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Acknowledge warning`))

	cmd.RunE = c.Run

	return cmd
}

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

	// Parse remote
	remoteName, UUID, err := c.global.conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	warning := api.WarningPut{Status: "acknowledged"}

	return remoteServer.UpdateWarning(UUID, warning, "")
}

// Show
type cmdWarningShow struct {
	global  *cmdGlobal
	warning *cmdWarning
}

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

	cmd.RunE = c.Run

	return cmd
}

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

	// Parse remote
	remoteName, UUID, err := c.global.conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	warning, _, err := remoteServer.GetWarning(UUID)
	if err != nil {
		return err
	}

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

	fmt.Printf("%s", data)

	return nil
}

// Delete
type cmdWarningDelete struct {
	global  *cmdGlobal
	warning *cmdWarning

	flagAll bool
}

func (c *cmdWarningDelete) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("delete", i18n.G("[<remote>:]<warning-uuid>"))
	cmd.Aliases = []string{"rm"}
	cmd.Short = i18n.G("Delete warning")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Delete warning`))

	cmd.Flags().BoolVarP(&c.flagAll, "all", "a", false, i18n.G("Delete all warnings")+"``")

	cmd.RunE = c.Run

	return cmd
}

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

	// Parse remote
	remoteName, UUID, err := c.global.conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	return remoteServer.DeleteWarning(UUID)
}
<commit_msg>lxc/warning: workaround for subcommand errors<commit_after>package main

import (
	"fmt"
	"sort"
	"strings"

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

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

type warningColumn struct {
	Name string
	Data func(api.Warning) string
}

type cmdWarning struct {
	global *cmdGlobal
}

func (c *cmdWarning) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("warning")
	cmd.Short = i18n.G("Manage warnings")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Manage warnings`))

	// List
	warningListCmd := cmdWarningList{global: c.global, warning: c}
	cmd.AddCommand(warningListCmd.Command())

	// Acknowledge
	warningAcknowledgeCmd := cmdWarningAcknowledge{global: c.global, warning: c}
	cmd.AddCommand(warningAcknowledgeCmd.Command())

	// Show
	warningShowCmd := cmdWarningShow{global: c.global, warning: c}
	cmd.AddCommand(warningShowCmd.Command())

	// Delete
	warningDeleteCmd := cmdWarningDelete{global: c.global, warning: c}
	cmd.AddCommand(warningDeleteCmd.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
}

// List
type cmdWarningList struct {
	global  *cmdGlobal
	warning *cmdWarning

	flagColumns string
	flagFormat  string
	flagAll     bool
}

const defaultWarningColumns = "utSscpLl"

func (c *cmdWarningList) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("list", i18n.G("[<remote>:]"))
	cmd.Aliases = []string{"ls"}
	cmd.Short = i18n.G("List warnings")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`List warnings

The -c option takes a (optionally comma-separated) list of arguments
that control which warning attributes to output when displaying in table
or csv format.

Default column layout is: utSscpLl

Column shorthand chars:

    c - Count
    l - Last seen
    L - Location
    f - First seen
    p - Project
    s - Severity
    S - Status
    u - UUID
    t - Type`))

	cmd.Flags().StringVarP(&c.flagColumns, "columns", "c", defaultWarningColumns, i18n.G("Columns")+"``")
	cmd.Flags().StringVarP(&c.flagFormat, "format", "f", "table", i18n.G("Format (csv|json|table|yaml)")+"``")
	cmd.Flags().BoolVarP(&c.flagAll, "all", "a", false, i18n.G("List all warnings")+"``")

	cmd.RunE = c.Run

	return cmd
}

func (c *cmdWarningList) Run(cmd *cobra.Command, args []string) error {
	// Parse remote
	remote := ""
	if len(args) > 0 {
		remote = args[0]
	}

	remoteName, _, err := c.global.conf.ParseRemote(remote)
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	allWarnings, err := remoteServer.GetWarnings()
	if err != nil {
		return err
	}

	// Per default, acknowledged and resolved warnings are not shown. Using the --all flag will show
	// those as well.
	var warnings []api.Warning

	if c.flagAll {
		warnings = allWarnings
	} else {
		for _, warning := range allWarnings {
			if warning.Status == "acknowledged" || warning.Status == "resolved" {
				continue
			}

			warnings = append(warnings, warning)
		}
	}

	// Process the columns
	columns, err := c.parseColumns(remoteServer.IsClustered())
	if err != nil {
		return err
	}

	// Render the table
	data := [][]string{}
	for _, warning := range warnings {
		row := []string{}
		for _, column := range columns {
			row = append(row, column.Data(warning))
		}
		data = append(data, row)
	}
	sort.Sort(stringList(data))

	rawData := make([]*api.Warning, len(warnings))
	for i := range warnings {
		rawData[i] = &warnings[i]
	}

	headers := []string{}
	for _, column := range columns {
		headers = append(headers, column.Name)
	}

	return utils.RenderTable(c.flagFormat, headers, data, rawData)
}

func (c *cmdWarningList) countColumnData(warning api.Warning) string {
	return fmt.Sprintf("%d", warning.Count)
}

func (c *cmdWarningList) firstSeenColumnData(warning api.Warning) string {
	return warning.FirstSeenAt.UTC().Format("Jan 2, 2006 at 3:04pm (MST)")
}

func (c *cmdWarningList) lastSeenColumnData(warning api.Warning) string {
	return warning.LastSeenAt.UTC().Format("Jan 2, 2006 at 3:04pm (MST)")
}

func (c *cmdWarningList) locationColumnData(warning api.Warning) string {
	return warning.Location
}

func (c *cmdWarningList) projectColumnData(warning api.Warning) string {
	return warning.Project
}

func (c *cmdWarningList) severityColumnData(warning api.Warning) string {
	return strings.ToUpper(warning.Severity)
}

func (c *cmdWarningList) statusColumnData(warning api.Warning) string {
	return strings.ToUpper(warning.Status)
}

func (c *cmdWarningList) typeColumnData(warning api.Warning) string {
	return warning.Type
}

func (c *cmdWarningList) uuidColumnData(warning api.Warning) string {
	return warning.UUID
}

func (c *cmdWarningList) parseColumns(clustered bool) ([]warningColumn, error) {
	columnsShorthandMap := map[rune]warningColumn{
		'c': {i18n.G("COUNT"), c.countColumnData},
		'f': {i18n.G("FIRST SEEN"), c.firstSeenColumnData},
		'l': {i18n.G("LAST SEEN"), c.lastSeenColumnData},
		'p': {i18n.G("PROJECT"), c.projectColumnData},
		's': {i18n.G("SEVERITY"), c.severityColumnData},
		'S': {i18n.G("STATUS"), c.statusColumnData},
		't': {i18n.G("TYPE"), c.typeColumnData},
		'u': {i18n.G("UUID"), c.uuidColumnData},
	}

	if clustered {
		columnsShorthandMap['L'] = warningColumn{i18n.G("LOCATION"), c.locationColumnData}
	} else {
		if c.flagColumns != defaultWarningColumns {
			if strings.ContainsAny(c.flagColumns, "L") {
				return nil, fmt.Errorf(i18n.G("Can't specify column L when not clustered"))
			}
		}
		c.flagColumns = strings.Replace(c.flagColumns, "L", "", -1)
	}

	columnList := strings.Split(c.flagColumns, ",")

	columns := []warningColumn{}
	for _, columnEntry := range columnList {
		if columnEntry == "" {
			return nil, fmt.Errorf(i18n.G("Empty column entry (redundant, leading or trailing command) in '%s'"), c.flagColumns)
		}

		for _, columnRune := range columnEntry {
			if column, ok := columnsShorthandMap[columnRune]; ok {
				columns = append(columns, column)
			} else {
				return nil, fmt.Errorf(i18n.G("Unknown column shorthand char '%c' in '%s'"), columnRune, columnEntry)
			}
		}
	}

	return columns, nil
}

// Acknowledge
type cmdWarningAcknowledge struct {
	global  *cmdGlobal
	warning *cmdWarning

	flagAll bool
}

func (c *cmdWarningAcknowledge) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("acknowledge", i18n.G("[<remote>:]<warning-uuid>"))
	cmd.Aliases = []string{"ack"}
	cmd.Short = i18n.G("Acknowledge warning")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Acknowledge warning`))

	cmd.RunE = c.Run

	return cmd
}

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

	// Parse remote
	remoteName, UUID, err := c.global.conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	warning := api.WarningPut{Status: "acknowledged"}

	return remoteServer.UpdateWarning(UUID, warning, "")
}

// Show
type cmdWarningShow struct {
	global  *cmdGlobal
	warning *cmdWarning
}

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

	cmd.RunE = c.Run

	return cmd
}

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

	// Parse remote
	remoteName, UUID, err := c.global.conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	warning, _, err := remoteServer.GetWarning(UUID)
	if err != nil {
		return err
	}

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

	fmt.Printf("%s", data)

	return nil
}

// Delete
type cmdWarningDelete struct {
	global  *cmdGlobal
	warning *cmdWarning

	flagAll bool
}

func (c *cmdWarningDelete) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("delete", i18n.G("[<remote>:]<warning-uuid>"))
	cmd.Aliases = []string{"rm"}
	cmd.Short = i18n.G("Delete warning")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Delete warning`))

	cmd.Flags().BoolVarP(&c.flagAll, "all", "a", false, i18n.G("Delete all warnings")+"``")

	cmd.RunE = c.Run

	return cmd
}

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

	// Parse remote
	remoteName, UUID, err := c.global.conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	remoteServer, err := c.global.conf.GetInstanceServer(remoteName)
	if err != nil {
		return err
	}

	return remoteServer.DeleteWarning(UUID)
}
<|endoftext|>


<commit_before>// LXD external REST API
//
// This is the REST API used by all LXD clients.
// Internal endpoints aren't included in this documentation.
//
// The LXD API is available over both a local unix+http and remote https API.
// Authentication for local users relies on group membership and access to the unix socket.
// For remote users, the default authentication method is TLS client
// certificates with a macaroon based (candid) authentication method also
// supported.
//
// WARNING: This API documentation is a work in progress.
// You may find the full documentation in its old format at "doc/rest-api.md".
//
//     Version: 1.0
//     License: Apache-2.0 https://www.apache.org/licenses/LICENSE-2.0
//     Contact: LXD upstream <lxc-devel@lists.linuxcontainers.org> https://github.com/lxc/lxd
//
// swagger:meta
package main

import (
	"github.com/lxc/lxd/shared/api"
)

// Common error definitions.

// Operation
//
// swagger:response Operation
type swaggerOperation struct {
	// Empty sync response
	// in: body
	Body struct {
		// Example: async
		Type string `json:"type"`

		// Example: Operation created
		Status string `json:"status"`

		// Example: 100
		StatusCode int `json:"status_code"`

		// Example: /1.0/operations/66e83638-9dd7-4a26-aef2-5462814869a1
		Operation string `json:"operation"`

		Metadata api.Operation
	}
}

// Empty sync response
//
// swagger:response EmptySyncResponse
type swaggerEmptySyncResponse struct {
	// Empty sync response
	// in: body
	Body struct {
		// Example: sync
		Type string `json:"type"`

		// Example: Success
		Status string `json:"status"`

		// Example: 200
		StatusCode int `json:"status_code"`
	}
}

// Bad Request
//
// swagger:response BadRequest
type swaggerBadRequest struct {
	// Bad Request
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 400
		Code int `json:"code"`

		// Example: bad request
		Error string `json:"error"`
	}
}

// Forbidden
//
// swagger:response Forbidden
type swaggerForbidden struct {
	// Bad Request
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 403
		Code int `json:"code"`

		// Example: not authorized
		Error string `json:"error"`
	}
}

// Precondition Failed
//
// swagger:response PreconditionFailed
type swaggerPreconditionFailed struct {
	// Internal server Error
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 412
		Code int `json:"code"`

		// Example: precondition failed
		Error string `json:"error"`
	}
}

// Internal Server Error
//
// swagger:response InternalServerError
type swaggerInternalServerError struct {
	// Internal server Error
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 500
		Code int `json:"code"`

		// Example: internal server error
		Error string `json:"error"`
	}
}
<commit_msg>lxd/swagger: Add NotFound response<commit_after>// LXD external REST API
//
// This is the REST API used by all LXD clients.
// Internal endpoints aren't included in this documentation.
//
// The LXD API is available over both a local unix+http and remote https API.
// Authentication for local users relies on group membership and access to the unix socket.
// For remote users, the default authentication method is TLS client
// certificates with a macaroon based (candid) authentication method also
// supported.
//
// WARNING: This API documentation is a work in progress.
// You may find the full documentation in its old format at "doc/rest-api.md".
//
//     Version: 1.0
//     License: Apache-2.0 https://www.apache.org/licenses/LICENSE-2.0
//     Contact: LXD upstream <lxc-devel@lists.linuxcontainers.org> https://github.com/lxc/lxd
//
// swagger:meta
package main

import (
	"github.com/lxc/lxd/shared/api"
)

// Common error definitions.

// Operation
//
// swagger:response Operation
type swaggerOperation struct {
	// Empty sync response
	// in: body
	Body struct {
		// Example: async
		Type string `json:"type"`

		// Example: Operation created
		Status string `json:"status"`

		// Example: 100
		StatusCode int `json:"status_code"`

		// Example: /1.0/operations/66e83638-9dd7-4a26-aef2-5462814869a1
		Operation string `json:"operation"`

		Metadata api.Operation
	}
}

// Empty sync response
//
// swagger:response EmptySyncResponse
type swaggerEmptySyncResponse struct {
	// Empty sync response
	// in: body
	Body struct {
		// Example: sync
		Type string `json:"type"`

		// Example: Success
		Status string `json:"status"`

		// Example: 200
		StatusCode int `json:"status_code"`
	}
}

// Bad Request
//
// swagger:response BadRequest
type swaggerBadRequest struct {
	// Bad Request
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 400
		Code int `json:"code"`

		// Example: bad request
		Error string `json:"error"`
	}
}

// Forbidden
//
// swagger:response Forbidden
type swaggerForbidden struct {
	// Bad Request
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 403
		Code int `json:"code"`

		// Example: not authorized
		Error string `json:"error"`
	}
}

// Precondition Failed
//
// swagger:response PreconditionFailed
type swaggerPreconditionFailed struct {
	// Internal server Error
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 412
		Code int `json:"code"`

		// Example: precondition failed
		Error string `json:"error"`
	}
}

// Internal Server Error
//
// swagger:response InternalServerError
type swaggerInternalServerError struct {
	// Internal server Error
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 500
		Code int `json:"code"`

		// Example: internal server error
		Error string `json:"error"`
	}
}

// Not found
//
// swagger:response NotFound
type swaggerNotFound struct {
	// Not found
	// in: body
	Body struct {
		// Example: error
		Type string `json:"type"`

		// Example: 404
		Code int `json:"code"`

		// Example: not found
		Error string `json:"error"`
	}
}
<|endoftext|>