<commit_before>package main

import (
	"encoding/base64"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"strconv"
	"time"

	"github.com/armon/go-metrics"
	metrics_prom "github.com/armon/go-metrics/prometheus"
	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"

	"github.com/weaveworks/common/logging"
	"github.com/weaveworks/common/network"
	"github.com/weaveworks/common/sanitize"
	"github.com/weaveworks/common/signals"
	"github.com/weaveworks/common/tracing"
	"github.com/weaveworks/go-checkpoint"
	"github.com/weaveworks/scope/common/hostname"
	"github.com/weaveworks/scope/common/weave"
	"github.com/weaveworks/scope/common/xfer"
	"github.com/weaveworks/scope/probe"
	"github.com/weaveworks/scope/probe/appclient"
	"github.com/weaveworks/scope/probe/awsecs"
	"github.com/weaveworks/scope/probe/controls"
	"github.com/weaveworks/scope/probe/cri"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/probe/overlay"
	"github.com/weaveworks/scope/probe/plugins"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/report"
)

const (
	versionCheckPeriod = 6 * time.Hour
	defaultServiceHost = "https://cloud.weave.works.:443"

	kubernetesRoleHost    = "host"
	kubernetesRoleCluster = "cluster"
)

var (
	pluginAPIVersion = "1"
)

func checkNewScopeVersion(flags probeFlags) {
	checkpointFlags := makeBaseCheckpointFlags()
	if flags.kubernetesEnabled {
		checkpointFlags["kubernetes_enabled"] = "true"
	}
	if flags.ecsEnabled {
		checkpointFlags["ecs_enabled"] = "true"
	}

	go func() {
		handleResponse := func(r *checkpoint.CheckResponse, err error) {
			if err != nil {
				log.Errorf("Error checking version: %v", err)
			} else if r.Outdated {
				log.Infof("Scope version %s is available; please update at %s",
					r.CurrentVersion, r.CurrentDownloadURL)
			}
		}

		// Start background version checking
		params := checkpoint.CheckParams{
			Product: "scope-probe",
			Version: version,
			Flags:   checkpointFlags,
		}
		resp, err := checkpoint.Check(&params)
		handleResponse(resp, err)
		checkpoint.CheckInterval(&params, versionCheckPeriod, handleResponse)
	}()
}

func maybeExportProfileData(flags probeFlags) {
	if flags.httpListen != "" {
		go func() {
			http.Handle("/metrics", prometheus.Handler())
			log.Infof("Profiling data being exported to %s", flags.httpListen)
			log.Infof("go tool pprof http://%s/debug/pprof/{profile,heap,block}", flags.httpListen)
			log.Infof("Profiling endpoint %s terminated: %v", flags.httpListen, http.ListenAndServe(flags.httpListen, nil))
		}()
	}
}

// Main runs the probe
func probeMain(flags probeFlags, targets []appclient.Target) {
	setLogLevel(flags.logLevel)
	setLogFormatter(flags.logPrefix)

	if flags.basicAuth {
		log.Infof("Basic authentication enabled")
	} else {
		log.Infof("Basic authentication disabled")
	}

	traceCloser := tracing.NewFromEnv("scope-probe")
	defer traceCloser.Close()

	cfg := &metrics.Config{
		ServiceName:      "scope-probe",
		TimerGranularity: time.Second,
		FilterDefault:    true, // Don't filter metrics by default
	}
	if flags.httpListen == "" {
		// Setup in memory metrics sink
		inm := metrics.NewInmemSink(time.Minute, 2*time.Minute)
		sig := metrics.DefaultInmemSignal(inm)
		defer sig.Stop()
		metrics.NewGlobal(cfg, inm)
	} else {
		sink, err := metrics_prom.NewPrometheusSink()
		if err != nil {
			log.Fatalf("Failed to create Prometheus metrics sink: %v", err)
		}
		metrics.NewGlobal(cfg, sink)
	}
	logCensoredArgs()
	defer log.Info("probe exiting")

	switch flags.kubernetesRole {
	case "": // nothing special
	case kubernetesRoleHost:
		flags.kubernetesEnabled = true
	case kubernetesRoleCluster:
		flags.kubernetesEnabled = true
		flags.spyProcs = false
		flags.procEnabled = false
		flags.useConntrack = false
		flags.useEbpfConn = false
	default:
		log.Warnf("unrecognized --probe.kubernetes.role: %s", flags.kubernetesRole)
	}

	if flags.spyProcs && os.Getegid() != 0 {
		log.Warn("--probe.proc.spy=true, but that requires root to find everything")
	}

	rand.Seed(time.Now().UnixNano())
	var (
		probeID  = strconv.FormatInt(rand.Int63(), 16)
		hostName = hostname.Get()
		hostID   = hostName // TODO(pb): we should sanitize the hostname
	)
	log.Infof("probe starting, version %s, ID %s", version, probeID)
	checkNewScopeVersion(flags)

	handlerRegistry := controls.NewDefaultHandlerRegistry()
	clientFactory := func(hostname string, url url.URL) (appclient.AppClient, error) {
		token := flags.token
		if url.User != nil {
			token = url.User.Username()
			url.User = nil // erase credentials, as we use a special header
		}

		if flags.basicAuth {
			token = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", flags.username, flags.password)))
		}

		probeConfig := appclient.ProbeConfig{
			BasicAuth:    flags.basicAuth,
			Token:        token,
			ProbeVersion: version,
			ProbeID:      probeID,
			Insecure:     flags.insecure,
		}
		return appclient.NewAppClient(
			probeConfig, hostname, url,
			xfer.ControlHandlerFunc(handlerRegistry.HandleControlRequest),
		)
	}

	var clients interface {
		probe.ReportPublisher
		controls.PipeClient
	}
	if flags.printOnStdout {
		if len(targets) > 0 {
			log.Warnf("Dumping to stdout only: targets %v will be ignored", targets)
		}
		clients = new(struct {
			report.StdoutPublisher
			controls.DummyPipeClient
		})
	} else {
		multiClients := appclient.NewMultiAppClient(clientFactory, flags.noControls)
		defer multiClients.Stop()

		dnsLookupFn := net.LookupIP
		if flags.resolver != "" {
			dnsLookupFn = appclient.LookupUsing(flags.resolver)
		}
		resolver, err := appclient.NewResolver(appclient.ResolverConfig{
			Targets: targets,
			Lookup:  dnsLookupFn,
			Set:     multiClients.Set,
		})
		if err != nil {
			log.Fatalf("Failed to create resolver: %v", err)
			return
		}
		defer resolver.Stop()

		if flags.weaveEnabled && flags.weaveHostname != "" {
			dockerBridgeIP, err := network.GetFirstAddressOf(flags.dockerBridge)
			if err != nil {
				log.Errorf("Error getting docker bridge ip: %v", err)
			} else {
				weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53")
				weaveTargets, err := appclient.ParseTargets([]string{flags.weaveHostname})
				if err != nil {
					log.Errorf("Failed to parse weave targets: %v", err)
				} else {
					weaveResolver, err := appclient.NewResolver(appclient.ResolverConfig{
						Targets: weaveTargets,
						Lookup:  weaveDNSLookup,
						Set:     multiClients.Set,
					})
					if err != nil {
						log.Errorf("Failed to create weave resolver: %v", err)
					} else {
						defer weaveResolver.Stop()
					}
				}
			}
		}
		clients = multiClients
	}

	p := probe.New(flags.spyInterval, flags.publishInterval, clients, flags.ticksPerFullReport, flags.noControls)
	p.AddTagger(probe.NewTopologyTagger())
	var processCache *process.CachingWalker

	if flags.kubernetesRole != kubernetesRoleCluster {
		hostReporter := host.NewReporter(hostID, hostName, probeID, version, clients, handlerRegistry)
		defer hostReporter.Stop()
		p.AddReporter(hostReporter)
		p.AddTagger(host.NewTagger(hostID))

		if flags.procEnabled {
			processCache = process.NewCachingWalker(process.NewWalker(flags.procRoot, false))
			p.AddTicker(processCache)
			p.AddReporter(process.NewReporter(processCache, hostID, process.GetDeltaTotalJiffies, flags.noCommandLineArguments))
		}

		dnsSnooper, err := endpoint.NewDNSSnooper()
		if err != nil {
			log.Errorf("Failed to start DNS snooper: nodes for external services will be less accurate: %s", err)
		} else {
			defer dnsSnooper.Stop()
		}

		endpointReporter := endpoint.NewReporter(endpoint.ReporterConfig{
			HostID:       hostID,
			HostName:     hostName,
			SpyProcs:     flags.spyProcs,
			UseConntrack: flags.useConntrack,
			WalkProc:     flags.procEnabled,
			UseEbpfConn:  flags.useEbpfConn,
			ProcRoot:     flags.procRoot,
			BufferSize:   flags.conntrackBufferSize,
			ProcessCache: processCache,
			DNSSnooper:   dnsSnooper,
		})
		defer endpointReporter.Stop()
		p.AddReporter(endpointReporter)
	}

	if flags.dockerEnabled {
		// Don't add the bridge in Kubernetes since container IPs are global and
		// shouldn't be scoped
		if flags.dockerBridge != "" && !flags.kubernetesEnabled {
			if err := report.AddLocalBridge(flags.dockerBridge); err != nil {
				log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err)
			}
		}
		options := docker.RegistryOptions{
			Interval:               flags.dockerInterval,
			Pipes:                  clients,
			CollectStats:           true,
			HostID:                 hostID,
			HandlerRegistry:        handlerRegistry,
			NoCommandLineArguments: flags.noCommandLineArguments,
			NoEnvironmentVariables: flags.noEnvironmentVariables,
		}
		if registry, err := docker.NewRegistry(options); err == nil {
			defer registry.Stop()
			if flags.procEnabled {
				p.AddTagger(docker.NewTagger(registry, processCache))
			}
			p.AddReporter(docker.NewReporter(registry, hostID, probeID, p))
		} else {
			log.Errorf("Docker: failed to start registry: %v", err)
		}
	}

	if flags.criEnabled {
		client, err := cri.NewCRIClient(flags.criEndpoint)
		if err != nil {
			log.Errorf("CRI: failed to start registry: %v", err)
		} else {
			p.AddReporter(cri.NewReporter(client))
		}
	}

	if flags.kubernetesEnabled && flags.kubernetesRole != kubernetesRoleHost {
		if client, err := kubernetes.NewClient(flags.kubernetesClientConfig); err == nil {
			defer client.Stop()
			reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p, handlerRegistry, flags.kubernetesNodeName)
			defer reporter.Stop()
			p.AddReporter(reporter)
		} else {
			log.Errorf("Kubernetes: failed to start client: %v", err)
			log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide valid probe.kubernetes.* flags")
		}
	}

	if flags.kubernetesEnabled {
		p.AddTagger(&kubernetes.Tagger{})
	}

	if flags.ecsEnabled {
		reporter := awsecs.Make(flags.ecsCacheSize, flags.ecsCacheExpiry, flags.ecsClusterRegion, handlerRegistry, probeID)
		defer reporter.Stop()
		p.AddReporter(reporter)
		p.AddTagger(reporter)
	}

	if flags.weaveEnabled {
		client := weave.NewClient(sanitize.URL("http://", 6784, "")(flags.weaveAddr))
		weave, err := overlay.NewWeave(hostID, client)
		if err != nil {
			log.Errorf("Weave: failed to start client: %v", err)
		} else {
			defer weave.Stop()
			p.AddTagger(weave)
			p.AddReporter(weave)
		}
	}

	if flags.pluginsRoot != "" {
		pluginRegistry, err := plugins.NewRegistry(
			flags.pluginsRoot,
			pluginAPIVersion,
			map[string]string{
				"probe_id":    probeID,
				"api_version": pluginAPIVersion,
			},
			handlerRegistry,
			p,
		)
		if err != nil {
			log.Errorf("plugins: problem loading: %v", err)
		} else {
			defer pluginRegistry.Close()
			p.AddReporter(pluginRegistry)
		}
	}

	maybeExportProfileData(flags)

	p.Start()
	signals.SignalHandlerLoop(
		logging.Logrus(log.StandardLogger()),
		p,
	)
}
<commit_msg>Warn user if probe is now reporting pods from every node.<commit_after>package main

import (
	"encoding/base64"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"strconv"
	"time"

	"github.com/armon/go-metrics"
	metrics_prom "github.com/armon/go-metrics/prometheus"
	"github.com/prometheus/client_golang/prometheus"
	log "github.com/sirupsen/logrus"

	"github.com/weaveworks/common/logging"
	"github.com/weaveworks/common/network"
	"github.com/weaveworks/common/sanitize"
	"github.com/weaveworks/common/signals"
	"github.com/weaveworks/common/tracing"
	"github.com/weaveworks/go-checkpoint"
	"github.com/weaveworks/scope/common/hostname"
	"github.com/weaveworks/scope/common/weave"
	"github.com/weaveworks/scope/common/xfer"
	"github.com/weaveworks/scope/probe"
	"github.com/weaveworks/scope/probe/appclient"
	"github.com/weaveworks/scope/probe/awsecs"
	"github.com/weaveworks/scope/probe/controls"
	"github.com/weaveworks/scope/probe/cri"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/probe/overlay"
	"github.com/weaveworks/scope/probe/plugins"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/report"
)

const (
	versionCheckPeriod = 6 * time.Hour
	defaultServiceHost = "https://cloud.weave.works.:443"

	kubernetesRoleHost    = "host"
	kubernetesRoleCluster = "cluster"
)

var (
	pluginAPIVersion = "1"
)

func checkNewScopeVersion(flags probeFlags) {
	checkpointFlags := makeBaseCheckpointFlags()
	if flags.kubernetesEnabled {
		checkpointFlags["kubernetes_enabled"] = "true"
	}
	if flags.ecsEnabled {
		checkpointFlags["ecs_enabled"] = "true"
	}

	go func() {
		handleResponse := func(r *checkpoint.CheckResponse, err error) {
			if err != nil {
				log.Errorf("Error checking version: %v", err)
			} else if r.Outdated {
				log.Infof("Scope version %s is available; please update at %s",
					r.CurrentVersion, r.CurrentDownloadURL)
			}
		}

		// Start background version checking
		params := checkpoint.CheckParams{
			Product: "scope-probe",
			Version: version,
			Flags:   checkpointFlags,
		}
		resp, err := checkpoint.Check(&params)
		handleResponse(resp, err)
		checkpoint.CheckInterval(&params, versionCheckPeriod, handleResponse)
	}()
}

func maybeExportProfileData(flags probeFlags) {
	if flags.httpListen != "" {
		go func() {
			http.Handle("/metrics", prometheus.Handler())
			log.Infof("Profiling data being exported to %s", flags.httpListen)
			log.Infof("go tool pprof http://%s/debug/pprof/{profile,heap,block}", flags.httpListen)
			log.Infof("Profiling endpoint %s terminated: %v", flags.httpListen, http.ListenAndServe(flags.httpListen, nil))
		}()
	}
}

// Main runs the probe
func probeMain(flags probeFlags, targets []appclient.Target) {
	setLogLevel(flags.logLevel)
	setLogFormatter(flags.logPrefix)

	if flags.basicAuth {
		log.Infof("Basic authentication enabled")
	} else {
		log.Infof("Basic authentication disabled")
	}

	traceCloser := tracing.NewFromEnv("scope-probe")
	defer traceCloser.Close()

	cfg := &metrics.Config{
		ServiceName:      "scope-probe",
		TimerGranularity: time.Second,
		FilterDefault:    true, // Don't filter metrics by default
	}
	if flags.httpListen == "" {
		// Setup in memory metrics sink
		inm := metrics.NewInmemSink(time.Minute, 2*time.Minute)
		sig := metrics.DefaultInmemSignal(inm)
		defer sig.Stop()
		metrics.NewGlobal(cfg, inm)
	} else {
		sink, err := metrics_prom.NewPrometheusSink()
		if err != nil {
			log.Fatalf("Failed to create Prometheus metrics sink: %v", err)
		}
		metrics.NewGlobal(cfg, sink)
	}
	logCensoredArgs()
	defer log.Info("probe exiting")

	switch flags.kubernetesRole {
	case "": // nothing special
	case kubernetesRoleHost:
		flags.kubernetesEnabled = true
	case kubernetesRoleCluster:
		flags.kubernetesEnabled = true
		flags.spyProcs = false
		flags.procEnabled = false
		flags.useConntrack = false
		flags.useEbpfConn = false
	default:
		log.Warnf("unrecognized --probe.kubernetes.role: %s", flags.kubernetesRole)
	}

	if flags.spyProcs && os.Getegid() != 0 {
		log.Warn("--probe.proc.spy=true, but that requires root to find everything")
	}

	rand.Seed(time.Now().UnixNano())
	var (
		probeID  = strconv.FormatInt(rand.Int63(), 16)
		hostName = hostname.Get()
		hostID   = hostName // TODO(pb): we should sanitize the hostname
	)
	log.Infof("probe starting, version %s, ID %s", version, probeID)
	checkNewScopeVersion(flags)

	handlerRegistry := controls.NewDefaultHandlerRegistry()
	clientFactory := func(hostname string, url url.URL) (appclient.AppClient, error) {
		token := flags.token
		if url.User != nil {
			token = url.User.Username()
			url.User = nil // erase credentials, as we use a special header
		}

		if flags.basicAuth {
			token = base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", flags.username, flags.password)))
		}

		probeConfig := appclient.ProbeConfig{
			BasicAuth:    flags.basicAuth,
			Token:        token,
			ProbeVersion: version,
			ProbeID:      probeID,
			Insecure:     flags.insecure,
		}
		return appclient.NewAppClient(
			probeConfig, hostname, url,
			xfer.ControlHandlerFunc(handlerRegistry.HandleControlRequest),
		)
	}

	var clients interface {
		probe.ReportPublisher
		controls.PipeClient
	}
	if flags.printOnStdout {
		if len(targets) > 0 {
			log.Warnf("Dumping to stdout only: targets %v will be ignored", targets)
		}
		clients = new(struct {
			report.StdoutPublisher
			controls.DummyPipeClient
		})
	} else {
		multiClients := appclient.NewMultiAppClient(clientFactory, flags.noControls)
		defer multiClients.Stop()

		dnsLookupFn := net.LookupIP
		if flags.resolver != "" {
			dnsLookupFn = appclient.LookupUsing(flags.resolver)
		}
		resolver, err := appclient.NewResolver(appclient.ResolverConfig{
			Targets: targets,
			Lookup:  dnsLookupFn,
			Set:     multiClients.Set,
		})
		if err != nil {
			log.Fatalf("Failed to create resolver: %v", err)
			return
		}
		defer resolver.Stop()

		if flags.weaveEnabled && flags.weaveHostname != "" {
			dockerBridgeIP, err := network.GetFirstAddressOf(flags.dockerBridge)
			if err != nil {
				log.Errorf("Error getting docker bridge ip: %v", err)
			} else {
				weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53")
				weaveTargets, err := appclient.ParseTargets([]string{flags.weaveHostname})
				if err != nil {
					log.Errorf("Failed to parse weave targets: %v", err)
				} else {
					weaveResolver, err := appclient.NewResolver(appclient.ResolverConfig{
						Targets: weaveTargets,
						Lookup:  weaveDNSLookup,
						Set:     multiClients.Set,
					})
					if err != nil {
						log.Errorf("Failed to create weave resolver: %v", err)
					} else {
						defer weaveResolver.Stop()
					}
				}
			}
		}
		clients = multiClients
	}

	p := probe.New(flags.spyInterval, flags.publishInterval, clients, flags.ticksPerFullReport, flags.noControls)
	p.AddTagger(probe.NewTopologyTagger())
	var processCache *process.CachingWalker

	if flags.kubernetesRole != kubernetesRoleCluster {
		hostReporter := host.NewReporter(hostID, hostName, probeID, version, clients, handlerRegistry)
		defer hostReporter.Stop()
		p.AddReporter(hostReporter)
		p.AddTagger(host.NewTagger(hostID))

		if flags.procEnabled {
			processCache = process.NewCachingWalker(process.NewWalker(flags.procRoot, false))
			p.AddTicker(processCache)
			p.AddReporter(process.NewReporter(processCache, hostID, process.GetDeltaTotalJiffies, flags.noCommandLineArguments))
		}

		dnsSnooper, err := endpoint.NewDNSSnooper()
		if err != nil {
			log.Errorf("Failed to start DNS snooper: nodes for external services will be less accurate: %s", err)
		} else {
			defer dnsSnooper.Stop()
		}

		endpointReporter := endpoint.NewReporter(endpoint.ReporterConfig{
			HostID:       hostID,
			HostName:     hostName,
			SpyProcs:     flags.spyProcs,
			UseConntrack: flags.useConntrack,
			WalkProc:     flags.procEnabled,
			UseEbpfConn:  flags.useEbpfConn,
			ProcRoot:     flags.procRoot,
			BufferSize:   flags.conntrackBufferSize,
			ProcessCache: processCache,
			DNSSnooper:   dnsSnooper,
		})
		defer endpointReporter.Stop()
		p.AddReporter(endpointReporter)
	}

	if flags.dockerEnabled {
		// Don't add the bridge in Kubernetes since container IPs are global and
		// shouldn't be scoped
		if flags.dockerBridge != "" && !flags.kubernetesEnabled {
			if err := report.AddLocalBridge(flags.dockerBridge); err != nil {
				log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err)
			}
		}
		options := docker.RegistryOptions{
			Interval:               flags.dockerInterval,
			Pipes:                  clients,
			CollectStats:           true,
			HostID:                 hostID,
			HandlerRegistry:        handlerRegistry,
			NoCommandLineArguments: flags.noCommandLineArguments,
			NoEnvironmentVariables: flags.noEnvironmentVariables,
		}
		if registry, err := docker.NewRegistry(options); err == nil {
			defer registry.Stop()
			if flags.procEnabled {
				p.AddTagger(docker.NewTagger(registry, processCache))
			}
			p.AddReporter(docker.NewReporter(registry, hostID, probeID, p))
		} else {
			log.Errorf("Docker: failed to start registry: %v", err)
		}
	}

	if flags.criEnabled {
		client, err := cri.NewCRIClient(flags.criEndpoint)
		if err != nil {
			log.Errorf("CRI: failed to start registry: %v", err)
		} else {
			p.AddReporter(cri.NewReporter(client))
		}
	}

	if flags.kubernetesEnabled && flags.kubernetesRole != kubernetesRoleHost {
		if client, err := kubernetes.NewClient(flags.kubernetesClientConfig); err == nil {
			defer client.Stop()
			reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p, handlerRegistry, flags.kubernetesNodeName)
			defer reporter.Stop()
			p.AddReporter(reporter)
			if flags.kubernetesRole != kubernetesRoleCluster && flags.kubernetesNodeName == "" {
				log.Warnf("No value for --probe.kubernetes.node-name, reporting all pods from every probe (which may impact performance).")
			}
		} else {
			log.Errorf("Kubernetes: failed to start client: %v", err)
			log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide valid probe.kubernetes.* flags")
		}
	}

	if flags.kubernetesEnabled {
		p.AddTagger(&kubernetes.Tagger{})
	}

	if flags.ecsEnabled {
		reporter := awsecs.Make(flags.ecsCacheSize, flags.ecsCacheExpiry, flags.ecsClusterRegion, handlerRegistry, probeID)
		defer reporter.Stop()
		p.AddReporter(reporter)
		p.AddTagger(reporter)
	}

	if flags.weaveEnabled {
		client := weave.NewClient(sanitize.URL("http://", 6784, "")(flags.weaveAddr))
		weave, err := overlay.NewWeave(hostID, client)
		if err != nil {
			log.Errorf("Weave: failed to start client: %v", err)
		} else {
			defer weave.Stop()
			p.AddTagger(weave)
			p.AddReporter(weave)
		}
	}

	if flags.pluginsRoot != "" {
		pluginRegistry, err := plugins.NewRegistry(
			flags.pluginsRoot,
			pluginAPIVersion,
			map[string]string{
				"probe_id":    probeID,
				"api_version": pluginAPIVersion,
			},
			handlerRegistry,
			p,
		)
		if err != nil {
			log.Errorf("plugins: problem loading: %v", err)
		} else {
			defer pluginRegistry.Close()
			p.AddReporter(pluginRegistry)
		}
	}

	maybeExportProfileData(flags)

	p.Start()
	signals.SignalHandlerLoop(
		logging.Logrus(log.StandardLogger()),
		p,
	)
}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"
	"net"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/armon/go-metrics"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/weaveworks/common/network"
	"github.com/weaveworks/common/sanitize"
	"github.com/weaveworks/go-checkpoint"
	"github.com/weaveworks/scope/common/hostname"
	"github.com/weaveworks/scope/common/weave"
	"github.com/weaveworks/scope/common/xfer"
	"github.com/weaveworks/scope/probe"
	"github.com/weaveworks/scope/probe/appclient"
	"github.com/weaveworks/scope/probe/awsecs"
	"github.com/weaveworks/scope/probe/controls"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/probe/overlay"
	"github.com/weaveworks/scope/probe/plugins"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/report"
	"github.com/weaveworks/weave/common"
)

const (
	versionCheckPeriod = 6 * time.Hour
	defaultServiceHost = "https://cloud.weave.works.:443"
)

var (
	pluginAPIVersion = "1"
)

func checkNewScopeVersion(flags probeFlags) {
	checkpointFlags := makeBaseCheckpointFlags()
	if flags.kubernetesEnabled {
		checkpointFlags["kubernetes_enabled"] = "true"
	}
	if flags.ecsEnabled {
		checkpointFlags["ecs_enabled"] = "true"
	}

	go func() {
		handleResponse := func(r *checkpoint.CheckResponse, err error) {
			if err != nil {
				log.Errorf("Error checking version: %v", err)
			} else if r.Outdated {
				log.Infof("Scope version %s is available; please update at %s",
					r.CurrentVersion, r.CurrentDownloadURL)
			}
		}

		// Start background version checking
		params := checkpoint.CheckParams{
			Product: "scope-probe",
			Version: version,
			Flags:   checkpointFlags,
		}
		resp, err := checkpoint.Check(&params)
		handleResponse(resp, err)
		checkpoint.CheckInterval(&params, versionCheckPeriod, handleResponse)
	}()
}

func maybeExportProfileData(flags probeFlags) {
	if flags.httpListen != "" {
		go func() {
			http.Handle("/metrics", prometheus.Handler())
			log.Infof("Profiling data being exported to %s", flags.httpListen)
			log.Infof("go tool pprof http://%s/debug/pprof/{profile,heap,block}", flags.httpListen)
			log.Infof("Profiling endpoint %s terminated: %v", flags.httpListen, http.ListenAndServe(flags.httpListen, nil))
		}()
	}
}

// Main runs the probe
func probeMain(flags probeFlags, targets []appclient.Target) {
	setLogLevel(flags.logLevel)
	setLogFormatter(flags.logPrefix)

	// Setup in memory metrics sink
	inm := metrics.NewInmemSink(time.Minute, 2*time.Minute)
	sig := metrics.DefaultInmemSignal(inm)
	defer sig.Stop()
	metrics.NewGlobal(metrics.DefaultConfig("scope-probe"), inm)
	logCensoredArgs()
	defer log.Info("probe exiting")

	if flags.spyProcs && os.Getegid() != 0 {
		log.Warn("--probe.process=true, but that requires root to find everything")
	}

	rand.Seed(time.Now().UnixNano())
	var (
		probeID  = strconv.FormatInt(rand.Int63(), 16)
		hostName = hostname.Get()
		hostID   = hostName // TODO(pb): we should sanitize the hostname
	)
	log.Infof("probe starting, version %s, ID %s", version, probeID)
	checkNewScopeVersion(flags)

	handlerRegistry := controls.NewDefaultHandlerRegistry()
	clientFactory := func(hostname string, url url.URL) (appclient.AppClient, error) {
		token := flags.token
		if url.User != nil {
			token = url.User.Username()
			url.User = nil // erase credentials, as we use a special header
		}
		probeConfig := appclient.ProbeConfig{
			Token:        token,
			ProbeVersion: version,
			ProbeID:      probeID,
			Insecure:     flags.insecure,
		}
		return appclient.NewAppClient(
			probeConfig, hostname, url,
			xfer.ControlHandlerFunc(handlerRegistry.HandleControlRequest),
		)
	}
	clients := appclient.NewMultiAppClient(clientFactory, flags.noControls)
	defer clients.Stop()

	dnsLookupFn := net.LookupIP
	if flags.resolver != "" {
		dnsLookupFn = appclient.LookupUsing(flags.resolver)
	}
	resolver, err := appclient.NewResolver(appclient.ResolverConfig{
		Targets: targets,
		Lookup:  dnsLookupFn,
		Set:     clients.Set,
	})
	if err != nil {
		log.Fatalf("Failed to create resolver: %v", err)
		return
	}
	defer resolver.Stop()

	p := probe.New(flags.spyInterval, flags.publishInterval, clients, flags.noControls)

	hostReporter := host.NewReporter(hostID, hostName, probeID, version, clients, handlerRegistry)
	defer hostReporter.Stop()
	p.AddReporter(hostReporter)
	p.AddTagger(probe.NewTopologyTagger(), host.NewTagger(hostID))

	var processCache *process.CachingWalker
	if flags.procEnabled {
		processCache = process.NewCachingWalker(process.NewWalker(flags.procRoot, false))
		p.AddTicker(processCache)
		p.AddReporter(process.NewReporter(processCache, hostID, process.GetDeltaTotalJiffies, flags.noCommandLineArguments))
	}

	dnsSnooper, err := endpoint.NewDNSSnooper()
	if err != nil {
		log.Errorf("Failed to start DNS snooper: nodes for external services will be less accurate: %s", err)
	} else {
		defer dnsSnooper.Stop()
	}

	endpointReporter := endpoint.NewReporter(endpoint.ReporterConfig{
		HostID:       hostID,
		HostName:     hostName,
		SpyProcs:     flags.spyProcs,
		UseConntrack: flags.useConntrack,
		WalkProc:     flags.procEnabled,
		UseEbpfConn:  flags.useEbpfConn,
		ProcRoot:     flags.procRoot,
		BufferSize:   flags.conntrackBufferSize,
		ProcessCache: processCache,
		DNSSnooper:   dnsSnooper,
	})
	defer endpointReporter.Stop()
	p.AddReporter(endpointReporter)

	if flags.dockerEnabled {
		// Don't add the bridge in Kubernetes since container IPs are global and
		// shouldn't be scoped
		if !flags.kubernetesEnabled {
			if err := report.AddLocalBridge(flags.dockerBridge); err != nil {
				log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err)
			}
		}
		options := docker.RegistryOptions{
			Interval:               flags.dockerInterval,
			Pipes:                  clients,
			CollectStats:           true,
			HostID:                 hostID,
			HandlerRegistry:        handlerRegistry,
			NoCommandLineArguments: flags.noCommandLineArguments,
			NoEnvironmentVariables: flags.noEnvironmentVariables,
		}
		if registry, err := docker.NewRegistry(options); err == nil {
			defer registry.Stop()
			if flags.procEnabled {
				p.AddTagger(docker.NewTagger(registry, processCache))
			}
			p.AddReporter(docker.NewReporter(registry, hostID, probeID, p))
		} else {
			log.Errorf("Docker: failed to start registry: %v", err)
		}
	}

	if flags.kubernetesEnabled {
		if client, err := kubernetes.NewClient(flags.kubernetesClientConfig); err == nil {
			defer client.Stop()
			reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p, handlerRegistry, flags.kubernetesNodeName, flags.kubernetesKubeletPort)
			defer reporter.Stop()
			p.AddReporter(reporter)
			p.AddTagger(reporter)
		} else {
			log.Errorf("Kubernetes: failed to start client: %v", err)
			log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide valid probe.kubernetes.* flags")
		}
	}

	if flags.ecsEnabled {
		reporter := awsecs.Make(flags.ecsCacheSize, flags.ecsCacheExpiry, flags.ecsClusterRegion, handlerRegistry, probeID)
		defer reporter.Stop()
		p.AddReporter(reporter)
		p.AddTagger(reporter)
	}

	if flags.weaveEnabled {
		client := weave.NewClient(sanitize.URL("http://", 6784, "")(flags.weaveAddr))
		weave, err := overlay.NewWeave(hostID, client)
		if err != nil {
			log.Errorf("Weave: failed to start client: %v", err)
		} else {
			defer weave.Stop()
			p.AddTagger(weave)
			p.AddReporter(weave)

			if flags.weaveHostname != "" {
				dockerBridgeIP, err := network.GetFirstAddressOf(flags.dockerBridge)
				if err != nil {
					log.Errorf("Error getting docker bridge ip: %v", err)
				} else {
					weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53")
					weaveTargets, err := appclient.ParseTargets([]string{flags.weaveHostname})
					if err != nil {
						log.Errorf("Failed to parse weave targets: %v", err)
					} else {
						weaveResolver, err := appclient.NewResolver(appclient.ResolverConfig{
							Targets: weaveTargets,
							Lookup:  weaveDNSLookup,
							Set:     clients.Set,
						})
						if err != nil {
							log.Errorf("Failed to create weave resolver: %v", err)
						} else {
							defer weaveResolver.Stop()
						}
					}
				}
			}
		}
	}

	pluginRegistry, err := plugins.NewRegistry(
		flags.pluginsRoot,
		pluginAPIVersion,
		map[string]string{
			"probe_id":    probeID,
			"api_version": pluginAPIVersion,
		},
		handlerRegistry,
		p,
	)
	if err != nil {
		log.Errorf("plugins: problem loading: %v", err)
	} else {
		defer pluginRegistry.Close()
		p.AddReporter(pluginRegistry)
	}

	maybeExportProfileData(flags)

	p.Start()
	defer p.Stop()

	common.SignalHandlerLoop()
}
<commit_msg>Probe: fix message to name the correct flag<commit_after>package main

import (
	"math/rand"
	"net"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/armon/go-metrics"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/weaveworks/common/network"
	"github.com/weaveworks/common/sanitize"
	"github.com/weaveworks/go-checkpoint"
	"github.com/weaveworks/scope/common/hostname"
	"github.com/weaveworks/scope/common/weave"
	"github.com/weaveworks/scope/common/xfer"
	"github.com/weaveworks/scope/probe"
	"github.com/weaveworks/scope/probe/appclient"
	"github.com/weaveworks/scope/probe/awsecs"
	"github.com/weaveworks/scope/probe/controls"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/endpoint"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/kubernetes"
	"github.com/weaveworks/scope/probe/overlay"
	"github.com/weaveworks/scope/probe/plugins"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/report"
	"github.com/weaveworks/weave/common"
)

const (
	versionCheckPeriod = 6 * time.Hour
	defaultServiceHost = "https://cloud.weave.works.:443"
)

var (
	pluginAPIVersion = "1"
)

func checkNewScopeVersion(flags probeFlags) {
	checkpointFlags := makeBaseCheckpointFlags()
	if flags.kubernetesEnabled {
		checkpointFlags["kubernetes_enabled"] = "true"
	}
	if flags.ecsEnabled {
		checkpointFlags["ecs_enabled"] = "true"
	}

	go func() {
		handleResponse := func(r *checkpoint.CheckResponse, err error) {
			if err != nil {
				log.Errorf("Error checking version: %v", err)
			} else if r.Outdated {
				log.Infof("Scope version %s is available; please update at %s",
					r.CurrentVersion, r.CurrentDownloadURL)
			}
		}

		// Start background version checking
		params := checkpoint.CheckParams{
			Product: "scope-probe",
			Version: version,
			Flags:   checkpointFlags,
		}
		resp, err := checkpoint.Check(&params)
		handleResponse(resp, err)
		checkpoint.CheckInterval(&params, versionCheckPeriod, handleResponse)
	}()
}

func maybeExportProfileData(flags probeFlags) {
	if flags.httpListen != "" {
		go func() {
			http.Handle("/metrics", prometheus.Handler())
			log.Infof("Profiling data being exported to %s", flags.httpListen)
			log.Infof("go tool pprof http://%s/debug/pprof/{profile,heap,block}", flags.httpListen)
			log.Infof("Profiling endpoint %s terminated: %v", flags.httpListen, http.ListenAndServe(flags.httpListen, nil))
		}()
	}
}

// Main runs the probe
func probeMain(flags probeFlags, targets []appclient.Target) {
	setLogLevel(flags.logLevel)
	setLogFormatter(flags.logPrefix)

	// Setup in memory metrics sink
	inm := metrics.NewInmemSink(time.Minute, 2*time.Minute)
	sig := metrics.DefaultInmemSignal(inm)
	defer sig.Stop()
	metrics.NewGlobal(metrics.DefaultConfig("scope-probe"), inm)
	logCensoredArgs()
	defer log.Info("probe exiting")

	if flags.spyProcs && os.Getegid() != 0 {
		log.Warn("--probe.proc.spy=true, but that requires root to find everything")
	}

	rand.Seed(time.Now().UnixNano())
	var (
		probeID  = strconv.FormatInt(rand.Int63(), 16)
		hostName = hostname.Get()
		hostID   = hostName // TODO(pb): we should sanitize the hostname
	)
	log.Infof("probe starting, version %s, ID %s", version, probeID)
	checkNewScopeVersion(flags)

	handlerRegistry := controls.NewDefaultHandlerRegistry()
	clientFactory := func(hostname string, url url.URL) (appclient.AppClient, error) {
		token := flags.token
		if url.User != nil {
			token = url.User.Username()
			url.User = nil // erase credentials, as we use a special header
		}
		probeConfig := appclient.ProbeConfig{
			Token:        token,
			ProbeVersion: version,
			ProbeID:      probeID,
			Insecure:     flags.insecure,
		}
		return appclient.NewAppClient(
			probeConfig, hostname, url,
			xfer.ControlHandlerFunc(handlerRegistry.HandleControlRequest),
		)
	}
	clients := appclient.NewMultiAppClient(clientFactory, flags.noControls)
	defer clients.Stop()

	dnsLookupFn := net.LookupIP
	if flags.resolver != "" {
		dnsLookupFn = appclient.LookupUsing(flags.resolver)
	}
	resolver, err := appclient.NewResolver(appclient.ResolverConfig{
		Targets: targets,
		Lookup:  dnsLookupFn,
		Set:     clients.Set,
	})
	if err != nil {
		log.Fatalf("Failed to create resolver: %v", err)
		return
	}
	defer resolver.Stop()

	p := probe.New(flags.spyInterval, flags.publishInterval, clients, flags.noControls)

	hostReporter := host.NewReporter(hostID, hostName, probeID, version, clients, handlerRegistry)
	defer hostReporter.Stop()
	p.AddReporter(hostReporter)
	p.AddTagger(probe.NewTopologyTagger(), host.NewTagger(hostID))

	var processCache *process.CachingWalker
	if flags.procEnabled {
		processCache = process.NewCachingWalker(process.NewWalker(flags.procRoot, false))
		p.AddTicker(processCache)
		p.AddReporter(process.NewReporter(processCache, hostID, process.GetDeltaTotalJiffies, flags.noCommandLineArguments))
	}

	dnsSnooper, err := endpoint.NewDNSSnooper()
	if err != nil {
		log.Errorf("Failed to start DNS snooper: nodes for external services will be less accurate: %s", err)
	} else {
		defer dnsSnooper.Stop()
	}

	endpointReporter := endpoint.NewReporter(endpoint.ReporterConfig{
		HostID:       hostID,
		HostName:     hostName,
		SpyProcs:     flags.spyProcs,
		UseConntrack: flags.useConntrack,
		WalkProc:     flags.procEnabled,
		UseEbpfConn:  flags.useEbpfConn,
		ProcRoot:     flags.procRoot,
		BufferSize:   flags.conntrackBufferSize,
		ProcessCache: processCache,
		DNSSnooper:   dnsSnooper,
	})
	defer endpointReporter.Stop()
	p.AddReporter(endpointReporter)

	if flags.dockerEnabled {
		// Don't add the bridge in Kubernetes since container IPs are global and
		// shouldn't be scoped
		if !flags.kubernetesEnabled {
			if err := report.AddLocalBridge(flags.dockerBridge); err != nil {
				log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err)
			}
		}
		options := docker.RegistryOptions{
			Interval:               flags.dockerInterval,
			Pipes:                  clients,
			CollectStats:           true,
			HostID:                 hostID,
			HandlerRegistry:        handlerRegistry,
			NoCommandLineArguments: flags.noCommandLineArguments,
			NoEnvironmentVariables: flags.noEnvironmentVariables,
		}
		if registry, err := docker.NewRegistry(options); err == nil {
			defer registry.Stop()
			if flags.procEnabled {
				p.AddTagger(docker.NewTagger(registry, processCache))
			}
			p.AddReporter(docker.NewReporter(registry, hostID, probeID, p))
		} else {
			log.Errorf("Docker: failed to start registry: %v", err)
		}
	}

	if flags.kubernetesEnabled {
		if client, err := kubernetes.NewClient(flags.kubernetesClientConfig); err == nil {
			defer client.Stop()
			reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p, handlerRegistry, flags.kubernetesNodeName, flags.kubernetesKubeletPort)
			defer reporter.Stop()
			p.AddReporter(reporter)
			p.AddTagger(reporter)
		} else {
			log.Errorf("Kubernetes: failed to start client: %v", err)
			log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide valid probe.kubernetes.* flags")
		}
	}

	if flags.ecsEnabled {
		reporter := awsecs.Make(flags.ecsCacheSize, flags.ecsCacheExpiry, flags.ecsClusterRegion, handlerRegistry, probeID)
		defer reporter.Stop()
		p.AddReporter(reporter)
		p.AddTagger(reporter)
	}

	if flags.weaveEnabled {
		client := weave.NewClient(sanitize.URL("http://", 6784, "")(flags.weaveAddr))
		weave, err := overlay.NewWeave(hostID, client)
		if err != nil {
			log.Errorf("Weave: failed to start client: %v", err)
		} else {
			defer weave.Stop()
			p.AddTagger(weave)
			p.AddReporter(weave)

			if flags.weaveHostname != "" {
				dockerBridgeIP, err := network.GetFirstAddressOf(flags.dockerBridge)
				if err != nil {
					log.Errorf("Error getting docker bridge ip: %v", err)
				} else {
					weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53")
					weaveTargets, err := appclient.ParseTargets([]string{flags.weaveHostname})
					if err != nil {
						log.Errorf("Failed to parse weave targets: %v", err)
					} else {
						weaveResolver, err := appclient.NewResolver(appclient.ResolverConfig{
							Targets: weaveTargets,
							Lookup:  weaveDNSLookup,
							Set:     clients.Set,
						})
						if err != nil {
							log.Errorf("Failed to create weave resolver: %v", err)
						} else {
							defer weaveResolver.Stop()
						}
					}
				}
			}
		}
	}

	pluginRegistry, err := plugins.NewRegistry(
		flags.pluginsRoot,
		pluginAPIVersion,
		map[string]string{
			"probe_id":    probeID,
			"api_version": pluginAPIVersion,
		},
		handlerRegistry,
		p,
	)
	if err != nil {
		log.Errorf("plugins: problem loading: %v", err)
	} else {
		defer pluginRegistry.Close()
		p.AddReporter(pluginRegistry)
	}

	maybeExportProfileData(flags)

	p.Start()
	defer p.Stop()

	common.SignalHandlerLoop()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

// オプション
type options struct {
	host string // リモートホスト
}

// 実行コンテキスト
type context struct {
	host   string // リモートホスト
	path   string // 処理中のファイル
	lineno uint   // 処理中の行番号

	env     map[string]string // 環境変数
	user    string            // ユーザ
	workdir string            // 作業ディレクトリ

	remote  bool     // リモート実行
	cmd_run []string // RUN命令
	cmd_add []string // ADD命令
}

// コマンドの使い方
func usage() {
	cmd := os.Args[0]
	fmt.Fprintf(os.Stderr, "usage: %s [options] [file...]\n", filepath.Base(cmd))
	flag.PrintDefaults()
	os.Exit(0)
}

// コマンドの実行
func (ctx *context) execl(name string, arg ...string) (*exec.Cmd, error) {
	cmd := exec.Command(name, arg...)
	out, err := cmd.Output()
	if 0 < len(out) {
		fmt.Printf("%s", out)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s:%d: %s : %s\n", ctx.path, ctx.lineno, err, arg)
	}

	return cmd, err
}

// 初期化
func (ctx *context) init() error {
	ctx.env = make(map[string]string)
	ctx.remote = (0 < len(ctx.host))

	if ctx.remote {
		ssh, err := exec.LookPath("ssh")
		if err != nil {
			return err
		}
		scp, err := exec.LookPath("scp")
		if err != nil {
			return err
		}
		ctx.cmd_run = []string{ssh, ctx.host}
		ctx.cmd_add = []string{scp}
	} else {
		ctx.cmd_run = []string{"/bin/sh", "-c"}
		ctx.cmd_add = []string{"/bin/cp"}
	}

	return nil
}

// RUN命令
func (ctx *context) run(arg string) (*exec.Cmd, error) {
	if 0 < len(ctx.workdir) {
		arg = fmt.Sprintf("cd %s; %s", ctx.workdir, arg)
	}

	return ctx.execl(ctx.cmd_run[0], append(ctx.cmd_run[1:], arg)...)
}

// ADD命令
func (ctx *context) add(src string, dst string) (*exec.Cmd, error) {
	if 0 < len(ctx.workdir) && !filepath.IsAbs(dst) {
		// コピー先のパスを生成する
		dst = filepath.Join(ctx.workdir, dst)
	}

	if ctx.remote {
		// リモート・パスを生成する
		dst = fmt.Sprintf("%s:%s", ctx.host, dst)
	}

	return ctx.execl(ctx.cmd_add[0], src, dst)
}

// ENV命令
func (ctx *context) set_env(key string, val string) {
	ctx.env[key] = val
	os.Setenv(key, val)
}

// Dockerfile の実行
func runDockerfile(path string, opts *options) error {
	var file *os.File
	var err error

	if len(path) == 0 {
		file = os.Stdin
	} else {
		file, err = os.Open(path)
		if err != nil {
			// エラー処理をする
			return err
		}
		defer file.Close()
	}

	scanner := bufio.NewScanner(file)

	// 正規表現のコンパイル
	re := regexp.MustCompile("(?i)^ *(ONBUILD +)?([A-Z]+) +([^#]+)")
	re_args := regexp.MustCompile("(?i)^([^ ]+) +(.+)")

	ctx := context{host: opts.host, path: path}

	err = ctx.init()
	if err != nil {
		return err
	}

	for scanner.Scan() {
		line := scanner.Text()
		ctx.lineno += 1
		match := re.FindStringSubmatch(line)
		if match != nil {
			//onbuild := match[1]
			instruction := match[2]
			args := match[3]

			switch instruction {
			case "FROM":
				// 何もしない
			case "MAINTAINER":
				// 何もしない
			case "RUN":
				// スクリプトを実行
				_, err := ctx.run(args)
				if err != nil {
					return err
				}
			case "CMD":
			case "EXPOSE":
				// iptables があれば書換える
			case "ENV":
				// 環境変数を設定
				match_args := re_args.FindStringSubmatch(args)
				if match_args != nil {
					ctx.set_env(match_args[1], match_args[2])
				}
			case "ADD":
				// ファイルを追加
				match_args := re_args.FindStringSubmatch(args)
				if match_args != nil {
					_, err := ctx.add(match_args[1], match_args[2])
					if err != nil {
						return err
					}
				}
			case "ENTRYPOINT":
			case "VOLUME":
				// 何もしない
			case "USER":
				// ユーザを設定
				ctx.user = args
			case "WORKDIR":
				// 作業ディレクトリを変更
				ctx.workdir = args
			}
		}
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
	}

	return err
}

func main() {
	var opts options

	flag.StringVar(&opts.host, "H", "", "host")
	help := flag.Bool("h", false, "help")
	flag.Parse()

	if *help {
		usage()
	}

	if len(flag.Args()) == 0 {
		runDockerfile("Dockerfile", &opts)
	} else {
		for _, v := range flag.Args() {
			runDockerfile(v, &opts)
		}
	}
}
<commit_msg>環境変数の設定方法を変更<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

// オプション
type options struct {
	host string // リモートホスト
}

// 実行コンテキスト
type context struct {
	host   string // リモートホスト
	path   string // 処理中のファイル
	lineno uint   // 処理中の行番号

	env     []string // 環境変数
	user    string   // ユーザ
	workdir string   // 作業ディレクトリ

	remote  bool     // リモート実行
	cmd_run []string // RUN命令
	cmd_add []string // ADD命令
}

// コマンドの使い方
func usage() {
	cmd := os.Args[0]
	fmt.Fprintf(os.Stderr, "usage: %s [options] [file...]\n", filepath.Base(cmd))
	flag.PrintDefaults()
	os.Exit(0)
}

// コマンドの実行
func (ctx *context) execl(name string, arg ...string) (*exec.Cmd, error) {
	cmd := exec.Command(name, arg...)

	if !ctx.remote {
		cmd.Env = append(cmd.Env, ctx.env...)
	}

	out, err := cmd.Output()
	if 0 < len(out) {
		fmt.Printf("%s", out)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s:%d: %s : %s\n", ctx.path, ctx.lineno, err, arg)
	}

	return cmd, err
}

// 初期化
func (ctx *context) init() error {
	ctx.remote = (0 < len(ctx.host))

	if ctx.remote {
		ssh, err := exec.LookPath("ssh")
		if err != nil {
			return err
		}
		scp, err := exec.LookPath("scp")
		if err != nil {
			return err
		}
		ctx.cmd_run = []string{ssh, ctx.host}
		ctx.cmd_add = []string{scp}
	} else {
		ctx.cmd_run = []string{"/bin/sh", "-c"}
		ctx.cmd_add = []string{"/bin/cp"}
	}

	return nil
}

// RUN命令
func (ctx *context) run(arg string) (*exec.Cmd, error) {
	if 0 < len(ctx.workdir) {
		arg = fmt.Sprintf("cd %s; %s", ctx.workdir, arg)
	}

	return ctx.execl(ctx.cmd_run[0], append(ctx.cmd_run[1:], arg)...)
}

// ADD命令
func (ctx *context) add(src string, dst string) (*exec.Cmd, error) {
	if 0 < len(ctx.workdir) && !filepath.IsAbs(dst) {
		// コピー先のパスを生成する
		dst = filepath.Join(ctx.workdir, dst)
	}

	if ctx.remote {
		// リモート・パスを生成する
		dst = fmt.Sprintf("%s:%s", ctx.host, dst)
	}

	return ctx.execl(ctx.cmd_add[0], src, dst)
}

// ENV命令
func (ctx *context) set_env(key string, val string) {
	ctx.env = append(ctx.env, fmt.Sprintf("%s=%s", key, val))
}

// Dockerfile の実行
func runDockerfile(path string, opts *options) error {
	var file *os.File
	var err error

	if len(path) == 0 {
		file = os.Stdin
	} else {
		file, err = os.Open(path)
		if err != nil {
			// エラー処理をする
			return err
		}
		defer file.Close()
	}

	scanner := bufio.NewScanner(file)

	// 正規表現のコンパイル
	re := regexp.MustCompile("(?i)^ *(ONBUILD +)?([A-Z]+) +([^#]+)")
	re_args := regexp.MustCompile("(?i)^([^ ]+) +(.+)")

	ctx := context{host: opts.host, path: path}

	err = ctx.init()
	if err != nil {
		return err
	}

	for scanner.Scan() {
		line := scanner.Text()
		ctx.lineno += 1
		match := re.FindStringSubmatch(line)
		if match != nil {
			//onbuild := match[1]
			instruction := match[2]
			args := match[3]

			switch instruction {
			case "FROM":
				// 何もしない
			case "MAINTAINER":
				// 何もしない
			case "RUN":
				// スクリプトを実行
				_, err := ctx.run(args)
				if err != nil {
					return err
				}
			case "CMD":
			case "EXPOSE":
				// iptables があれば書換える
			case "ENV":
				// 環境変数を設定
				match_args := re_args.FindStringSubmatch(args)
				if match_args != nil {
					ctx.set_env(match_args[1], match_args[2])
				}
			case "ADD":
				// ファイルを追加
				match_args := re_args.FindStringSubmatch(args)
				if match_args != nil {
					_, err := ctx.add(match_args[1], match_args[2])
					if err != nil {
						return err
					}
				}
			case "ENTRYPOINT":
			case "VOLUME":
				// 何もしない
			case "USER":
				// ユーザを設定
				ctx.user = args
			case "WORKDIR":
				// 作業ディレクトリを変更
				ctx.workdir = args
			}
		}
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
	}

	return err
}

func main() {
	var opts options

	flag.StringVar(&opts.host, "H", "", "host")
	help := flag.Bool("h", false, "help")
	flag.Parse()

	if *help {
		usage()
	}

	if len(flag.Args()) == 0 {
		runDockerfile("Dockerfile", &opts)
	} else {
		for _, v := range flag.Args() {
			runDockerfile(v, &opts)
		}
	}
}
<|endoftext|>


<commit_before>package runner

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/howeyc/fsnotify"
)

func watchFolder(path string) {
	if !strings.Contains(path, "vendor/") && !strings.Contains(path, "node_modules") && !strings.Contains(path, "public/system/") && !strings.Contains(path, ".tmpl") {
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			fatal(err)
		}

		go func() {
			for {
				select {
				case ev := <-watcher.Event:
					if isWatchedFile(ev.Name) {
						watcherLog("sending event %s", ev)
						startChannel <- ev.String()
					}
				case err := <-watcher.Error:
					watcherLog("error: %s", err)
				}
			}
		}()

		watcherLog("Watching %s", path)
		err = watcher.Watch(path)

		if err != nil {
			fatal(err)
		}
	}
}

func watch() {
	// root := root()
	paths := root()
	if extraDirs := extraDirs(); extraDirs != "" {
		paths += "," + extraDirs
	}

	for _, root := range strings.Split(paths, ",") {
		filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
			if info.IsDir() && !isTmpDir(path) {
				if len(path) > 1 && strings.HasPrefix(filepath.Base(path), ".") {
					return filepath.SkipDir
				}

				watchFolder(path)
			}

			return err
		})
	}
}
<commit_msg>Ignore bower_components<commit_after>package runner

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/howeyc/fsnotify"
)

func watchFolder(path string) {
	if !strings.Contains(path, "vendor/") && !strings.Contains(path, "bower_components") && !strings.Contains(path, "node_modules") && !strings.Contains(path, "public/system/") && !strings.Contains(path, ".tmpl") {
		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			fatal(err)
		}

		go func() {
			for {
				select {
				case ev := <-watcher.Event:
					if isWatchedFile(ev.Name) {
						watcherLog("sending event %s", ev)
						startChannel <- ev.String()
					}
				case err := <-watcher.Error:
					watcherLog("error: %s", err)
				}
			}
		}()

		watcherLog("Watching %s", path)
		err = watcher.Watch(path)

		if err != nil {
			fatal(err)
		}
	}
}

func watch() {
	// root := root()
	paths := root()
	if extraDirs := extraDirs(); extraDirs != "" {
		paths += "," + extraDirs
	}

	for _, root := range strings.Split(paths, ",") {
		filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
			if info.IsDir() && !isTmpDir(path) {
				if len(path) > 1 && strings.HasPrefix(filepath.Base(path), ".") {
					return filepath.SkipDir
				}

				watchFolder(path)
			}

			return err
		})
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015-2016, RadiantBlue Technologies, Inc.

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

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

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

// Package job provides JobManager helper functions.
package job

import (
	"bytes"
	"errors"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

// StatusType is a string describing the state of the job.
type StatusType int

// Enumerate valid StatusType values.
const (
	Submitted StatusType = iota
	Running
	Success
	Cancelled
	Error
	Fail
)

var statuses = [...]string{
	"submitted", "running", "success", "cancelled", "error", "fail",
}

func (status StatusType) String() string {
	return statuses[status]
}

// S3Bucket defines the expected JSON structure for S3 buckets.
// An S3 bucket can be used for source (input) and destination (output) files.
type S3Bucket struct {
	Bucket string `json:"bucket,omitempty"`
	Key    string `json:"key,omitempty"`
}

// InputMsg defines the expected input JSON structure.
// We currently support S3 input (bucket/key), though provider-specific (e.g.,
// GRiD) may be legitimate.
type InputMsg struct {
	Source      S3Bucket         `json:"source,omitempty"`
	Function    *string          `json:"function,omitempty"`
	Options     *json.RawMessage `json:"options,omitempty"`
	Destination S3Bucket         `json:"destination,omitempty"`
}

// OutputMsg defines the expected output JSON structure.
type OutputMsg struct {
	Input      InputMsg                    `json:"input,omitempty"`
	StartedAt  time.Time                   `json:"started_at,omitempty"`
	FinishedAt time.Time                   `json:"finished_at,omitempty"`
	Code       int                         `json:"code,omitempty"`
	Message    string                      `json:"message,omitempty"`
	Response   map[string]*json.RawMessage `json:"response,omitempty"`
}

// ResourceMetadata defines the metadata required to register the service.
type ResourceMetadata struct {
	Name                string    `json:"name"`
	Description         string    `json:"description"`
	URL                 string    `json:"url"`
	Method              string    `json:"method,omitempty"`
  RequestMimeType     string    `json:"requestMimeType,omitempty"`
	ResponseMimeType    string    `json:"responseMimeType,omitempty"`
	Params              string    `json:"params,omitempty"`
}

// RegisterServiceMsg defines the expected output JSON returned by Piazza when
// an external service is registered.
type RegisterServiceMsg struct {
	ResourceID          string    `json:"resourceId"`
}

// UpdateMsg defines the expected output JSON structure for updating the
// JobManager.
type UpdateMsg struct {
	Status string `json:"status"`
}

// Update handles PDAL status updates.
func Update(t StatusType, r *http.Request) {
	log.Println("Setting job status as \"", t.String(), "\"")
	// var res UpdateMsg
	// res.Status = t.String()
	// //	url := "http://192.168.99.100:8080/manager"
	// url := r.URL.Path + `/manager`
	//
	// jsonStr, err := json.Marshal(res)
	// req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	// req.Header.Set("Content-Type", "application/json")
	//
	// client := &http.Client{}
	// resp, err := client.Do(req)
	// if err != nil {
	// 	panic(err)
	// }
	// defer resp.Body.Close()
}

/*
BadRequest handles bad requests.

All bad requests result in a failure in the eyes of the JobManager. The
ResponseWriter echos some key aspects of the Request (e.g., input, start time)
and appends StatusBadRequest (400) as well as a message to the OutputMsg, which
is returned as JSON.
*/
func BadRequest(w http.ResponseWriter, r *http.Request, res OutputMsg, message string) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusBadRequest)
	res.Code = http.StatusBadRequest
	res.Message = message
	if err := json.NewEncoder(w).Encode(res); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	Update(Fail, r)
}

/*
InternalError handles internal server errors.

All internal server errors result in an error in the eyes of the JobManager. The
ResponseWriter echos some key aspects of the Request (e.g., input, start time)
and appends StatusInternalServerError (500) as well as a message to the
OutputMsg, which is returned as JSON.
*/
func InternalError(
	w http.ResponseWriter, r *http.Request, res OutputMsg, message string,
) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusInternalServerError)
	res.Code = http.StatusInternalServerError
	res.Message = message
	if err := json.NewEncoder(w).Encode(res); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	Update(Error, r)
}

/*
Okay handles successful calls.

All successful calls result in sucess in the eyes of the JobManager. The
ResponseWriter echos some key aspects of the Request (e.g., input, start time)
and appends StatusOK (200) as well as a message to the OutputMsg, which is
returned as JSON.
*/
func Okay(
	w http.ResponseWriter, r *http.Request, res OutputMsg, message string,
) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	res.Code = http.StatusOK
	res.Message = message
	if err := json.NewEncoder(w).Encode(res); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	Update(Success, r)
}

// GetInputMsg provides a common means of parsing the InputMsg JSON.
func GetInputMsg(
	w http.ResponseWriter, r *http.Request, res OutputMsg,
) InputMsg {
	var msg InputMsg

	// There should always be a body, else how are we to know what to do? Throw
	// 400 if missing.
	if r.Body == nil {
		http.Error(w, "No JSON", http.StatusBadRequest)
	}

	// Throw 500 if we cannot read the body.
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	// Throw 400 if we cannot unmarshal the body as a valid InputMsg.
	if err := json.Unmarshal(b, &msg); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	return msg
}

// ContentTypeJSON is the http content-type for JSON.
const ContentTypeJSON = "application/json"

// registryURL is the Piazza registration endpoint
const RegistryURL = "http://pz-servicecontroller.cf.piazzageo.io/servicecontroller/registerService"
//const RegistryURL = "http://localhost:8082/servicecontroller/registerService"

/*
RegisterService handles service registartion with Piazza for external services.
*/
func RegisterService(m ResourceMetadata) error {
  data, err := json.Marshal(m)
	if err != nil {
		return err
	}

	response, err := http.Post(RegistryURL, ContentTypeJSON, bytes.NewBuffer(data))
	if err != nil {
		return err
	}

	if response.Body == nil {
		return errors.New("No JSON body returned from registerService")
	}

	b, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err;
	}

	// Throw 400 if we cannot unmarshal the body as a valid InputMsg.
	var rm RegisterServiceMsg;
	if err := json.Unmarshal(b, &rm); err != nil {
		return err;
	}
	log.Println("RegisterService received resourceId="+rm.ResourceID)

	return nil
}
<commit_msg>Failures in GetInputMsg should return immediately<commit_after>/*
Copyright 2015-2016, RadiantBlue Technologies, Inc.

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

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

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

// Package job provides JobManager helper functions.
package job

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

// StatusType is a string describing the state of the job.
type StatusType int

// Enumerate valid StatusType values.
const (
	Submitted StatusType = iota
	Running
	Success
	Cancelled
	Error
	Fail
)

var statuses = [...]string{
	"submitted", "running", "success", "cancelled", "error", "fail",
}

func (status StatusType) String() string {
	return statuses[status]
}

// S3Bucket defines the expected JSON structure for S3 buckets.
// An S3 bucket can be used for source (input) and destination (output) files.
type S3Bucket struct {
	Bucket string `json:"bucket,omitempty"`
	Key    string `json:"key,omitempty"`
}

// InputMsg defines the expected input JSON structure.
// We currently support S3 input (bucket/key), though provider-specific (e.g.,
// GRiD) may be legitimate.
type InputMsg struct {
	Source      S3Bucket         `json:"source,omitempty"`
	Function    *string          `json:"function,omitempty"`
	Options     *json.RawMessage `json:"options,omitempty"`
	Destination S3Bucket         `json:"destination,omitempty"`
}

// OutputMsg defines the expected output JSON structure.
type OutputMsg struct {
	Input      InputMsg                    `json:"input,omitempty"`
	StartedAt  time.Time                   `json:"started_at,omitempty"`
	FinishedAt time.Time                   `json:"finished_at,omitempty"`
	Code       int                         `json:"code,omitempty"`
	Message    string                      `json:"message,omitempty"`
	Response   map[string]*json.RawMessage `json:"response,omitempty"`
}

// ResourceMetadata defines the metadata required to register the service.
type ResourceMetadata struct {
	Name             string `json:"name"`
	Description      string `json:"description"`
	URL              string `json:"url"`
	Method           string `json:"method,omitempty"`
	RequestMimeType  string `json:"requestMimeType,omitempty"`
	ResponseMimeType string `json:"responseMimeType,omitempty"`
	Params           string `json:"params,omitempty"`
}

// RegisterServiceMsg defines the expected output JSON returned by Piazza when
// an external service is registered.
type RegisterServiceMsg struct {
	ResourceID string `json:"resourceId"`
}

// UpdateMsg defines the expected output JSON structure for updating the
// JobManager.
type UpdateMsg struct {
	Status string `json:"status"`
}

// Update handles PDAL status updates.
func Update(t StatusType, r *http.Request) {
	log.Println("Setting job status as \"", t.String(), "\"")
	// var res UpdateMsg
	// res.Status = t.String()
	// //	url := "http://192.168.99.100:8080/manager"
	// url := r.URL.Path + `/manager`
	//
	// jsonStr, err := json.Marshal(res)
	// req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	// req.Header.Set("Content-Type", "application/json")
	//
	// client := &http.Client{}
	// resp, err := client.Do(req)
	// if err != nil {
	// 	panic(err)
	// }
	// defer resp.Body.Close()
}

/*
BadRequest handles bad requests.

All bad requests result in a failure in the eyes of the JobManager. The
ResponseWriter echos some key aspects of the Request (e.g., input, start time)
and appends StatusBadRequest (400) as well as a message to the OutputMsg, which
is returned as JSON.
*/
func BadRequest(w http.ResponseWriter, r *http.Request, res OutputMsg, message string) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusBadRequest)
	res.Code = http.StatusBadRequest
	res.Message = message
	if err := json.NewEncoder(w).Encode(res); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	Update(Fail, r)
}

/*
InternalError handles internal server errors.

All internal server errors result in an error in the eyes of the JobManager. The
ResponseWriter echos some key aspects of the Request (e.g., input, start time)
and appends StatusInternalServerError (500) as well as a message to the
OutputMsg, which is returned as JSON.
*/
func InternalError(
	w http.ResponseWriter, r *http.Request, res OutputMsg, message string,
) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusInternalServerError)
	res.Code = http.StatusInternalServerError
	res.Message = message
	if err := json.NewEncoder(w).Encode(res); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	Update(Error, r)
}

/*
Okay handles successful calls.

All successful calls result in sucess in the eyes of the JobManager. The
ResponseWriter echos some key aspects of the Request (e.g., input, start time)
and appends StatusOK (200) as well as a message to the OutputMsg, which is
returned as JSON.
*/
func Okay(
	w http.ResponseWriter, r *http.Request, res OutputMsg, message string,
) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusOK)
	res.Code = http.StatusOK
	res.Message = message
	if err := json.NewEncoder(w).Encode(res); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	Update(Success, r)
}

// GetInputMsg provides a common means of parsing the InputMsg JSON.
func GetInputMsg(
	w http.ResponseWriter, r *http.Request, res OutputMsg,
) InputMsg {
	var msg InputMsg

	// There should always be a body, else how are we to know what to do? Throw
	// 400 if missing.
	if r.Body == nil {
		http.Error(w, "No JSON", http.StatusBadRequest)
		return msg
	}

	// Throw 500 if we cannot read the body.
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return msg
	}

	// Throw 400 if we cannot unmarshal the body as a valid InputMsg.
	if err := json.Unmarshal(b, &msg); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return msg
	}

	return msg
}

// ContentTypeJSON is the http content-type for JSON.
const ContentTypeJSON = "application/json"

// registryURL is the Piazza registration endpoint
const RegistryURL = "http://pz-servicecontroller.cf.piazzageo.io/servicecontroller/registerService"

//const RegistryURL = "http://localhost:8082/servicecontroller/registerService"

/*
RegisterService handles service registartion with Piazza for external services.
*/
func RegisterService(m ResourceMetadata) error {
	data, err := json.Marshal(m)
	if err != nil {
		return err
	}

	response, err := http.Post(RegistryURL, ContentTypeJSON, bytes.NewBuffer(data))
	if err != nil {
		return err
	}

	if response.Body == nil {
		return errors.New("No JSON body returned from registerService")
	}

	b, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}

	// Throw 400 if we cannot unmarshal the body as a valid InputMsg.
	var rm RegisterServiceMsg
	if err := json.Unmarshal(b, &rm); err != nil {
		return err
	}
	log.Println("RegisterService received resourceId=" + rm.ResourceID)

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"jogurto/commands"
)

func main() {
	var options string
	var packages []string
	if len(os.Args) < 2 {
		fmt.Printf("%s: A yaourt-like interface and toolkit for Debian.", os.Args[0])
	} else {
		options = os.Args[1]
		packages = os.Args[2:]
	}
	run := commands.Map[options]
	if run != nil {
		err := run(packages)
		if err != nil {
			fmt.Printf("An error occurred: %s", err.Error())
		}
	} else {
		fmt.Println("Command not defined")
	}
}<commit_msg>Slightly improve error messages<commit_after>package main

import (
	"fmt"
	"os"
	"jogurto/commands"
)

func main() {
	var options string
	var packages []string
	if len(os.Args) < 2 {
		fmt.Printf("%s: A yaourt-like interface and toolkit for Debian.", os.Args[0])
	} else {
		options = os.Args[1]
		packages = os.Args[2:]
	}
	run := commands.Map[options]
	if run != nil {
		err := run(packages)
		if err != nil {
			fmt.Println("An error occurred:", err.Error())
		}
	} else {
		fmt.Println("Option", options, "not implemented")
	}
}<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package memfs

import (
	"fmt"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/timeutil"
	"golang.org/x/net/context"
)

type memFS struct {
	fuseutil.NotImplementedFileSystem

	/////////////////////////
	// Dependencies
	/////////////////////////

	clock timeutil.Clock

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// The collection of all inodes that have ever been created, indexed by inode
	// ID. Some inodes are not in use if they have been unlinked, and no inode
	// with ID less than fuse.RootInodeID is ever used.
	//
	// INVARIANT: len(inodes) > fuse.RootInodeID
	// INVARIANT: For all i < fuse.RootInodeID, inodes[i].impl == nil
	// INVARIANT: inodes[fuse.RootInodeID].impl is of type *memDir
	inodes []inode // GUARDED_BY(mu)

	// A list of inode IDs within inodes available for reuse, not including the
	// reserved IDs less than fuse.RootInodeID.
	//
	// INVARIANT: This is all and only indices i of inodes such that i >
	// fuse.RootInodeID and inodes[i].impl == nil
	freeInodes []fuse.InodeID // GUARDED_BY(mu)
}

// Create a file system that stores data and metadata in memory.
func NewMemFS(
	clock timeutil.Clock) fuse.FileSystem {
	// Set up the basic struct.
	fs := &memFS{
		clock:  clock,
		inodes: make([]inode, fuse.RootInodeID+1),
	}

	// Set up the root inode.
	fs.inodes[fuse.RootInodeID].impl = newDir()

	// Set up invariant checking.
	fs.mu = syncutil.NewInvariantMutex(fs.checkInvariants)

	return fs
}

func (fs *memFS) checkInvariants() {
	// Check general inode invariants.
	for i := range fs.inodes {
		fs.inodes[i].checkInvariants()
	}

	// Check reserved inodes.
	for i := 0; i < fuse.RootInodeID; i++ {
		var inode *inode = &fs.inodes[i]
		if inode.impl != nil {
			panic(fmt.Sprintf("Non-nil impl for ID: %v", i))
		}
	}

	// Check the root inode.
	_ = fs.inodes[fuse.RootInodeID].impl.(*memDir)

	// Check inodes, building our own set of free IDs.
	freeIDsEncountered := make(map[fuse.InodeID]struct{})
	for i := fuse.RootInodeID + 1; i < len(fs.inodes); i++ {
		var inode *inode = &fs.inodes[i]
		if inode.impl == nil {
			freeIDsEncountered[fuse.InodeID(i)] = struct{}{}
			continue
		}
	}

	// Check fs.freeInodes.
	if len(fs.freeInodes) != len(freeIDsEncountered) {
		panic(
			fmt.Sprintf(
				"Length mismatch: %v vs. %v",
				len(fs.freeInodes),
				len(freeIDsEncountered)))
	}

	for _, id := range fs.freeInodes {
		if _, ok := freeIDsEncountered[id]; !ok {
			panic(fmt.Sprintf("Unexected free inode ID: %v", id))
		}
	}
}

func (fs *memFS) Init(
	ctx context.Context,
	req *fuse.InitRequest) (resp *fuse.InitResponse, err error) {
	resp = &fuse.InitResponse{}
	return
}

func (fs *memFS) OpenDir(
	ctx context.Context,
	req *fuse.OpenDirRequest) (resp *fuse.OpenDirResponse, err error) {
	resp = &fuse.OpenDirResponse{}

	fs.mu.RLock()
	defer fs.mu.RUnlock()

	// We don't mutate spontaneosuly, so if the VFS layer has asked for an
	// inode that doesn't exist, something screwed up earlier (a lookup, a
	// cache invalidation, etc.).
	if req.Inode >= fuse.InodeID(len(fs.inodes)) {
		panic(fmt.Sprintf("Inode out of range: %v vs. %v", req.Inode, len(fs.inodes)))
	}

	var inode *inode = &fs.inodes[req.Inode]
	if inode.impl == nil {
		panic(fmt.Sprintf("Dead inode requested: %v", req.Inode))
	}

	// All is good.
	return
}
<commit_msg>Implemented memFS.ReadDir.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package memfs

import (
	"fmt"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/gcloud/syncutil"
	"github.com/jacobsa/gcsfuse/timeutil"
	"golang.org/x/net/context"
)

type memFS struct {
	fuseutil.NotImplementedFileSystem

	/////////////////////////
	// Dependencies
	/////////////////////////

	clock timeutil.Clock

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// The collection of all inodes that have ever been created, indexed by inode
	// ID. Some inodes are not in use if they have been unlinked, and no inode
	// with ID less than fuse.RootInodeID is ever used.
	//
	// INVARIANT: len(inodes) > fuse.RootInodeID
	// INVARIANT: For all i < fuse.RootInodeID, inodes[i].impl == nil
	// INVARIANT: inodes[fuse.RootInodeID].impl is of type *memDir
	inodes []inode // GUARDED_BY(mu)

	// A list of inode IDs within inodes available for reuse, not including the
	// reserved IDs less than fuse.RootInodeID.
	//
	// INVARIANT: This is all and only indices i of inodes such that i >
	// fuse.RootInodeID and inodes[i].impl == nil
	freeInodes []fuse.InodeID // GUARDED_BY(mu)
}

// Create a file system that stores data and metadata in memory.
func NewMemFS(
	clock timeutil.Clock) fuse.FileSystem {
	// Set up the basic struct.
	fs := &memFS{
		clock:  clock,
		inodes: make([]inode, fuse.RootInodeID+1),
	}

	// Set up the root inode.
	fs.inodes[fuse.RootInodeID].impl = newDir()

	// Set up invariant checking.
	fs.mu = syncutil.NewInvariantMutex(fs.checkInvariants)

	return fs
}

func (fs *memFS) checkInvariants() {
	// Check general inode invariants.
	for i := range fs.inodes {
		fs.inodes[i].checkInvariants()
	}

	// Check reserved inodes.
	for i := 0; i < fuse.RootInodeID; i++ {
		var inode *inode = &fs.inodes[i]
		if inode.impl != nil {
			panic(fmt.Sprintf("Non-nil impl for ID: %v", i))
		}
	}

	// Check the root inode.
	_ = fs.inodes[fuse.RootInodeID].impl.(*memDir)

	// Check inodes, building our own set of free IDs.
	freeIDsEncountered := make(map[fuse.InodeID]struct{})
	for i := fuse.RootInodeID + 1; i < len(fs.inodes); i++ {
		var inode *inode = &fs.inodes[i]
		if inode.impl == nil {
			freeIDsEncountered[fuse.InodeID(i)] = struct{}{}
			continue
		}
	}

	// Check fs.freeInodes.
	if len(fs.freeInodes) != len(freeIDsEncountered) {
		panic(
			fmt.Sprintf(
				"Length mismatch: %v vs. %v",
				len(fs.freeInodes),
				len(freeIDsEncountered)))
	}

	for _, id := range fs.freeInodes {
		if _, ok := freeIDsEncountered[id]; !ok {
			panic(fmt.Sprintf("Unexected free inode ID: %v", id))
		}
	}
}

func (fs *memFS) Init(
	ctx context.Context,
	req *fuse.InitRequest) (resp *fuse.InitResponse, err error) {
	resp = &fuse.InitResponse{}
	return
}

// Panic if not a live dir.
//
// LOCKS_EXCLUDED(fs.mu)
func (fs *memFS) getDirOrDie(inodeID fuse.InodeID) (d *memDir) {
	fs.mu.RLock()
	defer fs.mu.RUnlock()

	if inodeID >= fuse.InodeID(len(fs.inodes)) {
		panic(fmt.Sprintf("Inode out of range: %v vs. %v", inodeID, len(fs.inodes)))
	}

	var inode *inode = &fs.inodes[inodeID]
	d = inode.impl.(*memDir)

	return
}

func (fs *memFS) OpenDir(
	ctx context.Context,
	req *fuse.OpenDirRequest) (resp *fuse.OpenDirResponse, err error) {
	resp = &fuse.OpenDirResponse{}

	// We don't mutate spontaneosuly, so if the VFS layer has asked for an
	// inode that doesn't exist, something screwed up earlier (a lookup, a
	// cache invalidation, etc.).
	_ = fs.getDirOrDie(req.Inode)

	return
}

func (fs *memFS) ReadDir(
	ctx context.Context,
	req *fuse.ReadDirRequest) (resp *fuse.ReadDirResponse, err error) {
	resp = &fuse.ReadDirResponse{}

	// Grab the directory.
	d := fs.getDirOrDie(req.Inode)

	d.mu.RLock()
	defer d.mu.RUnlock()

	// Return the entries requested.
	for i := int(req.Offset); i < len(d.entries); i++ {
		resp.Data = fuseutil.AppendDirent(resp.Data, d.entries[i])

		// Trim and stop early if we've exceeded the requested size.
		if len(resp.Data) > req.Size {
			resp.Data = resp.Data[:req.Size]
			break
		}
	}

	return
}
<|endoftext|>


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

//	leafveingo web 状态页处理
package leafveingo

import (
	"io"
	"net/http"
	"strconv"
)

const (
	HttpStartTemplate = `<!doctype html>

	<meta charset="UTF-8">
	<title>Error {{.status}}</title>

{{.status}}

{{.msg}}

		Back

{{.error}}

{{.stack}}

{{Leafveingo_app_name}} Version {{Leafveingo_app_version}}

Leafveingo Version {{Leafveingo_version}}

Golang Version {{GoVersion}}

`

	Status301Msg = "Moved Permanently"
	Status307Msg = "Temporary Redirect"
	Status400Msg = "Bad Request"
	Status403Msg = "Forbidden The server understood the request"
	Status404Msg = "Page Not Found"
	Status500Msg = "Internal Server Error"
	Status503Msg = "Service Unavailable"
)

var (
	//	http status support code
	//	http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
	Status200 = HttpStatus(200)
	Status301 = HttpStatus(301)
	Status307 = HttpStatus(307)
	Status400 = HttpStatus(400)
	Status403 = HttpStatus(403)
	Status404 = HttpStatus(404)
	Status500 = HttpStatus(500)
	Status503 = HttpStatus(503)
)

//	http status code
type HttpStatus int16

//	数据的封装
type HttpStatusValue struct {
	status HttpStatus        // status code
	data   map[string]string //
}

//	new status value
func NewHttpStatusValue(status HttpStatus, msg, error, stack string) HttpStatusValue {

	data := make(map[string]string)
	data["msg"] = msg
	data["error"] = error
	data["stack"] = stack
	data["status"] = strconv.Itoa(int(status))

	return HttpStatusValue{status, data}
}

//	根据状态获取相应的字符串信息
//
//	@status
//	@return
func StatusMsg(status HttpStatus) string {
	msg := ""
	switch status {
	case Status200:
		msg = "ok"
	case Status301:
		msg = Status301Msg
	case Status307:
		msg = Status307Msg
	case Status400:
		msg = Status400Msg
	case Status403:
		msg = Status403Msg
	case Status404:
		msg = Status404Msg
	case Status500:
		msg = Status500Msg
	case Status503:
		msg = Status503Msg
	}
	return msg
}
<commit_msg>增加状态代码的字符串转换<commit_after>//	Copyright 2013 slowfei And The Contributors All rights reserved.
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
//  Create on 2013-11-13
//  Update on 2014-06-20
//  Email  slowfei#foxmail.com
//  Home   http://www.slowfei.com

//	leafveingo web 状态页处理
package leafveingo

import (
	"io"
	"net/http"
	"strconv"
)

const (
	HttpStartTemplate = `<!doctype html>

	<meta charset="UTF-8">
	<title>Error {{.status}}</title>

{{.status}}

{{.msg}}

		Back

{{.error}}

{{.stack}}

{{Leafveingo_app_name}} Version {{Leafveingo_app_version}}

Leafveingo Version {{Leafveingo_version}}

Golang Version {{GoVersion}}

`

	Status301Msg = "Moved Permanently"
	Status307Msg = "Temporary Redirect"
	Status400Msg = "Bad Request"
	Status403Msg = "Forbidden The server understood the request"
	Status404Msg = "Page Not Found"
	Status500Msg = "Internal Server Error"
	Status503Msg = "Service Unavailable"
)

var (
	//	http status support code
	//	http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
	Status200 = HttpStatus(200)
	Status301 = HttpStatus(301)
	Status307 = HttpStatus(307)
	Status400 = HttpStatus(400)
	Status403 = HttpStatus(403)
	Status404 = HttpStatus(404)
	Status500 = HttpStatus(500)
	Status503 = HttpStatus(503)
)

//	http status code
type HttpStatus int16

//	数据的封装
type HttpStatusValue struct {
	status HttpStatus        // status code
	data   map[string]string //
}

//	new status value
func NewHttpStatusValue(status HttpStatus, msg, error, stack string) HttpStatusValue {

	data := make(map[string]string)
	data["msg"] = msg
	data["error"] = error
	data["stack"] = stack
	data["status"] = strconv.Itoa(int(status))

	return HttpStatusValue{status, data}
}

/**
 *	根据状态获取相应的字符串信息
 *
 *	@status
 *	@return
 */
func StatusMsg(status HttpStatus) string {
	msg := ""
	switch status {
	case Status200:
		msg = "ok"
	case Status301:
		msg = Status301Msg
	case Status307:
		msg = Status307Msg
	case Status400:
		msg = Status400Msg
	case Status403:
		msg = Status403Msg
	case Status404:
		msg = Status404Msg
	case Status500:
		msg = Status500Msg
	case Status503:
		msg = Status503Msg
	}
	return msg
}

/**
 *	status code convert string
 *
 *	@param status
 *	@return
 */
func StatusCodeToString(status HttpStatus) {
	msg := "-1"
	switch status {
	case Status200:
		msg = "200"
	case Status301:
		msg = "301"
	case Status307:
		msg = "307"
	case Status400:
		msg = "400"
	case Status403:
		msg = "403"
	case Status404:
		msg = "404"
	case Status500:
		msg = "500"
	case Status503:
		msg = "503"
	}
	return msg
}
<|endoftext|>


<commit_before>package fasthttp

import (
	"fmt"
	"strconv"
)

const (
	statusMessageMin = 100
	statusMessageMax = 511
)

// HTTP status codes were stolen from net/http.
const (
	StatusContinue           = 100 // RFC 7231, 6.2.1
	StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
	StatusProcessing         = 102 // RFC 2518, 10.1
	StatusEarlyHints         = 103 // RFC 8297

	StatusOK                   = 200 // RFC 7231, 6.3.1
	StatusCreated              = 201 // RFC 7231, 6.3.2
	StatusAccepted             = 202 // RFC 7231, 6.3.3
	StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
	StatusNoContent            = 204 // RFC 7231, 6.3.5
	StatusResetContent         = 205 // RFC 7231, 6.3.6
	StatusPartialContent       = 206 // RFC 7233, 4.1
	StatusMultiStatus          = 207 // RFC 4918, 11.1
	StatusAlreadyReported      = 208 // RFC 5842, 7.1
	StatusIMUsed               = 226 // RFC 3229, 10.4.1

	StatusMultipleChoices   = 300 // RFC 7231, 6.4.1
	StatusMovedPermanently  = 301 // RFC 7231, 6.4.2
	StatusFound             = 302 // RFC 7231, 6.4.3
	StatusSeeOther          = 303 // RFC 7231, 6.4.4
	StatusNotModified       = 304 // RFC 7232, 4.1
	StatusUseProxy          = 305 // RFC 7231, 6.4.5
	_                       = 306 // RFC 7231, 6.4.6 (Unused)
	StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
	StatusPermanentRedirect = 308 // RFC 7538, 3

	StatusBadRequest                   = 400 // RFC 7231, 6.5.1
	StatusUnauthorized                 = 401 // RFC 7235, 3.1
	StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
	StatusForbidden                    = 403 // RFC 7231, 6.5.3
	StatusNotFound                     = 404 // RFC 7231, 6.5.4
	StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
	StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
	StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
	StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
	StatusConflict                     = 409 // RFC 7231, 6.5.8
	StatusGone                         = 410 // RFC 7231, 6.5.9
	StatusLengthRequired               = 411 // RFC 7231, 6.5.10
	StatusPreconditionFailed           = 412 // RFC 7232, 4.2
	StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
	StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
	StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
	StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
	StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
	StatusTeapot                       = 418 // RFC 7168, 2.3.3
	StatusMisdirectedRequest           = 421 // RFC 7540, 9.1.2
	StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
	StatusLocked                       = 423 // RFC 4918, 11.3
	StatusFailedDependency             = 424 // RFC 4918, 11.4
	StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
	StatusPreconditionRequired         = 428 // RFC 6585, 3
	StatusTooManyRequests              = 429 // RFC 6585, 4
	StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
	StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3

	StatusInternalServerError           = 500 // RFC 7231, 6.6.1
	StatusNotImplemented                = 501 // RFC 7231, 6.6.2
	StatusBadGateway                    = 502 // RFC 7231, 6.6.3
	StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
	StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
	StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
	StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
	StatusInsufficientStorage           = 507 // RFC 4918, 11.5
	StatusLoopDetected                  = 508 // RFC 5842, 7.2
	StatusNotExtended                   = 510 // RFC 2774, 7
	StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)

var (
	statusLines = make([][]byte, statusMessageMax+1)

	statusMessages = []string{
		StatusContinue:           "Continue",
		StatusSwitchingProtocols: "Switching Protocols",
		StatusProcessing:         "Processing",
		StatusEarlyHints:         "Early Hints",

		StatusOK:                   "OK",
		StatusCreated:              "Created",
		StatusAccepted:             "Accepted",
		StatusNonAuthoritativeInfo: "Non-Authoritative Information",
		StatusNoContent:            "No Content",
		StatusResetContent:         "Reset Content",
		StatusPartialContent:       "Partial Content",
		StatusMultiStatus:          "Multi-Status",
		StatusAlreadyReported:      "Already Reported",
		StatusIMUsed:               "IM Used",

		StatusMultipleChoices:   "Multiple Choices",
		StatusMovedPermanently:  "Moved Permanently",
		StatusFound:             "Found",
		StatusSeeOther:          "See Other",
		StatusNotModified:       "Not Modified",
		StatusUseProxy:          "Use Proxy",
		StatusTemporaryRedirect: "Temporary Redirect",
		StatusPermanentRedirect: "Permanent Redirect",

		StatusBadRequest:                   "Bad Request",
		StatusUnauthorized:                 "Unauthorized",
		StatusPaymentRequired:              "Payment Required",
		StatusForbidden:                    "Forbidden",
		StatusNotFound:                     "Not Found",
		StatusMethodNotAllowed:             "Method Not Allowed",
		StatusNotAcceptable:                "Not Acceptable",
		StatusProxyAuthRequired:            "Proxy Authentication Required",
		StatusRequestTimeout:               "Request Timeout",
		StatusConflict:                     "Conflict",
		StatusGone:                         "Gone",
		StatusLengthRequired:               "Length Required",
		StatusPreconditionFailed:           "Precondition Failed",
		StatusRequestEntityTooLarge:        "Request Entity Too Large",
		StatusRequestURITooLong:            "Request URI Too Long",
		StatusUnsupportedMediaType:         "Unsupported Media Type",
		StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
		StatusExpectationFailed:            "Expectation Failed",
		StatusTeapot:                       "I'm a teapot",
		StatusMisdirectedRequest:           "Misdirected Request",
		StatusUnprocessableEntity:          "Unprocessable Entity",
		StatusLocked:                       "Locked",
		StatusFailedDependency:             "Failed Dependency",
		StatusUpgradeRequired:              "Upgrade Required",
		StatusPreconditionRequired:         "Precondition Required",
		StatusTooManyRequests:              "Too Many Requests",
		StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
		StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",

		StatusInternalServerError:           "Internal Server Error",
		StatusNotImplemented:                "Not Implemented",
		StatusBadGateway:                    "Bad Gateway",
		StatusServiceUnavailable:            "Service Unavailable",
		StatusGatewayTimeout:                "Gateway Timeout",
		StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
		StatusVariantAlsoNegotiates:         "Variant Also Negotiates",
		StatusInsufficientStorage:           "Insufficient Storage",
		StatusLoopDetected:                  "Loop Detected",
		StatusNotExtended:                   "Not Extended",
		StatusNetworkAuthenticationRequired: "Network Authentication Required",
	}
)

// StatusMessage returns HTTP status message for the given status code.
func StatusMessage(statusCode int) string {
	if statusCode < statusMessageMin || statusCode > statusMessageMax {
		return "Unknown Status Code"
	}

	s := statusMessages[statusCode]
	if s == "" {
		s = "Unknown Status Code"
	}
	return s
}

func init() {
	// Fill all valid status lines
	for i := 0; i < len(statusLines); i++ {
		statusLines[i] = []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", i, StatusMessage(i)))
	}
}

func statusLine(statusCode int) []byte {
	if statusCode < 0 || statusCode > statusMessageMax {
		return invalidStatusLine(statusCode)
	}

	return statusLines[statusCode]
}

func invalidStatusLine(statusCode int) []byte {
	statusText := StatusMessage(statusCode)
	// xxx placeholder of status code
	var line = make([]byte, 0, len("HTTP/1.1 xxx \r\n")+len(statusText))
	line = append(line, []byte("HTTP/1.1 ")...)
	line = strconv.AppendInt(line, int64(statusCode), 10)
	line = append(line, []byte(" ")...)
	line = append(line, []byte(statusText)...)
	line = append(line, []byte("\r\n")...)
	return line
}
<commit_msg>Update status.go (#1093)<commit_after>package fasthttp

import (
	"fmt"
	"strconv"
)

const (
	statusMessageMin = 100
	statusMessageMax = 511
)

// HTTP status codes were stolen from net/http.
const (
	StatusContinue           = 100 // RFC 7231, 6.2.1
	StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
	StatusProcessing         = 102 // RFC 2518, 10.1
	StatusEarlyHints         = 103 // RFC 8297

	StatusOK                   = 200 // RFC 7231, 6.3.1
	StatusCreated              = 201 // RFC 7231, 6.3.2
	StatusAccepted             = 202 // RFC 7231, 6.3.3
	StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
	StatusNoContent            = 204 // RFC 7231, 6.3.5
	StatusResetContent         = 205 // RFC 7231, 6.3.6
	StatusPartialContent       = 206 // RFC 7233, 4.1
	StatusMultiStatus          = 207 // RFC 4918, 11.1
	StatusAlreadyReported      = 208 // RFC 5842, 7.1
	StatusIMUsed               = 226 // RFC 3229, 10.4.1

	StatusMultipleChoices   = 300 // RFC 7231, 6.4.1
	StatusMovedPermanently  = 301 // RFC 7231, 6.4.2
	StatusFound             = 302 // RFC 7231, 6.4.3
	StatusSeeOther          = 303 // RFC 7231, 6.4.4
	StatusNotModified       = 304 // RFC 7232, 4.1
	StatusUseProxy          = 305 // RFC 7231, 6.4.5
	_                       = 306 // RFC 7231, 6.4.6 (Unused)
	StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
	StatusPermanentRedirect = 308 // RFC 7538, 3

	StatusBadRequest                   = 400 // RFC 7231, 6.5.1
	StatusUnauthorized                 = 401 // RFC 7235, 3.1
	StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
	StatusForbidden                    = 403 // RFC 7231, 6.5.3
	StatusNotFound                     = 404 // RFC 7231, 6.5.4
	StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
	StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
	StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
	StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
	StatusConflict                     = 409 // RFC 7231, 6.5.8
	StatusGone                         = 410 // RFC 7231, 6.5.9
	StatusLengthRequired               = 411 // RFC 7231, 6.5.10
	StatusPreconditionFailed           = 412 // RFC 7232, 4.2
	StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
	StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
	StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
	StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
	StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
	StatusTeapot                       = 418 // RFC 7168, 2.3.3
	StatusMisdirectedRequest           = 421 // RFC 7540, 9.1.2
	StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
	StatusLocked                       = 423 // RFC 4918, 11.3
	StatusFailedDependency             = 424 // RFC 4918, 11.4
	StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
	StatusPreconditionRequired         = 428 // RFC 6585, 3
	StatusTooManyRequests              = 429 // RFC 6585, 4
	StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
	StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3

	StatusInternalServerError           = 500 // RFC 7231, 6.6.1
	StatusNotImplemented                = 501 // RFC 7231, 6.6.2
	StatusBadGateway                    = 502 // RFC 7231, 6.6.3
	StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
	StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
	StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
	StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
	StatusInsufficientStorage           = 507 // RFC 4918, 11.5
	StatusLoopDetected                  = 508 // RFC 5842, 7.2
	StatusNotExtended                   = 510 // RFC 2774, 7
	StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)

var (
	statusLines = make([][]byte, statusMessageMax+1)

	statusMessages = []string{
		StatusContinue:           "Continue",
		StatusSwitchingProtocols: "Switching Protocols",
		StatusProcessing:         "Processing",
		StatusEarlyHints:         "Early Hints",

		StatusOK:                   "OK",
		StatusCreated:              "Created",
		StatusAccepted:             "Accepted",
		StatusNonAuthoritativeInfo: "Non-Authoritative Information",
		StatusNoContent:            "No Content",
		StatusResetContent:         "Reset Content",
		StatusPartialContent:       "Partial Content",
		StatusMultiStatus:          "Multi-Status",
		StatusAlreadyReported:      "Already Reported",
		StatusIMUsed:               "IM Used",

		StatusMultipleChoices:   "Multiple Choices",
		StatusMovedPermanently:  "Moved Permanently",
		StatusFound:             "Found",
		StatusSeeOther:          "See Other",
		StatusNotModified:       "Not Modified",
		StatusUseProxy:          "Use Proxy",
		StatusTemporaryRedirect: "Temporary Redirect",
		StatusPermanentRedirect: "Permanent Redirect",

		StatusBadRequest:                   "Bad Request",
		StatusUnauthorized:                 "Unauthorized",
		StatusPaymentRequired:              "Payment Required",
		StatusForbidden:                    "Forbidden",
		StatusNotFound:                     "Not Found",
		StatusMethodNotAllowed:             "Method Not Allowed",
		StatusNotAcceptable:                "Not Acceptable",
		StatusProxyAuthRequired:            "Proxy Authentication Required",
		StatusRequestTimeout:               "Request Timeout",
		StatusConflict:                     "Conflict",
		StatusGone:                         "Gone",
		StatusLengthRequired:               "Length Required",
		StatusPreconditionFailed:           "Precondition Failed",
		StatusRequestEntityTooLarge:        "Request Entity Too Large",
		StatusRequestURITooLong:            "Request URI Too Long",
		StatusUnsupportedMediaType:         "Unsupported Media Type",
		StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
		StatusExpectationFailed:            "Expectation Failed",
		StatusTeapot:                       "I'm a teapot",
		StatusMisdirectedRequest:           "Misdirected Request",
		StatusUnprocessableEntity:          "Unprocessable Entity",
		StatusLocked:                       "Locked",
		StatusFailedDependency:             "Failed Dependency",
		StatusUpgradeRequired:              "Upgrade Required",
		StatusPreconditionRequired:         "Precondition Required",
		StatusTooManyRequests:              "Too Many Requests",
		StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
		StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",

		StatusInternalServerError:           "Internal Server Error",
		StatusNotImplemented:                "Not Implemented",
		StatusBadGateway:                    "Bad Gateway",
		StatusServiceUnavailable:            "Service Unavailable",
		StatusGatewayTimeout:                "Gateway Timeout",
		StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
		StatusVariantAlsoNegotiates:         "Variant Also Negotiates",
		StatusInsufficientStorage:           "Insufficient Storage",
		StatusLoopDetected:                  "Loop Detected",
		StatusNotExtended:                   "Not Extended",
		StatusNetworkAuthenticationRequired: "Network Authentication Required",
	}
)

// StatusMessage returns HTTP status message for the given status code.
func StatusMessage(statusCode int) string {
	if statusCode < statusMessageMin || statusCode > statusMessageMax {
		return "Unknown Status Code"
	}

	s := statusMessages[statusCode]
	if s == "" {
		s = "Unknown Status Code"
	}
	return s
}

func init() {
	// Fill all valid status lines
	for i := 0; i < len(statusLines); i++ {
		statusLines[i] = []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", i, StatusMessage(i)))
	}
}

func statusLine(statusCode int) []byte {
	if statusCode < 0 || statusCode > statusMessageMax {
		return invalidStatusLine(statusCode)
	}

	return statusLines[statusCode]
}

func invalidStatusLine(statusCode int) []byte {
	statusText := StatusMessage(statusCode)
	// xxx placeholder of status code
	var line = make([]byte, 0, len("HTTP/1.1 xxx \r\n")+len(statusText))
	line = append(line, "HTTP/1.1 "...)
	line = strconv.AppendInt(line, int64(statusCode), 10)
	line = append(line, ' ')
	line = append(line, statusText...)
	line = append(line, "\r\n"...)
	return line
}
<|endoftext|>