<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
)

type AuroraCLI struct {
	cfg        *BuildConfig
	verbose    bool
	buildDir   string
	configFile string
	o          *log.Logger
}

type BuildConfig struct {
	AppName    string `json:"name"`
	Version    string `json:"version"`
	Public     string `json:"public"`
	Templates  string `json:"templates"`
	Dest       string `json:"dest"`
	Watch      bool   `json:"wtach"`
	Src        string `json:"src"`
	WorkingDir string `json:"-"`
	ConfigDir  string `json:"config"`
	DBDIr      string `json:"database_dir"`
}

func NewCLI() *AuroraCLI {
	return &AuroraCLI{verbose: false, o: log.New(os.Stdout, "", log.Lshortfile)}
}

func (a *AuroraCLI) Setup() {
	a.log("==>geting dependencies")
	out, err := exec.Command("go", "get", "-v").Output()
	a.logErr(err)
	if len(out) > 0 {
		a.log(fmt.Sprintf("%s \n", out))
	}
	a.log("done")

	a.log("==>checking directories")
	bd := path.Join(a.cfg.WorkingDir, path.Join(a.cfg.Dest, a.cfg.Version))
	a.logErr(os.MkdirAll(bd, 0700))
	a.buildDir = bd
	a.clean()
	a.log("done")
}
func (a *AuroraCLI) RunTests() {
	a.log("==>running tests")
	if a.verbose {
		out, err := exec.Command("go", "test", "-v").Output()
		a.logErr(err)
		if len(out) > 0 {
			a.log(fmt.Sprintf("%s", out))
		}
	} else {
		out, err := exec.Command("go", "test").Output()
		a.logErr(err)
		if len(out) > 0 {
			a.log(fmt.Sprintf("%s", out))
		}
	}
	a.log("done")
}
func (a *AuroraCLI) CreateBinary() {
	a.log("==>Creating executable")
	o := filepath.Join(a.cfg.Dest, filepath.Join(a.cfg.Version, a.cfg.AppName))
	src := filepath.Join(a.cfg.Src, a.cfg.AppName+".go")
	out, err := exec.Command("go", "build", "-o", o, "-v", src).Output()
	a.logErr(err)
	if len(out) > 0 {
		a.log(fmt.Sprintf("%s", out))
	}
	a.log("done")
}
func (a *AuroraCLI) Assemble() {
	// copy public folder
	a.logErr(a.copyDir(a.cfg.Public, path.Join(a.buildDir, a.cfg.Public)))

	//  copy templates
	a.logErr(a.copyDir(a.cfg.Templates, path.Join(a.buildDir, a.cfg.Templates)))

	// copy application configurations
	appCfg := path.Join(a.buildDir, path.Join(a.cfg.ConfigDir, "app"))
	a.logErr(a.copyDir(path.Join(a.cfg.ConfigDir, "app"), appCfg))

}
func (a *AuroraCLI) SetupDatabase() {
	// create database directory
	if a.cfg.DBDIr == "" {
		a.logErr(os.MkdirAll(path.Join(a.buildDir, "db"), 0700))
	} else if path.IsAbs(a.cfg.DBDIr) {
		a.logErr(os.MkdirAll(a.cfg.DBDIr, 0700))
	} else {
		a.logErr(os.MkdirAll(path.Join(a.buildDir, a.cfg.DBDIr), 0700))
	}
}
func (a *AuroraCLI) Build() {
	// load configuration file
	a.logErr(a.loadConfig())

	// setup build env
	a.Setup()

	// run tests
	a.RunTests()

	// create binary
	a.CreateBinary()

	// assemble evrything into the build directory
	a.Assemble()

	// setup database
	a.SetupDatabase()
}
func (a *AuroraCLI) loadConfig() error {
	a.log("==>loading configuration")
	cfg := new(BuildConfig)
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}
	cfgFile := filepath.Join(pwd, a.configFile)
	d, err := ioutil.ReadFile(cfgFile)
	if err != nil {
		return err
	}
	err = json.Unmarshal(d, cfg)
	if err != nil {
		return err
	}
	cfg.WorkingDir = pwd
	a.cfg = cfg
	a.log("done")
	return nil
}

func (a *AuroraCLI) log(msg interface{}) {
	if a.verbose {
		a.o.Output(2, fmt.Sprintln(msg))
	}
}
func (a *AuroraCLI) logErr(err error) {
	if err != nil {
		a.o.Output(2, fmt.Sprintln(err))
		os.Exit(1)
	}
}

func (a *AuroraCLI) copyDir(src, dest string) (err error) {

	// get properties of source dir
	sourceinfo, err := os.Stat(src)
	if err != nil {
		return err
	}

	// create dest dir

	err = os.MkdirAll(dest, sourceinfo.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(src)

	objects, err := directory.Readdir(-1)

	for _, obj := range objects {

		sourcefilepointer := src + "/" + obj.Name()

		destinationfilepointer := dest + "/" + obj.Name()

		if obj.IsDir() {
			// create sub-directories - recursively
			err = a.copyDir(sourcefilepointer, destinationfilepointer)
			if err != nil {
				break
			}
		} else {
			// perform copy
			err = a.copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				break
			}
		}

	}
	return
}

func (a *AuroraCLI) copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	_, err = io.Copy(destfile, sourcefile)
	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}

	return
}
func (a *AuroraCLI) clean() {
	a.log("cleaning build dir")
	a.logErr(os.RemoveAll(a.buildDir))
}
func main() {
	v := flag.Bool("v", false, "logs build messages on stdout")
	c := flag.String("c", "config/build/build.json", "specifies wich configuration file to use")
	flag.Parse()
	a := NewCLI()
	if *v {
		a.verbose = true
	}
	a.configFile = *c
	a.Build()
}
<commit_msg>fix build<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
)

type AuroraCLI struct {
	cfg        *BuildConfig
	verbose    bool
	buildDir   string
	configFile string
	o          *log.Logger
}

type BuildConfig struct {
	AppName    string `json:"name"`
	Version    string `json:"version"`
	Public     string `json:"public"`
	Templates  string `json:"templates"`
	Dest       string `json:"dest"`
	Watch      bool   `json:"wtach"`
	Src        string `json:"src"`
	WorkingDir string `json:"-"`
	ConfigDir  string `json:"config"`
	DBDIr      string `json:"database_dir"`
}

func NewCLI() *AuroraCLI {
	return &AuroraCLI{verbose: false, o: log.New(os.Stdout, "", log.Ltime)}
}

func (a *AuroraCLI) Setup() {
	a.log("===SETUP")
	out, err := exec.Command("go", "get", "-v").Output()
	a.logErr(err)
	if len(out) > 0 {
		a.log(fmt.Sprintf("%s \n", out))
	}
	bd := path.Join(a.cfg.WorkingDir, path.Join(a.cfg.Dest, a.cfg.Version))
	a.logErr(os.MkdirAll(bd, 0700))
	a.buildDir = bd
	a.clean()
	a.log("---DONE")
}
func (a *AuroraCLI) RunTests() {
	a.log("===TESTING")
	if a.verbose {
		out, err := exec.Command("godep", "go", "test", "-v").Output()
		a.logErr(err)
		if len(out) > 0 {
			a.log(fmt.Sprintf("%s", out))
		}
	} else {
		out, err := exec.Command("go", "test").Output()
		a.logErr(err)
		if len(out) > 0 {
			a.log(fmt.Sprintf("%s", out))
		}
	}
	a.log("---DONE")
}
func (a *AuroraCLI) CreateBinary() {
	a.log("===CREATING BINARY")
	o := filepath.Join(a.cfg.Dest, filepath.Join(a.cfg.Version, a.cfg.AppName))
	src := filepath.Join(a.cfg.Src, a.cfg.AppName+".go")
	out, err := exec.Command("go", "build", "-o", o, "-v", src).Output()
	a.logErr(err)
	if len(out) > 0 {
		a.log(fmt.Sprintf("%s", out))
	}
	a.log("---DONE")
}
func (a *AuroraCLI) Assemble() {
	a.log("===ASSEMBLING")
	// copy public folder
	a.logErr(a.copyDir(a.cfg.Public, path.Join(a.buildDir, a.cfg.Public)))

	//  copy templates
	a.logErr(a.copyDir(a.cfg.Templates, path.Join(a.buildDir, a.cfg.Templates)))

	// copy application configurations
	appCfg := path.Join(a.buildDir, path.Join(a.cfg.ConfigDir, "app"))
	a.logErr(a.copyDir(path.Join(a.cfg.ConfigDir, "app"), appCfg))
	a.log("---DONE")

}
func (a *AuroraCLI) SetupDatabase() {
	a.log("===SETUP DATABASE")

	// create database directory
	if a.cfg.DBDIr == "" {
		a.logErr(os.MkdirAll(path.Join(a.buildDir, "db"), 0700))
	} else if path.IsAbs(a.cfg.DBDIr) {
		a.logErr(os.MkdirAll(a.cfg.DBDIr, 0700))
	} else {
		a.logErr(os.MkdirAll(path.Join(a.buildDir, a.cfg.DBDIr), 0700))
	}
	a.log("---DONE")
}
func (a *AuroraCLI) Build() {
	// load configuration file
	a.logErr(a.loadConfig())

	// setup build env
	a.Setup()

	// run tests
	a.RunTests()

	// create binary
	a.CreateBinary()

	// assemble evrything into the build directory
	a.Assemble()

	// setup database
	a.SetupDatabase()

	a.log("[SUCCESS] build complete.")
}
func (a *AuroraCLI) loadConfig() error {
	a.log("===CONFIGURING BUILD")
	cfg := new(BuildConfig)
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}
	cfgFile := filepath.Join(pwd, a.configFile)
	d, err := ioutil.ReadFile(cfgFile)
	if err != nil {
		return err
	}
	err = json.Unmarshal(d, cfg)
	if err != nil {
		return err
	}
	cfg.WorkingDir = pwd
	a.cfg = cfg
	a.log("---DONE")
	return nil
}

func (a *AuroraCLI) log(msg interface{}) {
	if a.verbose {
		a.o.Output(2, fmt.Sprintln(msg))
	}
}
func (a *AuroraCLI) logErr(err error) {
	if err != nil {
		a.o.Output(2, fmt.Sprintln(err))
		os.Exit(1)
	}
}

func (a *AuroraCLI) copyDir(src, dest string) (err error) {

	// get properties of source dir
	sourceinfo, err := os.Stat(src)
	if err != nil {
		return err
	}

	// create dest dir

	err = os.MkdirAll(dest, sourceinfo.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(src)

	objects, err := directory.Readdir(-1)

	for _, obj := range objects {

		sourcefilepointer := src + "/" + obj.Name()

		destinationfilepointer := dest + "/" + obj.Name()

		if obj.IsDir() {
			// create sub-directories - recursively
			err = a.copyDir(sourcefilepointer, destinationfilepointer)
			if err != nil {
				break
			}
		} else {
			// perform copy
			err = a.copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				break
			}
		}

	}
	return
}

func (a *AuroraCLI) copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	_, err = io.Copy(destfile, sourcefile)
	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}

	return
}
func (a *AuroraCLI) clean() {
	a.log("===CLEANING")
	a.logErr(os.RemoveAll(a.buildDir))
	a.log("---DONE")
}
func main() {
	v := flag.Bool("v", false, "logs build messages on stdout")
	c := flag.String("c", "config/build/build.json", "specifies wich configuration file to use")
	flag.Parse()
	a := NewCLI()
	if *v {
		a.verbose = true
	}
	a.configFile = *c
	a.Build()
}
<|endoftext|>


<commit_before>package middleware

import (
	"fmt"
	"net"
	"time"

	"github.com/ant0ine/go-json-rest/rest"

	"github.com/tidepool-org/platform/request"
	"github.com/tidepool-org/platform/service"
)

type AccessLog struct{}

const (
	_LogErrors           = "errors"
	_LogMethod           = "method"
	_LogProto            = "proto"
	_LogRefererer        = "referrer"
	_LogRemoteAddress    = "remote-address"
	_LogRemoteUser       = "remote-user"
	_LogRequestURI       = "request-uri"
	_LogResponseBytes    = "response-bytes"
	_LogResponseDuration = "response-duration"
	_LogStartTime        = "start-time"
	_LogStatusCode       = "status-code"
	_LogUserAgent        = "user-agent"

	_RequestEnvBytesWritten = "BYTE_WRITTEN"
	_RequestEnvElapsedTime  = "ELAPSED_TIME"
	_RequestEnvRemoteUser   = "REMOTE_USER"
	_RequestEnvStartTime    = "START_TIME"
	_RequestEnvStatusCode   = "STATUS_CODE"
)

func NewAccessLog() (*AccessLog, error) {
	return &AccessLog{}, nil
}

func (a *AccessLog) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
	return func(res rest.ResponseWriter, req *rest.Request) {
		if handler != nil && res != nil && req != nil {
			handler(res, req)

			// DEPRECATED: Needs to be replaced with context version
			if logger := service.GetRequestLogger(req); logger != nil {
				loggerFields := map[string]interface{}{}
				if method := req.Method; method != "" {
					loggerFields[_LogMethod] = method
				}
				if uri := req.URL.RequestURI(); uri != "" {
					loggerFields[_LogRequestURI] = uri
				}
				if proto := req.Proto; proto != "" {
					loggerFields[_LogProto] = proto
				}
				if agent := req.UserAgent(); agent != "" {
					loggerFields[_LogUserAgent] = agent
				}
				if referer := req.Referer(); referer != "" {
					loggerFields[_LogRefererer] = referer
				}
				if remoteAddress := req.RemoteAddr; remoteAddress != "" {
					if ip, _, err := net.SplitHostPort(remoteAddress); err == nil && ip != "" {
						loggerFields[_LogRemoteAddress] = ip
					}
				}
				if remoteUser, ok := req.Env[_RequestEnvRemoteUser].(string); ok && remoteUser != "" {
					loggerFields[_LogRemoteUser] = remoteUser
				}
				if startTime, ok := req.Env[_RequestEnvStartTime].(*time.Time); ok {
					loggerFields[_LogStartTime] = startTime.Truncate(time.Microsecond).Format(time.RFC3339Nano)
				}
				if statusCode, ok := req.Env[_RequestEnvStatusCode].(int); ok {
					loggerFields[_LogStatusCode] = statusCode
				}
				if responseTime, ok := req.Env[_RequestEnvElapsedTime].(*time.Duration); ok {
					loggerFields[_LogResponseDuration] = *responseTime / time.Microsecond
				}
				if bytesWritten, ok := req.Env[_RequestEnvBytesWritten].(int64); ok {
					loggerFields[_LogResponseBytes] = bytesWritten
				}
				if errors := service.GetRequestErrors(req); errors != nil {
					loggerFields[_LogErrors] = errors // TODO: Limit to a maximum size?
				}

				message := fmt.Sprintf("%s %s", req.Method, req.URL.RequestURI())

				// TODO: Log this to a special logger level "access".
				// Will need to revamp log package, though.

				logger.WithError(request.GetErrorFromContext(req.Context())).WithFields(loggerFields).Warn(message)
			}
		}
	}
}
<commit_msg>Do not log status pings.<commit_after>package middleware

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/ant0ine/go-json-rest/rest"

	"github.com/tidepool-org/platform/request"
	"github.com/tidepool-org/platform/service"
)

type AccessLog struct{}

const (
	_LogErrors           = "errors"
	_LogMethod           = "method"
	_LogProto            = "proto"
	_LogRefererer        = "referrer"
	_LogRemoteAddress    = "remote-address"
	_LogRemoteUser       = "remote-user"
	_LogRequestURI       = "request-uri"
	_LogResponseBytes    = "response-bytes"
	_LogResponseDuration = "response-duration"
	_LogStartTime        = "start-time"
	_LogStatusCode       = "status-code"
	_LogUserAgent        = "user-agent"

	_RequestEnvBytesWritten = "BYTE_WRITTEN"
	_RequestEnvElapsedTime  = "ELAPSED_TIME"
	_RequestEnvRemoteUser   = "REMOTE_USER"
	_RequestEnvStartTime    = "START_TIME"
	_RequestEnvStatusCode   = "STATUS_CODE"
)

func NewAccessLog() (*AccessLog, error) {
	return &AccessLog{}, nil
}

func (a *AccessLog) ignore(req *rest.Request) bool {
	// ignore liveness and readiness probes
	if strings.Compare(req.URL.RequestURI(), "/status") == 0 {
		return true
	}
	return false
}

// MiddlewareFunc adds logging of all calls, except those ignored above.
func (a *AccessLog) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
	return func(res rest.ResponseWriter, req *rest.Request) {
		if handler != nil && res != nil && req != nil {
			handler(res, req)

			if a.ignore(req) {
				return
			}

			// DEPRECATED: Needs to be replaced with context version
			if logger := service.GetRequestLogger(req); logger != nil {
				loggerFields := map[string]interface{}{}
				if method := req.Method; method != "" {
					loggerFields[_LogMethod] = method
				}
				if uri := req.URL.RequestURI(); uri != "" {
					loggerFields[_LogRequestURI] = uri
				}
				if proto := req.Proto; proto != "" {
					loggerFields[_LogProto] = proto
				}
				if agent := req.UserAgent(); agent != "" {
					loggerFields[_LogUserAgent] = agent
				}
				if referer := req.Referer(); referer != "" {
					loggerFields[_LogRefererer] = referer
				}
				if remoteAddress := req.RemoteAddr; remoteAddress != "" {
					if ip, _, err := net.SplitHostPort(remoteAddress); err == nil && ip != "" {
						loggerFields[_LogRemoteAddress] = ip
					}
				}
				if remoteUser, ok := req.Env[_RequestEnvRemoteUser].(string); ok && remoteUser != "" {
					loggerFields[_LogRemoteUser] = remoteUser
				}
				if startTime, ok := req.Env[_RequestEnvStartTime].(*time.Time); ok {
					loggerFields[_LogStartTime] = startTime.Truncate(time.Microsecond).Format(time.RFC3339Nano)
				}
				if statusCode, ok := req.Env[_RequestEnvStatusCode].(int); ok {
					loggerFields[_LogStatusCode] = statusCode
				}
				if responseTime, ok := req.Env[_RequestEnvElapsedTime].(*time.Duration); ok {
					loggerFields[_LogResponseDuration] = *responseTime / time.Microsecond
				}
				if bytesWritten, ok := req.Env[_RequestEnvBytesWritten].(int64); ok {
					loggerFields[_LogResponseBytes] = bytesWritten
				}
				if errors := service.GetRequestErrors(req); errors != nil {
					loggerFields[_LogErrors] = errors // TODO: Limit to a maximum size?
				}

				message := fmt.Sprintf("%s %s", req.Method, req.URL.RequestURI())

				// TODO: Log this to a special logger level "access".
				// Will need to revamp log package, though.

				logger.WithError(request.GetErrorFromContext(req.Context())).WithFields(loggerFields).Warn(message)
			}
		}
	}
}
<|endoftext|>


<commit_before>package opentsdb_test

import (
	"testing"

	"github.com/BurntSushi/toml"
	"github.com/influxdb/influxdb/services/opentsdb"
)

func TestConfig_Parse(t *testing.T) {
	// Parse configuration.
	var c opentsdb.Config
	if _, err := toml.Decode(`
enabled = true
bind-address = ":9000"
database = "xxx"
consistency-level ="all"
tls-enabled = true
certificate = "/etc/ssl/cert.pem"
`, &c); err != nil {
		t.Fatal(err)
	}

	// Validate configuration.
	if c.Enabled != true {
		t.Fatalf("unexpected enabled: %v", c.Enabled)
	} else if c.BindAddress != ":9000" {
		t.Fatalf("unexpected bind address: %s", c.BindAddress)
	} else if c.Database != "xxx" {
		t.Fatalf("unexpected database: %s", c.Database)
	} else if c.ConsistencyLevel != "all" {
		t.Fatalf("unexpected consistency-level: %s", c.ConsistencyLevel)
	} else if c.TLSEnabled != true {
		t.Fatalf("unexpected tls-enabled: %s", c.TLSEnabled)
	} else if c.Certificate != "/etc/ssl/cert.pem" {
		t.Fatalf("unexpected certificate: %s", c.Certificate)
	}
}
<commit_msg>Fix go vet<commit_after>package opentsdb_test

import (
	"testing"

	"github.com/BurntSushi/toml"
	"github.com/influxdb/influxdb/services/opentsdb"
)

func TestConfig_Parse(t *testing.T) {
	// Parse configuration.
	var c opentsdb.Config
	if _, err := toml.Decode(`
enabled = true
bind-address = ":9000"
database = "xxx"
consistency-level ="all"
tls-enabled = true
certificate = "/etc/ssl/cert.pem"
`, &c); err != nil {
		t.Fatal(err)
	}

	// Validate configuration.
	if c.Enabled != true {
		t.Fatalf("unexpected enabled: %v", c.Enabled)
	} else if c.BindAddress != ":9000" {
		t.Fatalf("unexpected bind address: %s", c.BindAddress)
	} else if c.Database != "xxx" {
		t.Fatalf("unexpected database: %s", c.Database)
	} else if c.ConsistencyLevel != "all" {
		t.Fatalf("unexpected consistency-level: %s", c.ConsistencyLevel)
	} else if c.TLSEnabled != true {
		t.Fatalf("unexpected tls-enabled: %v", c.TLSEnabled)
	} else if c.Certificate != "/etc/ssl/cert.pem" {
		t.Fatalf("unexpected certificate: %s", c.Certificate)
	}
}
<|endoftext|>


<commit_before>package hcn

import (
	"fmt"
	"sync"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

var (
	// featuresOnce handles assigning the supported features and printing the supported info to stdout only once to avoid unnecessary work
	// multiple times.
	featuresOnce      sync.Once
	versionErr        error
	supportedFeatures SupportedFeatures
)

// SupportedFeatures are the features provided by the Service.
type SupportedFeatures struct {
	Acl                      AclFeatures `json:"ACL"`
	Api                      ApiSupport  `json:"API"`
	RemoteSubnet             bool        `json:"RemoteSubnet"`
	HostRoute                bool        `json:"HostRoute"`
	DSR                      bool        `json:"DSR"`
	Slash32EndpointPrefixes  bool        `json:"Slash32EndpointPrefixes"`
	AclSupportForProtocol252 bool        `json:"AclSupportForProtocol252"`
	SessionAffinity          bool        `json:"SessionAffinity"`
	IPv6DualStack            bool        `json:"IPv6DualStack"`
	SetPolicy                bool        `json:"SetPolicy"`
	VxlanPort                bool        `json:"VxlanPort"`
	L4Proxy                  bool        `json:"L4Proxy"`    // network policy that applies VFP rules to all endpoints on the network to redirect traffic
	L4WfpProxy               bool        `json:"L4WfpProxy"` // endpoint policy that applies WFP filters to redirect traffic to/from that endpoint
	TierAcl                  bool        `json:"TierAcl"`
	NetworkACL               bool        `json:"NetworkACL"`
	NestedIpSet              bool        `json:"NestedIpSet"`
}

// AclFeatures are the supported ACL possibilities.
type AclFeatures struct {
	AclAddressLists       bool `json:"AclAddressLists"`
	AclNoHostRulePriority bool `json:"AclHostRulePriority"`
	AclPortRanges         bool `json:"AclPortRanges"`
	AclRuleId             bool `json:"AclRuleId"`
}

// ApiSupport lists the supported API versions.
type ApiSupport struct {
	V1 bool `json:"V1"`
	V2 bool `json:"V2"`
}

// GetCachedSupportedFeatures returns the features supported by the Service and an error if the query failed. If this has been called
// before it will return the supported features and error received from the first call. This can be used to optimize if many calls to the
// various hcn.IsXSupported methods need to be made.
func GetCachedSupportedFeatures() (SupportedFeatures, error) {
	// Only query the HCN version and features supported once, instead of everytime this is invoked. The logs are useful to
	// debug incidents where there's confusion on if a feature is supported on the host machine. The sync.Once helps to avoid redundant
	// spam of these anytime a check needs to be made for if an HCN feature is supported. This is a common occurrence in kube-proxy
	// for example.
	featuresOnce.Do(func() {
		globals, err := GetGlobals()
		if err != nil {
			// It's expected if this fails once, it should always fail. It should fail on pre 1803 builds for example.
			versionErr = errors.Wrap(err, "failed to query HCN version number: this is expected on pre 1803 builds.")
		} else {
			supportedFeatures.Acl = AclFeatures{
				AclAddressLists:       isFeatureSupported(globals.Version, HNSVersion1803),
				AclNoHostRulePriority: isFeatureSupported(globals.Version, HNSVersion1803),
				AclPortRanges:         isFeatureSupported(globals.Version, HNSVersion1803),
				AclRuleId:             isFeatureSupported(globals.Version, HNSVersion1803),
			}

			supportedFeatures.Api = ApiSupport{
				V2: isFeatureSupported(globals.Version, V2ApiSupport),
				V1: true, // HNSCall is still available.
			}

			supportedFeatures.RemoteSubnet = isFeatureSupported(globals.Version, RemoteSubnetVersion)
			supportedFeatures.HostRoute = isFeatureSupported(globals.Version, HostRouteVersion)
			supportedFeatures.DSR = isFeatureSupported(globals.Version, DSRVersion)
			supportedFeatures.Slash32EndpointPrefixes = isFeatureSupported(globals.Version, Slash32EndpointPrefixesVersion)
			supportedFeatures.AclSupportForProtocol252 = isFeatureSupported(globals.Version, AclSupportForProtocol252Version)
			supportedFeatures.SessionAffinity = isFeatureSupported(globals.Version, SessionAffinityVersion)
			supportedFeatures.IPv6DualStack = isFeatureSupported(globals.Version, IPv6DualStackVersion)
			supportedFeatures.SetPolicy = isFeatureSupported(globals.Version, SetPolicyVersion)
			supportedFeatures.VxlanPort = isFeatureSupported(globals.Version, VxlanPortVersion)
			supportedFeatures.L4Proxy = isFeatureSupported(globals.Version, L4ProxyPolicyVersion)
			supportedFeatures.L4WfpProxy = isFeatureSupported(globals.Version, L4WfpProxyPolicyVersion)
			supportedFeatures.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion)
			supportedFeatures.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
			supportedFeatures.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)

			logrus.WithFields(logrus.Fields{
				"version":           fmt.Sprintf("%+v", globals.Version),
				"supportedFeatures": fmt.Sprintf("%+v", supportedFeatures),
			}).Info("HCN feature check")
		}
	})

	return supportedFeatures, versionErr
}

// GetSupportedFeatures returns the features supported by the Service. Prefer `GetCachedSupportedFeatures` as this method will query hns and validate
// every feature is supported on every invocation.
func GetSupportedFeatures() SupportedFeatures {
	var features SupportedFeatures

	globals, err := GetGlobals()
	if err != nil {
		// Expected on pre-1803 builds, all features will be false/unsupported
		logrus.Debugf("Unable to obtain globals: %s", err)
		return features
	}

	features.Acl = AclFeatures{
		AclAddressLists:       isFeatureSupported(globals.Version, HNSVersion1803),
		AclNoHostRulePriority: isFeatureSupported(globals.Version, HNSVersion1803),
		AclPortRanges:         isFeatureSupported(globals.Version, HNSVersion1803),
		AclRuleId:             isFeatureSupported(globals.Version, HNSVersion1803),
	}

	features.Api = ApiSupport{
		V2: isFeatureSupported(globals.Version, V2ApiSupport),
		V1: true, // HNSCall is still available.
	}

	features.RemoteSubnet = isFeatureSupported(globals.Version, RemoteSubnetVersion)
	features.HostRoute = isFeatureSupported(globals.Version, HostRouteVersion)
	features.DSR = isFeatureSupported(globals.Version, DSRVersion)
	features.Slash32EndpointPrefixes = isFeatureSupported(globals.Version, Slash32EndpointPrefixesVersion)
	features.AclSupportForProtocol252 = isFeatureSupported(globals.Version, AclSupportForProtocol252Version)
	features.SessionAffinity = isFeatureSupported(globals.Version, SessionAffinityVersion)
	features.IPv6DualStack = isFeatureSupported(globals.Version, IPv6DualStackVersion)
	features.SetPolicy = isFeatureSupported(globals.Version, SetPolicyVersion)
	features.VxlanPort = isFeatureSupported(globals.Version, VxlanPortVersion)
	features.L4Proxy = isFeatureSupported(globals.Version, L4ProxyPolicyVersion)
	features.L4WfpProxy = isFeatureSupported(globals.Version, L4WfpProxyPolicyVersion)
	features.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion)
	features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
	features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)

	logrus.WithFields(logrus.Fields{
		"version":           fmt.Sprintf("%+v", globals.Version),
		"supportedFeatures": fmt.Sprintf("%+v", features),
	}).Info("HCN feature check")

	return features
}

func isFeatureSupported(currentVersion Version, versionsSupported VersionRanges) bool {
	isFeatureSupported := false

	for _, versionRange := range versionsSupported {
		isFeatureSupported = isFeatureSupported || isFeatureInRange(currentVersion, versionRange)
	}

	return isFeatureSupported
}

func isFeatureInRange(currentVersion Version, versionRange VersionRange) bool {
	if currentVersion.Major < versionRange.MinVersion.Major {
		return false
	}
	if currentVersion.Major > versionRange.MaxVersion.Major {
		return false
	}
	if currentVersion.Major == versionRange.MinVersion.Major && currentVersion.Minor < versionRange.MinVersion.Minor {
		return false
	}
	if currentVersion.Major == versionRange.MaxVersion.Major && currentVersion.Minor > versionRange.MaxVersion.Minor {
		return false
	}
	return true
}
<commit_msg>PR feedback<commit_after>package hcn

import (
	"fmt"
	"sync"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

var (
	// featuresOnce handles assigning the supported features and printing the supported info to stdout only once to avoid unnecessary work
	// multiple times.
	featuresOnce      sync.Once
	featuresErr       error
	supportedFeatures SupportedFeatures
)

// SupportedFeatures are the features provided by the Service.
type SupportedFeatures struct {
	Acl                      AclFeatures `json:"ACL"`
	Api                      ApiSupport  `json:"API"`
	RemoteSubnet             bool        `json:"RemoteSubnet"`
	HostRoute                bool        `json:"HostRoute"`
	DSR                      bool        `json:"DSR"`
	Slash32EndpointPrefixes  bool        `json:"Slash32EndpointPrefixes"`
	AclSupportForProtocol252 bool        `json:"AclSupportForProtocol252"`
	SessionAffinity          bool        `json:"SessionAffinity"`
	IPv6DualStack            bool        `json:"IPv6DualStack"`
	SetPolicy                bool        `json:"SetPolicy"`
	VxlanPort                bool        `json:"VxlanPort"`
	L4Proxy                  bool        `json:"L4Proxy"`    // network policy that applies VFP rules to all endpoints on the network to redirect traffic
	L4WfpProxy               bool        `json:"L4WfpProxy"` // endpoint policy that applies WFP filters to redirect traffic to/from that endpoint
	TierAcl                  bool        `json:"TierAcl"`
	NetworkACL               bool        `json:"NetworkACL"`
	NestedIpSet              bool        `json:"NestedIpSet"`
}

// AclFeatures are the supported ACL possibilities.
type AclFeatures struct {
	AclAddressLists       bool `json:"AclAddressLists"`
	AclNoHostRulePriority bool `json:"AclHostRulePriority"`
	AclPortRanges         bool `json:"AclPortRanges"`
	AclRuleId             bool `json:"AclRuleId"`
}

// ApiSupport lists the supported API versions.
type ApiSupport struct {
	V1 bool `json:"V1"`
	V2 bool `json:"V2"`
}

// GetCachedSupportedFeatures returns the features supported by the Service and an error if the query failed. If this has been called
// before it will return the supported features and error received from the first call. This can be used to optimize if many calls to the
// various hcn.IsXSupported methods need to be made.
func GetCachedSupportedFeatures() (SupportedFeatures, error) {
	// Only query the HCN version and features supported once, instead of everytime this is invoked. The logs are useful to
	// debug incidents where there's confusion on if a feature is supported on the host machine. The sync.Once helps to avoid redundant
	// spam of these anytime a check needs to be made for if an HCN feature is supported. This is a common occurrence in kube-proxy
	// for example.
	featuresOnce.Do(func() {
		supportedFeatures, featuresErr = getSupportedFeatures()
	})

	return supportedFeatures, featuresErr
}

// Deprecated: Use GetCachedSupportedFeatures instead.
// GetSupportedFeatures returns the features supported by the Service.
func GetSupportedFeatures() SupportedFeatures {
	features, err := GetCachedSupportedFeatures()
	if err != nil {
		// Expected on pre-1803 builds, all features will be false/unsupported
		logrus.Errorf("Unable to obtain globals: %s", err)
		return features
	}
	return features
}

func getSupportedFeatures() (SupportedFeatures, error) {
	var features SupportedFeatures
	globals, err := GetGlobals()
	if err != nil {
		// It's expected if this fails once, it should always fail. It should fail on pre 1803 builds for example.
		return SupportedFeatures{}, errors.Wrap(err, "failed to query HCN version number: this is expected on pre 1803 builds.")
	}
	features.Acl = AclFeatures{
		AclAddressLists:       isFeatureSupported(globals.Version, HNSVersion1803),
		AclNoHostRulePriority: isFeatureSupported(globals.Version, HNSVersion1803),
		AclPortRanges:         isFeatureSupported(globals.Version, HNSVersion1803),
		AclRuleId:             isFeatureSupported(globals.Version, HNSVersion1803),
	}

	features.Api = ApiSupport{
		V2: isFeatureSupported(globals.Version, V2ApiSupport),
		V1: true, // HNSCall is still available.
	}

	features.RemoteSubnet = isFeatureSupported(globals.Version, RemoteSubnetVersion)
	features.HostRoute = isFeatureSupported(globals.Version, HostRouteVersion)
	features.DSR = isFeatureSupported(globals.Version, DSRVersion)
	features.Slash32EndpointPrefixes = isFeatureSupported(globals.Version, Slash32EndpointPrefixesVersion)
	features.AclSupportForProtocol252 = isFeatureSupported(globals.Version, AclSupportForProtocol252Version)
	features.SessionAffinity = isFeatureSupported(globals.Version, SessionAffinityVersion)
	features.IPv6DualStack = isFeatureSupported(globals.Version, IPv6DualStackVersion)
	features.SetPolicy = isFeatureSupported(globals.Version, SetPolicyVersion)
	features.VxlanPort = isFeatureSupported(globals.Version, VxlanPortVersion)
	features.L4Proxy = isFeatureSupported(globals.Version, L4ProxyPolicyVersion)
	features.L4WfpProxy = isFeatureSupported(globals.Version, L4WfpProxyPolicyVersion)
	features.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion)
	features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
	features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)

	logrus.WithFields(logrus.Fields{
		"version":           fmt.Sprintf("%+v", globals.Version),
		"supportedFeatures": fmt.Sprintf("%+v", features),
	}).Info("HCN feature check")

	return features, nil
}

func isFeatureSupported(currentVersion Version, versionsSupported VersionRanges) bool {
	isFeatureSupported := false

	for _, versionRange := range versionsSupported {
		isFeatureSupported = isFeatureSupported || isFeatureInRange(currentVersion, versionRange)
	}

	return isFeatureSupported
}

func isFeatureInRange(currentVersion Version, versionRange VersionRange) bool {
	if currentVersion.Major < versionRange.MinVersion.Major {
		return false
	}
	if currentVersion.Major > versionRange.MaxVersion.Major {
		return false
	}
	if currentVersion.Major == versionRange.MinVersion.Major && currentVersion.Minor < versionRange.MinVersion.Minor {
		return false
	}
	if currentVersion.Major == versionRange.MaxVersion.Major && currentVersion.Minor > versionRange.MaxVersion.Minor {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package backupandrestore_test

import (
	"fmt"
	"path/filepath"
	"testing"

	"gopkg.in/yaml.v2"

	"github.com/cf-deployment/units/helpers"
)

type manifest struct {
	InstanceGroups []struct {
		Name string
		Jobs []struct {
			Name       string
			Properties struct {
				SelectDirectoriesToBackup []string `yaml:"select_directories_to_backup"`
			}
		}
	} `yaml:"instance_groups"`
}

const testDirectory = "operations/backup-and-restore"

var backupAndRestoreTests = map[string]helpers.OpsFileTestParams{
	//internal
	"enable-backup-restore.yml": {
		Ops: []string{"enable-backup-restore.yml"},
	},
	"skip-backup-restore-droplets.yml": {
		Ops: []string{"enable-backup-restore.yml", "skip-backup-restore-droplets.yml"},
	},
	"skip-backup-restore-droplets-and-packages.yml": {
		Ops: []string{"enable-backup-restore.yml", "skip-backup-restore-droplets-and-packages.yml"},
	},

	//azure
	"enable-backup-restore-azure.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-backup-restore-azure.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml"},
	},
	"enable-backup-restore-azure.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-backup-restore-azure.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml"},
	},
	"enable-backup-restore-azure.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-backup-restore-azure.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml"},
	},

	//azure-clone
	"enable-restore-azure-clone.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-restore-azure-clone.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml", "example-vars-files/vars-enable-restore-azure-clone.yml"},
	},
	"enable-restore-azure-clone.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-restore-azure-clone.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml", "example-vars-files/vars-enable-restore-azure-clone.yml"},
	},
	"enable-restore-azure-clone.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-restore-azure-clone.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml", "example-vars-files/vars-enable-restore-azure-clone.yml"},
	},

	//gcs
	"enable-backup-restore-gcs.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-gcs-blobstore-service-account.yml", "enable-backup-restore-gcs.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-gcs-blobstore-service-account.yml", "example-vars-files/vars-enable-backup-restore-gcs.yml"},
	},
	"enable-backup-restore-gcs.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-gcs-blobstore-service-account.yml", "enable-backup-restore-gcs.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-gcs-blobstore-service-account.yml", "example-vars-files/vars-enable-backup-restore-gcs.yml"},
	},
	"enable-backup-restore-gcs.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-gcs-blobstore-service-account.yml", "enable-backup-restore-gcs.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-gcs-blobstore-service-account.yml", "example-vars-files/vars-enable-backup-restore-gcs.yml"},
	},

	//s3-unversioned
	"enable-backup-restore-s3-unversioned.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-unversioned.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml", "example-vars-files/vars-enable-backup-restore-s3-unversioned.yml"},
	},
	"enable-backup-restore-s3-unversioned.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-unversioned.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml", "example-vars-files/vars-enable-backup-restore-s3-unversioned.yml"},
	},
	"enable-backup-restore-s3-unversioned.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-unversioned.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml", "example-vars-files/vars-enable-backup-restore-s3-unversioned.yml"},
	},

	//s3-versioned
	"enable-backup-restore-s3-versioned.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-versioned.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml"},
	},
	"enable-backup-restore-s3-versioned.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-versioned.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml"},
	},
	"enable-backup-restore-s3-versioned.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-versioned.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml"},
	},

	//nfs-broker
	"enable-restore-nfs-broker.yml": {
		Ops: []string{"enable-backup-restore.yml", "../enable-nfs-volume-service.yml", "skip-backup-restore-droplets-and-packages.yml", "enable-restore-nfs-broker.yml"},
	},
	"enable-restore-smb-broker.yml": {
		Ops: []string{"enable-backup-restore.yml", "../enable-smb-volume-service.yml", "skip-backup-restore-droplets-and-packages.yml", "enable-restore-smb-broker.yml"},
	},
}

func TestBackupAndRestore(t *testing.T) {
	cfDeploymentHome, err := helpers.SetPath()
	if err != nil {
		t.Fatalf("setup: %v", err)
	}

	suite := helpers.NewSuiteTest(cfDeploymentHome, testDirectory, backupAndRestoreTests)
	suite.EnsureTestCoverage(t)
	suite.ReadmeTest(t)
	suite.InterpolateTest(t)

	operationsSubDirectory := filepath.Join(cfDeploymentHome, "operations")
	manifestPath := filepath.Join(cfDeploymentHome, "cf-deployment.yml")

	t.Run("skip droplets", func(t *testing.T) {
		manifest, err := boshInterpolateAndUnmarshal(
			operationsSubDirectory,
			manifestPath,
			"-o", "backup-and-restore/enable-backup-restore.yml", "-o", "backup-and-restore/skip-backup-restore-droplets.yml",
		)

		if err != nil {
			t.Errorf("failed to bosh interpolate: %v", err)
		}

		dirs := findDirectoriesToBackup(manifest)
		if !(len(dirs) == 2 && dirs[0] == "buildpacks" && dirs[1] == "packages") {
			t.Error("Ops file skip-backup-restore-droplets.yml is failing to remove droplets directories from select_directories_to_backup")
		}
	})

	t.Run("skip droplets and packages", func(t *testing.T) {
		manifest, err := boshInterpolateAndUnmarshal(
			operationsSubDirectory,
			manifestPath,
			"-o", "backup-and-restore/enable-backup-restore.yml", "-o", "backup-and-restore/skip-backup-restore-droplets-and-packages.yml",
		)

		if err != nil {
			t.Errorf("failed to bosh interpolate: %v", err)
		}

		dirs := findDirectoriesToBackup(manifest)
		if !(len(dirs) == 1 && dirs[0] == "buildpacks") {
			t.Error("Ops file skip-backup-restore-droplets-and-packages.yml is failing to remove droplets and packages directories from select_directories_to_backup")
		}
	})
}

func boshInterpolateAndUnmarshal(opsSubDir, manifestPath string, args ...string) (manifest, error) {
	boshInterpolateOutput, err := helpers.BoshInterpolate(opsSubDir, manifestPath, "", args...)

	if err != nil {
		return manifest{}, fmt.Errorf("bosh interpolate error: %v", err)
	}

	var m manifest
	err = yaml.Unmarshal(boshInterpolateOutput, &m)
	if err != nil {
		return manifest{}, fmt.Errorf("failed to unmarshal bosh interpolate output: %v", err)
	}

	return m, nil
}

func findDirectoriesToBackup(manifest manifest) []string {
	for _, instanceGroup := range manifest.InstanceGroups {
		if instanceGroup.Name == "singleton-blobstore" {
			for _, job := range instanceGroup.Jobs {
				if job.Name == "blobstore" {
					return job.Properties.SelectDirectoriesToBackup
				}
			}
		}
	}
	return []string{}
}
<commit_msg>Convert golang BBR interpolation tests to use PathValidator<commit_after>package backupandrestore_test

import (
	"testing"

	"github.com/cf-deployment/units/helpers"
)

const testDirectory = "operations/backup-and-restore"

var backupAndRestoreTests = map[string]helpers.OpsFileTestParams{
	//internal
	"enable-backup-restore.yml": {
		Ops: []string{"enable-backup-restore.yml"},
	},
	"skip-backup-restore-droplets.yml": {
		Ops: []string{"enable-backup-restore.yml", "skip-backup-restore-droplets.yml"},
		PathValidator: helpers.PathValidator{
			Path: "/instance_groups/name=singleton-blobstore/jobs/name=blobstore/properties/select_directories_to_backup", ExpectedValue: "- buildpacks\n- packages",
		},
	},
	"skip-backup-restore-droplets-and-packages.yml": {
		Ops: []string{"enable-backup-restore.yml", "skip-backup-restore-droplets-and-packages.yml"},
		PathValidator: helpers.PathValidator{
			Path: "/instance_groups/name=singleton-blobstore/jobs/name=blobstore/properties/select_directories_to_backup", ExpectedValue: "- buildpacks",
		},
	},

	//azure
	"enable-backup-restore-azure.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-backup-restore-azure.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml"},
	},
	"enable-backup-restore-azure.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-backup-restore-azure.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml"},
	},
	"enable-backup-restore-azure.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-backup-restore-azure.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml"},
	},

	//azure-clone
	"enable-restore-azure-clone.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-restore-azure-clone.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml", "example-vars-files/vars-enable-restore-azure-clone.yml"},
	},
	"enable-restore-azure-clone.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-restore-azure-clone.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml", "example-vars-files/vars-enable-restore-azure-clone.yml"},
	},
	"enable-restore-azure-clone.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-azure-storage-blobstore.yml", "enable-restore-azure-clone.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-azure-storage-blobstore.yml", "example-vars-files/vars-enable-restore-azure-clone.yml"},
	},

	//gcs
	"enable-backup-restore-gcs.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-gcs-blobstore-service-account.yml", "enable-backup-restore-gcs.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-gcs-blobstore-service-account.yml", "example-vars-files/vars-enable-backup-restore-gcs.yml"},
	},
	"enable-backup-restore-gcs.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-gcs-blobstore-service-account.yml", "enable-backup-restore-gcs.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-gcs-blobstore-service-account.yml", "example-vars-files/vars-enable-backup-restore-gcs.yml"},
	},
	"enable-backup-restore-gcs.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-gcs-blobstore-service-account.yml", "enable-backup-restore-gcs.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-gcs-blobstore-service-account.yml", "example-vars-files/vars-enable-backup-restore-gcs.yml"},
	},

	//s3-unversioned
	"enable-backup-restore-s3-unversioned.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-unversioned.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml", "example-vars-files/vars-enable-backup-restore-s3-unversioned.yml"},
	},
	"enable-backup-restore-s3-unversioned.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-unversioned.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml", "example-vars-files/vars-enable-backup-restore-s3-unversioned.yml"},
	},
	"enable-backup-restore-s3-unversioned.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-unversioned.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml", "example-vars-files/vars-enable-backup-restore-s3-unversioned.yml"},
	},

	//s3-versioned
	"enable-backup-restore-s3-versioned.yml": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-versioned.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml"},
	},
	"enable-backup-restore-s3-versioned.yml with skip droplets": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-versioned.yml", "skip-backup-restore-droplets.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml"},
	},
	"enable-backup-restore-s3-versioned.yml with skip droplets and packages": {
		Ops:       []string{"enable-backup-restore.yml", "../use-external-blobstore.yml", "../use-s3-blobstore.yml", "enable-backup-restore-s3-versioned.yml", "skip-backup-restore-droplets-and-packages.yml"},
		VarsFiles: []string{"../example-vars-files/vars-use-s3-blobstore.yml"},
	},

	//nfs-broker
	"enable-restore-nfs-broker.yml": {
		Ops: []string{"enable-backup-restore.yml", "../enable-nfs-volume-service.yml", "skip-backup-restore-droplets-and-packages.yml", "enable-restore-nfs-broker.yml"},
	},
	"enable-restore-smb-broker.yml": {
		Ops: []string{"enable-backup-restore.yml", "../enable-smb-volume-service.yml", "skip-backup-restore-droplets-and-packages.yml", "enable-restore-smb-broker.yml"},
	},
}

func TestBackupAndRestore(t *testing.T) {
	cfDeploymentHome, err := helpers.SetPath()
	if err != nil {
		t.Fatalf("setup: %v", err)
	}

	suite := helpers.NewSuiteTest(cfDeploymentHome, testDirectory, backupAndRestoreTests)
	suite.EnsureTestCoverage(t)
	suite.ReadmeTest(t)
	suite.InterpolateTest(t)
}
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// 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 indices

import (
	"encoding/json"
	"fmt"
	api "github.com/mattbaird/elastigo/api"
	"reflect"
	"strings"
)

type Mapping map[string]MappingOptions

type MappingOptions struct {
	Id         IdOptions              `json:"_id"`
	Timestamp  TimestampOptions       `json:"_timestamp"`
	Properties map[string]interface{} `json:"properties"`
}

type TimestampOptions struct {
	Enabled bool `json:"enabled"`
}

type IdOptions struct {
	Index string `json:"index"`
	Path  string `json:"path"`
}

func (m_ Mapping) Options() MappingOptions {
	m := map[string]MappingOptions(m_)
	for _, v := range m {
		return v
	}
	panic(fmt.Errorf("Malformed input: %v", m_))
}

func MappingForType(typeName string, opts MappingOptions) Mapping {
	return map[string]MappingOptions{typeName: opts}
}

func PutMapping(index string, typeName string, instance interface{}, opt MappingOptions) error {
	instanceType := reflect.TypeOf(instance)
	if instanceType.Kind() != reflect.Struct {
		return fmt.Errorf("instance kind was not struct")
	}

	if opt.Properties == nil {
		opt.Properties = make(map[string]interface{})
	}
	getProperties(instanceType, opt.Properties)
	body, err := json.Marshal(MappingForType(typeName, opt))
	if err != nil {
		return err
	}
	_, err = api.DoCommand("PUT", fmt.Sprintf("/%s/%s/_mapping", index, typeName), nil, string(body))
	if err != nil {
		return err
	}

	return nil
}

func getProperties(t reflect.Type, prop map[string]interface{}) {
	n := t.NumField()
	for i := 0; i < n; i++ {
		field := t.Field(i)

		name := strings.Split(field.Tag.Get("json"), ",")[0]
		if name == "-" {
			continue
		} else if name == "" {
			name = field.Name
		}

		attrMap := make(map[string]string)
		tag := field.Tag.Get("elastic")
		if tag == "" {
			if field.Anonymous && field.Type.Kind() == reflect.Struct {
				getProperties(field.Type, prop)
			}
			continue
		}
		attrs := strings.Split(tag, ",")
		for _, attr := range attrs {
			keyvalue := strings.Split(attr, ":")
			attrMap[keyvalue[0]] = keyvalue[1]
		}
		prop[name] = attrMap
	}
}
<commit_msg>make _id mapping optional<commit_after>// Copyright 2013 Matthew Baird
// 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 indices

import (
	"encoding/json"
	"fmt"
	api "github.com/mattbaird/elastigo/api"
	"reflect"
	"strings"
)

type Mapping map[string]MappingOptions

type MappingOptions struct {
	Id         IdOptions              `json:"_id"`
	Timestamp  TimestampOptions       `json:"_timestamp"`
	Properties map[string]interface{} `json:"properties"`
}

type TimestampOptions struct {
	Enabled bool `json:"enabled"`
}

type IdOptions struct {
	Index string `json:"index,omitempty"`
	Path  string `json:"path,omitempty"`
}

func (m_ Mapping) Options() MappingOptions {
	m := map[string]MappingOptions(m_)
	for _, v := range m {
		return v
	}
	panic(fmt.Errorf("Malformed input: %v", m_))
}

func MappingForType(typeName string, opts MappingOptions) Mapping {
	return map[string]MappingOptions{typeName: opts}
}

func PutMapping(index string, typeName string, instance interface{}, opt MappingOptions) error {
	instanceType := reflect.TypeOf(instance)
	if instanceType.Kind() != reflect.Struct {
		return fmt.Errorf("instance kind was not struct")
	}

	if opt.Properties == nil {
		opt.Properties = make(map[string]interface{})
	}
	getProperties(instanceType, opt.Properties)
	body, err := json.Marshal(MappingForType(typeName, opt))
	if err != nil {
		return err
	}
	_, err = api.DoCommand("PUT", fmt.Sprintf("/%s/%s/_mapping", index, typeName), nil, string(body))
	if err != nil {
		return err
	}

	return nil
}

func getProperties(t reflect.Type, prop map[string]interface{}) {
	n := t.NumField()
	for i := 0; i < n; i++ {
		field := t.Field(i)

		name := strings.Split(field.Tag.Get("json"), ",")[0]
		if name == "-" {
			continue
		} else if name == "" {
			name = field.Name
		}

		attrMap := make(map[string]string)
		tag := field.Tag.Get("elastic")
		if tag == "" {
			if field.Anonymous && field.Type.Kind() == reflect.Struct {
				getProperties(field.Type, prop)
			}
			continue
		}
		attrs := strings.Split(tag, ",")
		for _, attr := range attrs {
			keyvalue := strings.Split(attr, ":")
			attrMap[keyvalue[0]] = keyvalue[1]
		}
		prop[name] = attrMap
	}
}
<|endoftext|>


<commit_before>// this program creates a gif demonstrating a cycloid - the shape that
// is formed when you trace one point on a rolling circle. it uses the
// very nice gg library for all of the drawing, found at
// github.com/fogleman/gg, as well as a custom library I created for
// using image.GIFs
package main

import (
	"github.com/daviswithanS/gifutil"
	"github.com/fogleman/gg"
	"image"
	"image/color/palette"
	"log"
	"math"
)

var width, height int = 600, 400
var steps int = 32

// get the xy coordinates for a given angle according to the cycloid functions
func getCoordinates(theta float64) (x, y float64) {
	sin, cos := math.Sincos(theta)
	x = theta - sin
	y = 1 - cos
	return
}

// get the function that generates the correct image given the frame number
func getFrameGenerator() (getFrame func(int) *image.Image) {
	// getFrame() closes over the drawing context so that it remains
	// persistent through calls of getFrame()
	dc := gg.NewContext(width, height)
	dc.InvertY()
	dc.Scale(100, 100)
	dc.Translate(3, 1)

	dTheta := math.Pi / 16

	getFrame = func(step int) *image.Image {
		theta := float64(step) * dTheta

		dc.SetHexColor("FCF")
		dc.Clear()

		dc.Translate(-dTheta, 0) // keep the circle in the center

		padding := 2 * math.Pi
		// the path to the current point and the circle are redrawn every time
		// so that they can update their position
		for t := -padding; t <= theta+padding; t += dTheta {
			x, y := getCoordinates(t)
			dc.LineTo(x, y)
		}
		dc.SetHexColor("000")
		dc.SetLineWidth(4)
		dc.Stroke()

		dc.DrawCircle(theta, 1, 1)
		dc.SetLineWidth(2)
		dc.Stroke()

		x, y := getCoordinates(theta)
		dc.DrawPoint(x, y, 6)
		dc.SetHexColor("66C")
		dc.Fill()

		frame := dc.Image()
		return &frame
	}
	return
}

func main() {
	// create output gif
	out := gifutil.NewGIF(palette.WebSafe, width, height)

	getFrame := getFrameGenerator()
	gifutil.Populate(out, steps, getFrame)

	writeErr := gifutil.WriteToFile(out, "cycloid.gif")
	if writeErr != nil {
		log.Fatal(writeErr)
	}
}
<commit_msg>Minor comment changes to cycloid.go.<commit_after>// cycloid.go creates a gif demonstrating a cycloid - the shape that
// is formed when you trace one point on a rolling circle. it uses the
// gg library for all of the drawing, found at github.com/fogleman/gg.
package main

import (
	"github.com/daviswithanS/gifutil"
	"github.com/fogleman/gg"
	"image"
	"image/color/palette"
	"log"
	"math"
)

var width, height int = 600, 400
var steps int = 32

// get the xy coordinates for a given angle according to the cycloid functions
func getCoordinates(theta float64) (x, y float64) {
	sin, cos := math.Sincos(theta)
	x = theta - sin
	y = 1 - cos
	return
}

// get the function that generates the correct image given the frame number
func getFrameGenerator() (getFrame func(int) *image.Image) {
	// getFrame() closes over the drawing context so that it remains
	// persistent through calls of getFrame()
	dc := gg.NewContext(width, height)
	dc.InvertY()
	dc.Scale(100, 100)
	dc.Translate(3, 1)

	dTheta := math.Pi / 16

	getFrame = func(step int) *image.Image {
		theta := float64(step) * dTheta

		dc.SetHexColor("FCF")
		dc.Clear()

		dc.Translate(-dTheta, 0) // keep the circle in the center

		padding := 2 * math.Pi
		// the path to the current point and the circle are redrawn every time
		// so that they can update their position
		for t := -padding; t <= theta+padding; t += dTheta {
			x, y := getCoordinates(t)
			dc.LineTo(x, y)
		}
		dc.SetHexColor("000")
		dc.SetLineWidth(4)
		dc.Stroke()

		dc.DrawCircle(theta, 1, 1)
		dc.SetLineWidth(2)
		dc.Stroke()

		x, y := getCoordinates(theta)
		dc.DrawPoint(x, y, 6)
		dc.SetHexColor("66C")
		dc.Fill()

		frame := dc.Image()
		return &frame
	}
	return
}

func main() {
	// create output gif
	out := gifutil.NewGIF(palette.WebSafe, width, height)

	getFrame := getFrameGenerator()
	gifutil.Populate(out, steps, getFrame)

	writeErr := gifutil.WriteToFile(out, "cycloid.gif")
	if writeErr != nil {
		log.Fatal(writeErr)
	}
}
<|endoftext|>


<commit_before>package gotest

import (
	"time"

	"github.com/jstemmer/go-junit-report/v2/gtr"
)

// reportBuilder helps build a test Report from a collection of events.
//
// The reportBuilder keeps track of the active context whenever a test,
// benchmark or build error is created. This is necessary because the test
// parser do not contain any state themselves and simply just emit an event for
// every line that is read. By tracking the active context, any output that is
// appended to the reportBuilder gets attributed to the correct test, benchmark
// or build error.
type reportBuilder struct {
	packages    []gtr.Package
	tests       map[int]gtr.Test
	benchmarks  map[int]gtr.Benchmark
	buildErrors map[int]gtr.Error
	runErrors   map[int]gtr.Error

	// state
	nextId   int      // next free unused id
	lastId   int      // most recently created id
	output   []string // output that does not belong to any test
	coverage float64  // coverage percentage

	// default values
	PackageName   string
	TimestampFunc func() time.Time
}

// newReportBuilder creates a new reportBuilder.
func newReportBuilder() *reportBuilder {
	return &reportBuilder{
		tests:         make(map[int]gtr.Test),
		benchmarks:    make(map[int]gtr.Benchmark),
		buildErrors:   make(map[int]gtr.Error),
		runErrors:     make(map[int]gtr.Error),
		nextId:        1,
		TimestampFunc: time.Now,
	}
}

// newId returns a new unique id and sets the active context this id.
func (b *reportBuilder) newId() int {
	id := b.nextId
	b.lastId = id
	b.nextId += 1
	return id
}

// flush creates a new package in this report containing any tests or
// benchmarks we've collected so far. This is necessary when a test or
// benchmark did not end with a summary.
func (b *reportBuilder) flush() {
	if len(b.tests) > 0 || len(b.benchmarks) > 0 {
		b.CreatePackage(b.PackageName, "", 0, "")
	}
}

// Build returns the new Report containing all the tests, benchmarks and output
// created so far.
func (b *reportBuilder) Build() gtr.Report {
	b.flush()
	return gtr.Report{Packages: b.packages}
}

// CreateTest adds a test with the given name to the report, and marks it as
// active.
func (b *reportBuilder) CreateTest(name string) {
	b.tests[b.newId()] = gtr.Test{Name: name}
}

// PauseTest marks the active context as no longer active. Any results or
// output added to the report after calling PauseTest will no longer be assumed
// to belong to this test.
func (b *reportBuilder) PauseTest(name string) {
	b.lastId = 0
}

// ContinueTest finds the test with the given name and marks it as active. If
// more than one test exist with this name, the most recently created test will
// be used.
func (b *reportBuilder) ContinueTest(name string) {
	b.lastId = b.findTest(name)
}

// EndTest finds the test with the given name, sets the result, duration and
// level. If more than one test exists with this name, the most recently
// created test will be used. If no test exists with this name, a new test is
// created.
func (b *reportBuilder) EndTest(name, result string, duration time.Duration, level int) {
	b.lastId = b.findTest(name)
	if b.lastId < 0 {
		// test did not exist, create one
		// TODO: Likely reason is that the user ran go test without the -v
		// flag, should we report this somewhere?
		b.CreateTest(name)
	}

	t := b.tests[b.lastId]
	t.Result = parseResult(result)
	t.Duration = duration
	t.Level = level
	b.tests[b.lastId] = t
	b.lastId = 0
}

// End marks the active context as no longer active.
func (b *reportBuilder) End() {
	b.lastId = 0
}

// CreateBenchmark adds a benchmark with the given name to the report, and
// marks it as active. If more than one benchmark exists with this name, the
// most recently created benchmark will be updated. If no benchmark exists with
// this name, a new benchmark is created.
func (b *reportBuilder) CreateBenchmark(name string) {
	b.benchmarks[b.newId()] = gtr.Benchmark{
		Name: name,
	}
}

// BenchmarkResult updates an existing or adds a new benchmark with the given
// results and marks it as active. If an existing benchmark with this name
// exists but without result, then that one is updated. Otherwise a new one is
// added to the report.
func (b *reportBuilder) BenchmarkResult(name string, iterations int64, nsPerOp, mbPerSec float64, bytesPerOp, allocsPerOp int64) {
	b.lastId = b.findBenchmark(name)
	if b.lastId < 0 || b.benchmarks[b.lastId].Result != gtr.Unknown {
		b.CreateBenchmark(name)
	}

	b.benchmarks[b.lastId] = gtr.Benchmark{
		Name:        name,
		Result:      gtr.Pass,
		Iterations:  iterations,
		NsPerOp:     nsPerOp,
		MBPerSec:    mbPerSec,
		BytesPerOp:  bytesPerOp,
		AllocsPerOp: allocsPerOp,
	}
}

// EndBenchmark finds the benchmark with the given name and sets the result. If
// more than one benchmark exists with this name, the most recently created
// benchmark will be used. If no benchmark exists with this name, a new
// benchmark is created.
func (b *reportBuilder) EndBenchmark(name, result string) {
	b.lastId = b.findBenchmark(name)
	if b.lastId < 0 {
		b.CreateBenchmark(name)
	}

	bm := b.benchmarks[b.lastId]
	bm.Result = parseResult(result)
	b.benchmarks[b.lastId] = bm
	b.lastId = 0
}

// CreateBuildError creates a new build error and marks it as active.
func (b *reportBuilder) CreateBuildError(packageName string) {
	b.buildErrors[b.newId()] = gtr.Error{Name: packageName}
}

// CreatePackage adds a new package with the given name to the Report. This
// package contains all the build errors, output, tests and benchmarks created
// so far. Afterwards all state is reset.
func (b *reportBuilder) CreatePackage(name, result string, duration time.Duration, data string) {
	pkg := gtr.Package{
		Name:     name,
		Duration: duration,
	}

	if b.TimestampFunc != nil {
		pkg.Timestamp = b.TimestampFunc()
	}

	// Build errors are treated somewhat differently. Rather than having a
	// single package with all build errors collected so far, we only care
	// about the build errors for this particular package.
	for id, buildErr := range b.buildErrors {
		if buildErr.Name == name {
			if len(b.tests) > 0 || len(b.benchmarks) > 0 {
				panic("unexpected tests and/or benchmarks found in build error package")
			}
			buildErr.Duration = duration
			buildErr.Cause = data
			pkg.BuildError = buildErr
			b.packages = append(b.packages, pkg)

			delete(b.buildErrors, id)
			// TODO: reset state
			// TODO: buildErrors shouldn't reset/use nextId/lastId, they're more like a global cache
			return
		}
	}

	// If we've collected output, but there were no tests or benchmarks then
	// either there were no tests, or there was some other non-build error.
	if len(b.output) > 0 && len(b.tests) == 0 && len(b.benchmarks) == 0 {
		if parseResult(result) == gtr.Fail {
			pkg.RunError = gtr.Error{
				Name:   name,
				Output: b.output,
			}
		}
		b.packages = append(b.packages, pkg)

		// TODO: reset state
		b.output = nil
		return
	}

	// If the summary result says we failed, but there were no failing tests
	// then something else must have failed.
	if parseResult(result) == gtr.Fail && (len(b.tests) > 0 || len(b.benchmarks) > 0) && !b.containsFailingTest() {
		pkg.RunError = gtr.Error{
			Name:   name,
			Output: b.output,
		}
		b.output = nil
	}

	// Collect tests and benchmarks for this package, maintaining insertion order.
	var tests []gtr.Test
	var benchmarks []gtr.Benchmark
	for id := 1; id < b.nextId; id++ {
		if t, ok := b.tests[id]; ok {
			tests = append(tests, t)
		}
		if bm, ok := b.benchmarks[id]; ok {
			benchmarks = append(benchmarks, bm)
		}
	}

	pkg.Coverage = b.coverage
	pkg.Output = b.output
	pkg.Tests = tests
	pkg.Benchmarks = benchmarks
	b.packages = append(b.packages, pkg)

	// reset state
	b.nextId = 1
	b.lastId = 0
	b.output = nil
	b.coverage = 0
	b.tests = make(map[int]gtr.Test)
	b.benchmarks = make(map[int]gtr.Benchmark)
}

// Coverage sets the code coverage percentage.
func (b *reportBuilder) Coverage(pct float64, packages []string) {
	b.coverage = pct
}

// AppendOutput appends the given line to the currently active context. If no
// active context exists, the output is assumed to belong to the package.
func (b *reportBuilder) AppendOutput(line string) {
	if b.lastId <= 0 {
		b.output = append(b.output, line)
		return
	}

	if t, ok := b.tests[b.lastId]; ok {
		t.Output = append(t.Output, line)
		b.tests[b.lastId] = t
	} else if bm, ok := b.benchmarks[b.lastId]; ok {
		bm.Output = append(bm.Output, line)
		b.benchmarks[b.lastId] = bm
	} else if be, ok := b.buildErrors[b.lastId]; ok {
		be.Output = append(be.Output, line)
		b.buildErrors[b.lastId] = be
	} else {
		b.output = append(b.output, line)
	}
}

// findTest returns the id of the most recently created test with the given
// name, or -1 if no such test exists.
func (b *reportBuilder) findTest(name string) int {
	// check if this test was lastId
	if t, ok := b.tests[b.lastId]; ok && t.Name == name {
		return b.lastId
	}
	for id := len(b.tests); id >= 0; id-- {
		if b.tests[id].Name == name {
			return id
		}
	}
	return -1
}

// findBenchmark returns the id of the most recently created benchmark with the
// given name, or -1 if no such benchmark exists.
func (b *reportBuilder) findBenchmark(name string) int {
	// check if this benchmark was lastId
	if bm, ok := b.benchmarks[b.lastId]; ok && bm.Name == name {
		return b.lastId
	}
	for id := len(b.benchmarks); id >= 0; id-- {
		if b.benchmarks[id].Name == name {
			return id
		}
	}
	return -1
}

// containsFailingTest return true if the current list of tests contains at
// least one failing test or an unknown result.
func (b *reportBuilder) containsFailingTest() bool {
	for _, test := range b.tests {
		if test.Result == gtr.Fail || test.Result == gtr.Unknown {
			return true
		}
	}
	return false
}

// parseResult returns a Result for the given string r.
func parseResult(r string) gtr.Result {
	switch r {
	case "PASS":
		return gtr.Pass
	case "FAIL":
		return gtr.Fail
	case "SKIP":
		return gtr.Skip
	case "BENCH":
		return gtr.Pass
	default:
		return gtr.Unknown
	}
}
<commit_msg>parser/gotest: rename Id -> ID<commit_after>package gotest

import (
	"time"

	"github.com/jstemmer/go-junit-report/v2/gtr"
)

// reportBuilder helps build a test Report from a collection of events.
//
// The reportBuilder keeps track of the active context whenever a test,
// benchmark or build error is created. This is necessary because the test
// parser do not contain any state themselves and simply just emit an event for
// every line that is read. By tracking the active context, any output that is
// appended to the reportBuilder gets attributed to the correct test, benchmark
// or build error.
type reportBuilder struct {
	packages    []gtr.Package
	tests       map[int]gtr.Test
	benchmarks  map[int]gtr.Benchmark
	buildErrors map[int]gtr.Error
	runErrors   map[int]gtr.Error

	// state
	nextID   int      // next free unused id
	lastID   int      // most recently created id
	output   []string // output that does not belong to any test
	coverage float64  // coverage percentage

	// default values
	PackageName   string
	TimestampFunc func() time.Time
}

// newReportBuilder creates a new reportBuilder.
func newReportBuilder() *reportBuilder {
	return &reportBuilder{
		tests:         make(map[int]gtr.Test),
		benchmarks:    make(map[int]gtr.Benchmark),
		buildErrors:   make(map[int]gtr.Error),
		runErrors:     make(map[int]gtr.Error),
		nextID:        1,
		TimestampFunc: time.Now,
	}
}

// newID returns a new unique id and sets the active context this id.
func (b *reportBuilder) newID() int {
	id := b.nextID
	b.lastID = id
	b.nextID += 1
	return id
}

// flush creates a new package in this report containing any tests or
// benchmarks we've collected so far. This is necessary when a test or
// benchmark did not end with a summary.
func (b *reportBuilder) flush() {
	if len(b.tests) > 0 || len(b.benchmarks) > 0 {
		b.CreatePackage(b.PackageName, "", 0, "")
	}
}

// Build returns the new Report containing all the tests, benchmarks and output
// created so far.
func (b *reportBuilder) Build() gtr.Report {
	b.flush()
	return gtr.Report{Packages: b.packages}
}

// CreateTest adds a test with the given name to the report, and marks it as
// active.
func (b *reportBuilder) CreateTest(name string) {
	b.tests[b.newID()] = gtr.Test{Name: name}
}

// PauseTest marks the active context as no longer active. Any results or
// output added to the report after calling PauseTest will no longer be assumed
// to belong to this test.
func (b *reportBuilder) PauseTest(name string) {
	b.lastID = 0
}

// ContinueTest finds the test with the given name and marks it as active. If
// more than one test exist with this name, the most recently created test will
// be used.
func (b *reportBuilder) ContinueTest(name string) {
	b.lastID = b.findTest(name)
}

// EndTest finds the test with the given name, sets the result, duration and
// level. If more than one test exists with this name, the most recently
// created test will be used. If no test exists with this name, a new test is
// created.
func (b *reportBuilder) EndTest(name, result string, duration time.Duration, level int) {
	b.lastID = b.findTest(name)
	if b.lastID < 0 {
		// test did not exist, create one
		// TODO: Likely reason is that the user ran go test without the -v
		// flag, should we report this somewhere?
		b.CreateTest(name)
	}

	t := b.tests[b.lastID]
	t.Result = parseResult(result)
	t.Duration = duration
	t.Level = level
	b.tests[b.lastID] = t
	b.lastID = 0
}

// End marks the active context as no longer active.
func (b *reportBuilder) End() {
	b.lastID = 0
}

// CreateBenchmark adds a benchmark with the given name to the report, and
// marks it as active. If more than one benchmark exists with this name, the
// most recently created benchmark will be updated. If no benchmark exists with
// this name, a new benchmark is created.
func (b *reportBuilder) CreateBenchmark(name string) {
	b.benchmarks[b.newID()] = gtr.Benchmark{
		Name: name,
	}
}

// BenchmarkResult updates an existing or adds a new benchmark with the given
// results and marks it as active. If an existing benchmark with this name
// exists but without result, then that one is updated. Otherwise a new one is
// added to the report.
func (b *reportBuilder) BenchmarkResult(name string, iterations int64, nsPerOp, mbPerSec float64, bytesPerOp, allocsPerOp int64) {
	b.lastID = b.findBenchmark(name)
	if b.lastID < 0 || b.benchmarks[b.lastID].Result != gtr.Unknown {
		b.CreateBenchmark(name)
	}

	b.benchmarks[b.lastID] = gtr.Benchmark{
		Name:        name,
		Result:      gtr.Pass,
		Iterations:  iterations,
		NsPerOp:     nsPerOp,
		MBPerSec:    mbPerSec,
		BytesPerOp:  bytesPerOp,
		AllocsPerOp: allocsPerOp,
	}
}

// EndBenchmark finds the benchmark with the given name and sets the result. If
// more than one benchmark exists with this name, the most recently created
// benchmark will be used. If no benchmark exists with this name, a new
// benchmark is created.
func (b *reportBuilder) EndBenchmark(name, result string) {
	b.lastID = b.findBenchmark(name)
	if b.lastID < 0 {
		b.CreateBenchmark(name)
	}

	bm := b.benchmarks[b.lastID]
	bm.Result = parseResult(result)
	b.benchmarks[b.lastID] = bm
	b.lastID = 0
}

// CreateBuildError creates a new build error and marks it as active.
func (b *reportBuilder) CreateBuildError(packageName string) {
	b.buildErrors[b.newID()] = gtr.Error{Name: packageName}
}

// CreatePackage adds a new package with the given name to the Report. This
// package contains all the build errors, output, tests and benchmarks created
// so far. Afterwards all state is reset.
func (b *reportBuilder) CreatePackage(name, result string, duration time.Duration, data string) {
	pkg := gtr.Package{
		Name:     name,
		Duration: duration,
	}

	if b.TimestampFunc != nil {
		pkg.Timestamp = b.TimestampFunc()
	}

	// Build errors are treated somewhat differently. Rather than having a
	// single package with all build errors collected so far, we only care
	// about the build errors for this particular package.
	for id, buildErr := range b.buildErrors {
		if buildErr.Name == name {
			if len(b.tests) > 0 || len(b.benchmarks) > 0 {
				panic("unexpected tests and/or benchmarks found in build error package")
			}
			buildErr.Duration = duration
			buildErr.Cause = data
			pkg.BuildError = buildErr
			b.packages = append(b.packages, pkg)

			delete(b.buildErrors, id)
			// TODO: reset state
			// TODO: buildErrors shouldn't reset/use nextID/lastID, they're more like a global cache
			return
		}
	}

	// If we've collected output, but there were no tests or benchmarks then
	// either there were no tests, or there was some other non-build error.
	if len(b.output) > 0 && len(b.tests) == 0 && len(b.benchmarks) == 0 {
		if parseResult(result) == gtr.Fail {
			pkg.RunError = gtr.Error{
				Name:   name,
				Output: b.output,
			}
		}
		b.packages = append(b.packages, pkg)

		// TODO: reset state
		b.output = nil
		return
	}

	// If the summary result says we failed, but there were no failing tests
	// then something else must have failed.
	if parseResult(result) == gtr.Fail && (len(b.tests) > 0 || len(b.benchmarks) > 0) && !b.containsFailingTest() {
		pkg.RunError = gtr.Error{
			Name:   name,
			Output: b.output,
		}
		b.output = nil
	}

	// Collect tests and benchmarks for this package, maintaining insertion order.
	var tests []gtr.Test
	var benchmarks []gtr.Benchmark
	for id := 1; id < b.nextID; id++ {
		if t, ok := b.tests[id]; ok {
			tests = append(tests, t)
		}
		if bm, ok := b.benchmarks[id]; ok {
			benchmarks = append(benchmarks, bm)
		}
	}

	pkg.Coverage = b.coverage
	pkg.Output = b.output
	pkg.Tests = tests
	pkg.Benchmarks = benchmarks
	b.packages = append(b.packages, pkg)

	// reset state
	b.nextID = 1
	b.lastID = 0
	b.output = nil
	b.coverage = 0
	b.tests = make(map[int]gtr.Test)
	b.benchmarks = make(map[int]gtr.Benchmark)
}

// Coverage sets the code coverage percentage.
func (b *reportBuilder) Coverage(pct float64, packages []string) {
	b.coverage = pct
}

// AppendOutput appends the given line to the currently active context. If no
// active context exists, the output is assumed to belong to the package.
func (b *reportBuilder) AppendOutput(line string) {
	if b.lastID <= 0 {
		b.output = append(b.output, line)
		return
	}

	if t, ok := b.tests[b.lastID]; ok {
		t.Output = append(t.Output, line)
		b.tests[b.lastID] = t
	} else if bm, ok := b.benchmarks[b.lastID]; ok {
		bm.Output = append(bm.Output, line)
		b.benchmarks[b.lastID] = bm
	} else if be, ok := b.buildErrors[b.lastID]; ok {
		be.Output = append(be.Output, line)
		b.buildErrors[b.lastID] = be
	} else {
		b.output = append(b.output, line)
	}
}

// findTest returns the id of the most recently created test with the given
// name, or -1 if no such test exists.
func (b *reportBuilder) findTest(name string) int {
	// check if this test was lastID
	if t, ok := b.tests[b.lastID]; ok && t.Name == name {
		return b.lastID
	}
	for id := len(b.tests); id >= 0; id-- {
		if b.tests[id].Name == name {
			return id
		}
	}
	return -1
}

// findBenchmark returns the id of the most recently created benchmark with the
// given name, or -1 if no such benchmark exists.
func (b *reportBuilder) findBenchmark(name string) int {
	// check if this benchmark was lastID
	if bm, ok := b.benchmarks[b.lastID]; ok && bm.Name == name {
		return b.lastID
	}
	for id := len(b.benchmarks); id >= 0; id-- {
		if b.benchmarks[id].Name == name {
			return id
		}
	}
	return -1
}

// containsFailingTest return true if the current list of tests contains at
// least one failing test or an unknown result.
func (b *reportBuilder) containsFailingTest() bool {
	for _, test := range b.tests {
		if test.Result == gtr.Fail || test.Result == gtr.Unknown {
			return true
		}
	}
	return false
}

// parseResult returns a Result for the given string r.
func parseResult(r string) gtr.Result {
	switch r {
	case "PASS":
		return gtr.Pass
	case "FAIL":
		return gtr.Fail
	case "SKIP":
		return gtr.Skip
	case "BENCH":
		return gtr.Pass
	default:
		return gtr.Unknown
	}
}
<|endoftext|>


<commit_before>/*
   Copyright 2015 Comcast Cable Communications Management, LLC

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

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

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

package client

// GetDeliveryServiceResponse ...
type GetDeliveryServiceResponse struct {
	Response []DeliveryService `json:"response"`
}

// CreateDeliveryServiceResponse ...
type CreateDeliveryServiceResponse struct {
	Response []DeliveryService      `json:"response"`
	Alerts   []DeliveryServiceAlert `json:"alerts"`
}

// UpdateDeliveryServiceResponse ...
type UpdateDeliveryServiceResponse struct {
	Response []DeliveryService      `json:"response"`
	Alerts   []DeliveryServiceAlert `json:"alerts"`
}

// DeliveryServiceResponse ...
type DeliveryServiceResponse struct {
	Response DeliveryService        `json:"response"`
	Alerts   []DeliveryServiceAlert `json:"alerts"`
}

// DeleteDeliveryServiceResponse ...
type DeleteDeliveryServiceResponse struct {
	Alerts []DeliveryServiceAlert `json:"alerts"`
}

// DeliveryService ...
type DeliveryService struct {
	ID                   int                    `json:"id"`
	XMLID                string                 `json:"xmlId"`
	Active               bool                   `json:"active"`
	DSCP                 int                    `json:"dscp"`
	Signed               bool                   `json:"signed"`
	QStringIgnore        int                    `json:"qstringIgnore"`
	GeoLimit             int                    `json:"geoLimit"`
	GeoProvider          int                    `json:"geoProvider"`
	HTTPBypassFQDN       string                 `json:"httpBypassFqdn"`
	DNSBypassIP          string                 `json:"dnsBypassIp"`
	DNSBypassIP6         string                 `json:"dnsBypassIp6"`
	DNSBypassCname       string                 `json:"dnsBypassCname"`
	DNSBypassTTL         int                    `json:"dnsBypassTtl"`
	OrgServerFQDN        string                 `json:"orgServerFqdn"`
	TypeID               int                    `json:"typeId"`
	Type                 string                 `json:"type"`
	ProfileID            int                    `json:"profileId"`
	ProfileName          string                 `json:"profileName"`
	ProfileDesc          string                 `json:"profileDescription"`
	CDNName              string                 `json:"cdnName"`
	CDNID                int                    `json:"cdnId"`
	CCRDNSTTL            int                    `json:"ccrDnsTtl"`
	GlobalMaxMBPS        int                    `json:"globalMaxMbps"`
	GlobalMaxTPS         int                    `json:"globalMaxTps"`
	LongDesc             string                 `json:"longDesc"`
	LongDesc1            string                 `json:"longDesc1"`
	LongDesc2            string                 `json:"longDesc2"`
	MaxDNSAnswers        int                    `json:"maxDnsAnswers"`
	InfoURL              string                 `json:"infoUrl"`
	MissLat              float64                `json:"missLat"`
	MissLong             float64                `json:"missLong"`
	CheckPath            string                 `json:"checkPath"`
	LastUpdated          string                 `json:"lastUpdated"`
	Protocol             int                    `json:"protocol"`
	IPV6RoutingEnabled   bool                   `json:"ipv6RoutingEnabled"`
	RangeRequestHandling int                    `json:"rangeRequestHandling"`
	EdgeHeaderRewrite    string                 `json:"edgeHeaderRewrite"`
	MidHeaderRewrite     string                 `json:"midHeaderRewrite"`
	TRResponseHeaders    string                 `json:"trResponseHeaders"`
	RegexRemap           string                 `json:"regexRemap"`
	CacheURL             string                 `json:"cacheurl"`
	RemapText            string                 `json:"remapText"`
	MultiSiteOrigin      bool                   `json:"multiSiteOrigin"`
	DisplayName          string                 `json:"displayName"`
	InitialDispersion    int                    `json:"initialDispersion"`
	MatchList            []DeliveryServiceMatch `json:"matchList,omitempty"`
	RegionalGeoBlocking  bool                   `json:"regionalGeoBlocking"`
	LogsEnabled          bool                   `json:"logsEnabled"`
}

// DeliveryServiceMatch ...
type DeliveryServiceMatch struct {
	Type      string `json:"type"`
	SetNumber string `json:"setNumber"`
	Pattern   string `json:"pattern"`
}

// DeliveryServiceAlert ...
type DeliveryServiceAlert struct {
	Level string `json:"level"`
	Text  string `json:"text"`
}

// DeliveryServiceStateResponse ...
type DeliveryServiceStateResponse struct {
	Response DeliveryServiceState `json:"response"`
}

// DeliveryServiceState ...
type DeliveryServiceState struct {
	Enabled  bool                    `json:"enabled"`
	Failover DeliveryServiceFailover `json:"failover"`
}

// DeliveryServiceFailover ...
type DeliveryServiceFailover struct {
	Locations   []string                   `json:"locations"`
	Destination DeliveryServiceDestination `json:"destination"`
	Configured  bool                       `json:"configured"`
	Enabled     bool                       `json:"enabled"`
}

// DeliveryServiceDestination ...
type DeliveryServiceDestination struct {
	Location string `json:"location"`
	Type     string `json:"type"`
}

// DeliveryServiceHealthResponse ...
type DeliveryServiceHealthResponse struct {
	Response DeliveryServiceHealth `json:"response"`
}

// DeliveryServiceHealth ...
type DeliveryServiceHealth struct {
	TotalOnline  int                         `json:"totalOnline"`
	TotalOffline int                         `json:"totalOffline"`
	CacheGroups  []DeliveryServiceCacheGroup `json:"cacheGroups"`
}

// DeliveryServiceCacheGroup ...
type DeliveryServiceCacheGroup struct {
	Online  int    `json:"online"`
	Offline int    `json:"offline"`
	Name    string `json:"name"`
}

// DeliveryServiceCapacityResponse ...
type DeliveryServiceCapacityResponse struct {
	Response DeliveryServiceCapacity `json:"response"`
}

// DeliveryServiceCapacity ...
type DeliveryServiceCapacity struct {
	AvailablePercent   float64 `json:"availablePercent"`
	UnavailablePercent float64 `json:"unavailablePercent"`
	UtilizedPercent    float64 `json:"utilizedPercent"`
	MaintenancePercent float64 `json:"maintenancePercent"`
}

// DeliveryServiceRoutingResponse ...
type DeliveryServiceRoutingResponse struct {
	Response DeliveryServiceRouting `json:"response"`
}

// DeliveryServiceRouting ...
type DeliveryServiceRouting struct {
	StaticRoute       int     `json:"staticRoute"`
	Miss              int     `json:"miss"`
	Geo               float64 `json:"geo"`
	Err               int     `json:"err"`
	CZ                float64 `json:"cz"`
	DSR               float64 `json:"dsr"`
	Fed               int     `json:"fed"`
	RegionalAlternate int     `json:"regionalAlternate"`
	RegionalDenied    int     `json:"regionalDenied"`
}

// DeliveryServiceServerResponse ...
type DeliveryServiceServerResponse struct {
	Response []DeliveryServiceServer `json:"response"`
	Page     int                     `json:"page"`
	OrderBy  string                  `json:"orderby"`
	Limit    int                     `json:"limit"`
}

// DeliveryServiceServer ...
type DeliveryServiceServer struct {
	LastUpdated     string `json:"lastUpdated"`
	Server          int    `json:"server"`
	DeliveryService int    `json:"deliveryService"`
}

// DeliveryServiceSSLKeysResponse ...
type DeliveryServiceSSLKeysResponse struct {
	Response DeliveryServiceSSLKeys `json:"response"`
}

// DeliveryServiceSSLKeys ...
type DeliveryServiceSSLKeys struct {
	CDN             string                            `json:"cdn"`
	DeliveryService string                            `json:"DeliveryService"`
	BusinessUnit    string                            `json:"businessUnit"`
	City            string                            `json:"city"`
	Organization    string                            `json:"organization"`
	Hostname        string                            `json:"hostname"`
	Country         string                            `json:"country"`
	State           string                            `json:"state"`
	Version         string                            `json:"version"`
	Certificate     DeliveryServiceSSLKeysCertificate `json:"certificate"`
}

// DeliveryServiceSSLKeysCertificate ...
type DeliveryServiceSSLKeysCertificate struct {
	Crt string `json:"crt"`
	Key string `json:"key"`
	CSR string `json:"csr"`
}
<commit_msg>update DeliveryserviceServer struct to match output from TO<commit_after>/*
   Copyright 2015 Comcast Cable Communications Management, LLC

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

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

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

package client

// GetDeliveryServiceResponse ...
type GetDeliveryServiceResponse struct {
	Response []DeliveryService `json:"response"`
}

// CreateDeliveryServiceResponse ...
type CreateDeliveryServiceResponse struct {
	Response []DeliveryService      `json:"response"`
	Alerts   []DeliveryServiceAlert `json:"alerts"`
}

// UpdateDeliveryServiceResponse ...
type UpdateDeliveryServiceResponse struct {
	Response []DeliveryService      `json:"response"`
	Alerts   []DeliveryServiceAlert `json:"alerts"`
}

// DeliveryServiceResponse ...
type DeliveryServiceResponse struct {
	Response DeliveryService        `json:"response"`
	Alerts   []DeliveryServiceAlert `json:"alerts"`
}

// DeleteDeliveryServiceResponse ...
type DeleteDeliveryServiceResponse struct {
	Alerts []DeliveryServiceAlert `json:"alerts"`
}

// DeliveryService ...
type DeliveryService struct {
	ID                   int                    `json:"id"`
	XMLID                string                 `json:"xmlId"`
	Active               bool                   `json:"active"`
	DSCP                 int                    `json:"dscp"`
	Signed               bool                   `json:"signed"`
	QStringIgnore        int                    `json:"qstringIgnore"`
	GeoLimit             int                    `json:"geoLimit"`
	GeoProvider          int                    `json:"geoProvider"`
	HTTPBypassFQDN       string                 `json:"httpBypassFqdn"`
	DNSBypassIP          string                 `json:"dnsBypassIp"`
	DNSBypassIP6         string                 `json:"dnsBypassIp6"`
	DNSBypassCname       string                 `json:"dnsBypassCname"`
	DNSBypassTTL         int                    `json:"dnsBypassTtl"`
	OrgServerFQDN        string                 `json:"orgServerFqdn"`
	TypeID               int                    `json:"typeId"`
	Type                 string                 `json:"type"`
	ProfileID            int                    `json:"profileId"`
	ProfileName          string                 `json:"profileName"`
	ProfileDesc          string                 `json:"profileDescription"`
	CDNName              string                 `json:"cdnName"`
	CDNID                int                    `json:"cdnId"`
	CCRDNSTTL            int                    `json:"ccrDnsTtl"`
	GlobalMaxMBPS        int                    `json:"globalMaxMbps"`
	GlobalMaxTPS         int                    `json:"globalMaxTps"`
	LongDesc             string                 `json:"longDesc"`
	LongDesc1            string                 `json:"longDesc1"`
	LongDesc2            string                 `json:"longDesc2"`
	MaxDNSAnswers        int                    `json:"maxDnsAnswers"`
	InfoURL              string                 `json:"infoUrl"`
	MissLat              float64                `json:"missLat"`
	MissLong             float64                `json:"missLong"`
	CheckPath            string                 `json:"checkPath"`
	LastUpdated          string                 `json:"lastUpdated"`
	Protocol             int                    `json:"protocol"`
	IPV6RoutingEnabled   bool                   `json:"ipv6RoutingEnabled"`
	RangeRequestHandling int                    `json:"rangeRequestHandling"`
	EdgeHeaderRewrite    string                 `json:"edgeHeaderRewrite"`
	MidHeaderRewrite     string                 `json:"midHeaderRewrite"`
	TRResponseHeaders    string                 `json:"trResponseHeaders"`
	RegexRemap           string                 `json:"regexRemap"`
	CacheURL             string                 `json:"cacheurl"`
	RemapText            string                 `json:"remapText"`
	MultiSiteOrigin      bool                   `json:"multiSiteOrigin"`
	DisplayName          string                 `json:"displayName"`
	InitialDispersion    int                    `json:"initialDispersion"`
	MatchList            []DeliveryServiceMatch `json:"matchList,omitempty"`
	RegionalGeoBlocking  bool                   `json:"regionalGeoBlocking"`
	LogsEnabled          bool                   `json:"logsEnabled"`
}

// DeliveryServiceMatch ...
type DeliveryServiceMatch struct {
	Type      string `json:"type"`
	SetNumber string `json:"setNumber"`
	Pattern   string `json:"pattern"`
}

// DeliveryServiceAlert ...
type DeliveryServiceAlert struct {
	Level string `json:"level"`
	Text  string `json:"text"`
}

// DeliveryServiceStateResponse ...
type DeliveryServiceStateResponse struct {
	Response DeliveryServiceState `json:"response"`
}

// DeliveryServiceState ...
type DeliveryServiceState struct {
	Enabled  bool                    `json:"enabled"`
	Failover DeliveryServiceFailover `json:"failover"`
}

// DeliveryServiceFailover ...
type DeliveryServiceFailover struct {
	Locations   []string                   `json:"locations"`
	Destination DeliveryServiceDestination `json:"destination"`
	Configured  bool                       `json:"configured"`
	Enabled     bool                       `json:"enabled"`
}

// DeliveryServiceDestination ...
type DeliveryServiceDestination struct {
	Location string `json:"location"`
	Type     string `json:"type"`
}

// DeliveryServiceHealthResponse ...
type DeliveryServiceHealthResponse struct {
	Response DeliveryServiceHealth `json:"response"`
}

// DeliveryServiceHealth ...
type DeliveryServiceHealth struct {
	TotalOnline  int                         `json:"totalOnline"`
	TotalOffline int                         `json:"totalOffline"`
	CacheGroups  []DeliveryServiceCacheGroup `json:"cacheGroups"`
}

// DeliveryServiceCacheGroup ...
type DeliveryServiceCacheGroup struct {
	Online  int    `json:"online"`
	Offline int    `json:"offline"`
	Name    string `json:"name"`
}

// DeliveryServiceCapacityResponse ...
type DeliveryServiceCapacityResponse struct {
	Response DeliveryServiceCapacity `json:"response"`
}

// DeliveryServiceCapacity ...
type DeliveryServiceCapacity struct {
	AvailablePercent   float64 `json:"availablePercent"`
	UnavailablePercent float64 `json:"unavailablePercent"`
	UtilizedPercent    float64 `json:"utilizedPercent"`
	MaintenancePercent float64 `json:"maintenancePercent"`
}

// DeliveryServiceRoutingResponse ...
type DeliveryServiceRoutingResponse struct {
	Response DeliveryServiceRouting `json:"response"`
}

// DeliveryServiceRouting ...
type DeliveryServiceRouting struct {
	StaticRoute       int     `json:"staticRoute"`
	Miss              int     `json:"miss"`
	Geo               float64 `json:"geo"`
	Err               int     `json:"err"`
	CZ                float64 `json:"cz"`
	DSR               float64 `json:"dsr"`
	Fed               int     `json:"fed"`
	RegionalAlternate int     `json:"regionalAlternate"`
	RegionalDenied    int     `json:"regionalDenied"`
}

// DeliveryServiceServerResponse ...
type DeliveryServiceServerResponse struct {
	Response []DeliveryServiceServer `json:"response"`
	Size     string                  `json:"size"`
	OrderBy  string                  `json:"orderby"`
	Limit    string                  `json:"limit"`
}

// DeliveryServiceServer ...
type DeliveryServiceServer struct {
	LastUpdated     string `json:"lastUpdated"`
	Server          int    `json:"server"`
	DeliveryService int    `json:"deliveryService"`
}

// DeliveryServiceSSLKeysResponse ...
type DeliveryServiceSSLKeysResponse struct {
	Response DeliveryServiceSSLKeys `json:"response"`
}

// DeliveryServiceSSLKeys ...
type DeliveryServiceSSLKeys struct {
	CDN             string                            `json:"cdn"`
	DeliveryService string                            `json:"DeliveryService"`
	BusinessUnit    string                            `json:"businessUnit"`
	City            string                            `json:"city"`
	Organization    string                            `json:"organization"`
	Hostname        string                            `json:"hostname"`
	Country         string                            `json:"country"`
	State           string                            `json:"state"`
	Version         string                            `json:"version"`
	Certificate     DeliveryServiceSSLKeysCertificate `json:"certificate"`
}

// DeliveryServiceSSLKeysCertificate ...
type DeliveryServiceSSLKeysCertificate struct {
	Crt string `json:"crt"`
	Key string `json:"key"`
	CSR string `json:"csr"`
}
<|endoftext|>