<commit_before>package test_test

import (
	"io"
	"os/exec"

	. "k8s.io/kubectl/pkg/framework/test"

	"fmt"

	"time"

	"net/url"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"k8s.io/kubectl/pkg/framework/test/testfakes"
)

var _ = Describe("Apiserver", func() {
	var (
		fakeSession      *testfakes.FakeSimpleSession
		apiServer        *APIServer
		fakeEtcdProcess  *testfakes.FakeControlPlaneProcess
		apiServerStopper chan struct{}
		cleanupCallCount int
	)

	BeforeEach(func() {
		fakeSession = &testfakes.FakeSimpleSession{}
		fakeEtcdProcess = &testfakes.FakeControlPlaneProcess{}

		apiServerStopper = make(chan struct{}, 1)
		fakeSession.TerminateReturns(&gexec.Session{
			Exited: apiServerStopper,
		})
		close(apiServerStopper)

		apiServer = &APIServer{
			Address: &url.URL{Scheme: "http", Host: "the.host.for.api.server:5678"},
			Path:    "/some/path/to/apiserver",
			CertDir: &Directory{
				Path: "/some/path/to/certdir",
				Cleanup: func() error {
					cleanupCallCount += 1
					return nil
				},
			},
			Etcd:        fakeEtcdProcess,
			StopTimeout: 500 * time.Millisecond,
		}
	})

	Describe("starting and stopping the server", func() {
		Context("when given a path to a binary that runs for a long time", func() {
			It("can start and stop that binary", func() {
				sessionBuffer := gbytes.NewBuffer()
				fmt.Fprint(sessionBuffer, "Everything is fine")
				fakeSession.BufferReturns(sessionBuffer)

				fakeSession.ExitCodeReturnsOnCall(0, -1)
				fakeSession.ExitCodeReturnsOnCall(1, 143)

				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.the.API.server:1234"}
				fakeEtcdProcess.URLReturns("the etcd url", nil)

				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					Expect(command.Args).To(ContainElement("--insecure-port=1234"))
					Expect(command.Args).To(ContainElement("--insecure-bind-address=this.is.the.API.server"))
					Expect(command.Args).To(ContainElement("--etcd-servers=the etcd url"))
					Expect(command.Args).To(ContainElement("--cert-dir=/some/path/to/certdir"))
					Expect(command.Path).To(Equal("/some/path/to/apiserver"))
					fmt.Fprint(err, "Serving insecurely on this.is.the.API.server:1234")
					return fakeSession, nil
				}

				By("Starting the API Server")
				err := apiServer.Start()
				Expect(err).NotTo(HaveOccurred())

				By("...in turn starting Etcd")
				Expect(fakeEtcdProcess.StartCallCount()).To(Equal(1),
					"the Etcd process should be started exactly once")

				By("...getting the URL of Etcd")
				Expect(fakeEtcdProcess.URLCallCount()).To(Equal(1))

				Eventually(apiServer).Should(gbytes.Say("Everything is fine"))
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
				Expect(apiServer).NotTo(gexec.Exit())
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(1))

				By("Stopping the API Server")
				Expect(apiServer.Stop()).To(Succeed())

				Expect(cleanupCallCount).To(Equal(1))
				Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
				Expect(apiServer).To(gexec.Exit(143))
				Expect(fakeSession.TerminateCallCount()).To(Equal(1))
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(2))
			})
		})

		Context("when the certificate directory cannot be destroyed", func() {
			It("propagates the error", func() {
				apiServer.CertDir.Cleanup = func() error { return fmt.Errorf("destroy failed") }
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())
				err := apiServer.Stop()
				Expect(err).To(MatchError(ContainSubstring("destroy failed")))
			})
		})

		Context("when there is on function to cleanup the certificate directory", func() {
			It("does not panic", func() {
				apiServer.CertDir.Cleanup = nil
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())

				var err error
				Expect(func() {
					err = apiServer.Stop()
				}).NotTo(Panic())
				Expect(err).NotTo(HaveOccurred())
			})
		})

		Context("when etcd cannot be stopped", func() {
			It("propagates the error", func() {
				fakeEtcdProcess.StopReturns(fmt.Errorf("stopping etcd failed"))
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())
				err := apiServer.Stop()
				Expect(err).To(MatchError(ContainSubstring("stopping etcd failed")))
			})
		})

		Context("when starting etcd fails", func() {
			It("propagates the error, and does not start the process", func() {
				fakeEtcdProcess.StartReturnsOnCall(0, fmt.Errorf("starting etcd failed"))
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					Expect(true).To(BeFalse(),
						"the api server process starter shouldn't be called if starting etcd fails")
					return nil, nil
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("starting etcd failed")))
			})
		})

		Context("when getting the URL of Etcd fails", func() {
			It("propagates the error, stop Etcd and keep APIServer down", func() {
				fakeEtcdProcess.URLReturns("", fmt.Errorf("no etcd url"))

				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					Expect(true).To(BeFalse(),
						"the api server process starter shouldn't be called if getting etcd's URL fails")
					return nil, nil
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("no etcd url")))
				Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
			})

			Context("and stopping of etcd fails too", func() {
				It("propagates the combined error", func() {
					fakeEtcdProcess.URLReturns("", fmt.Errorf("no etcd url"))
					fakeEtcdProcess.StopReturns(fmt.Errorf("stopping etcd failed"))

					apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
						Expect(true).To(BeFalse(),
							"the api server process starter shouldn't be called if getting etcd's URL fails")
						return nil, nil
					}

					err := apiServer.Start()
					Expect(err).To(MatchError(ContainSubstring("no etcd url")))
					Expect(err).To(MatchError(ContainSubstring("stopping etcd failed")))
					Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
				})
			})
		})

		Context("when the starter returns an error", func() {
			It("propagates the error", func() {
				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					return nil, fmt.Errorf("Some error in the apiserver starter.")
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("Some error in the apiserver starter.")))
			})
		})

		Context("when the starter takes longer than our timeout", func() {
			It("gives us a timeout error", func() {
				apiServer.StartTimeout = 1 * time.Nanosecond
				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					return &gexec.Session{}, nil
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("timeout waiting for apiserver to start serving")))
			})
		})

		Context("when we try to stop a server that hasn't been started", func() {
			It("is a noop and does not call exit on the session", func() {
				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					return fakeSession, nil
				}
				apiServer.Stop()
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
			})
		})

		Context("when Stop() times out", func() {
			JustBeforeEach(func() {
				apiServerStopperWillNeverBeUsed := make(chan struct{}, 1)
				fakeSession.TerminateReturns(&gexec.Session{
					Exited: apiServerStopperWillNeverBeUsed,
				})
			})
			It("propagates the error", func() {
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())
				err := apiServer.Stop()
				Expect(err).To(MatchError(ContainSubstring("timeout")))
			})
		})
	})

	Describe("querying the server for its URL", func() {
		It("can be queried for the URL it listens on", func() {
			apiServerURL, err := apiServer.URL()
			Expect(err).NotTo(HaveOccurred())
			Expect(apiServerURL).To(Equal("http://the.host.for.api.server:5678"))
		})

		Context("before starting the server", func() {
			Context("and therefore the address has not been initialized", func() {
				BeforeEach(func() {
					apiServer = &APIServer{}
				})
				It("gives a sane error", func() {
					_, err := apiServer.URL()
					Expect(err).To(MatchError(ContainSubstring("not initialized")))
				})
			})
		})
	})
})
<commit_msg>Make go fmt happy<commit_after>package test_test

import (
	"io"
	"os/exec"

	. "k8s.io/kubectl/pkg/framework/test"

	"fmt"

	"time"

	"net/url"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"k8s.io/kubectl/pkg/framework/test/testfakes"
)

var _ = Describe("Apiserver", func() {
	var (
		fakeSession      *testfakes.FakeSimpleSession
		apiServer        *APIServer
		fakeEtcdProcess  *testfakes.FakeControlPlaneProcess
		apiServerStopper chan struct{}
		cleanupCallCount int
	)

	BeforeEach(func() {
		fakeSession = &testfakes.FakeSimpleSession{}
		fakeEtcdProcess = &testfakes.FakeControlPlaneProcess{}

		apiServerStopper = make(chan struct{}, 1)
		fakeSession.TerminateReturns(&gexec.Session{
			Exited: apiServerStopper,
		})
		close(apiServerStopper)

		apiServer = &APIServer{
			Address: &url.URL{Scheme: "http", Host: "the.host.for.api.server:5678"},
			Path:    "/some/path/to/apiserver",
			CertDir: &Directory{
				Path: "/some/path/to/certdir",
				Cleanup: func() error {
					cleanupCallCount += 1
					return nil
				},
			},
			Etcd:        fakeEtcdProcess,
			StopTimeout: 500 * time.Millisecond,
		}
	})

	Describe("starting and stopping the server", func() {
		Context("when given a path to a binary that runs for a long time", func() {
			It("can start and stop that binary", func() {
				sessionBuffer := gbytes.NewBuffer()
				fmt.Fprint(sessionBuffer, "Everything is fine")
				fakeSession.BufferReturns(sessionBuffer)

				fakeSession.ExitCodeReturnsOnCall(0, -1)
				fakeSession.ExitCodeReturnsOnCall(1, 143)

				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.the.API.server:1234"}
				fakeEtcdProcess.URLReturns("the etcd url", nil)

				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					Expect(command.Args).To(ContainElement("--insecure-port=1234"))
					Expect(command.Args).To(ContainElement("--insecure-bind-address=this.is.the.API.server"))
					Expect(command.Args).To(ContainElement("--etcd-servers=the etcd url"))
					Expect(command.Args).To(ContainElement("--cert-dir=/some/path/to/certdir"))
					Expect(command.Path).To(Equal("/some/path/to/apiserver"))
					fmt.Fprint(err, "Serving insecurely on this.is.the.API.server:1234")
					return fakeSession, nil
				}

				By("Starting the API Server")
				err := apiServer.Start()
				Expect(err).NotTo(HaveOccurred())

				By("...in turn starting Etcd")
				Expect(fakeEtcdProcess.StartCallCount()).To(Equal(1),
					"the Etcd process should be started exactly once")

				By("...getting the URL of Etcd")
				Expect(fakeEtcdProcess.URLCallCount()).To(Equal(1))

				Eventually(apiServer).Should(gbytes.Say("Everything is fine"))
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
				Expect(apiServer).NotTo(gexec.Exit())
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(1))

				By("Stopping the API Server")
				Expect(apiServer.Stop()).To(Succeed())

				Expect(cleanupCallCount).To(Equal(1))
				Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
				Expect(apiServer).To(gexec.Exit(143))
				Expect(fakeSession.TerminateCallCount()).To(Equal(1))
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(2))
			})
		})

		Context("when the certificate directory cannot be destroyed", func() {
			It("propagates the error", func() {
				apiServer.CertDir.Cleanup = func() error { return fmt.Errorf("destroy failed") }
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())
				err := apiServer.Stop()
				Expect(err).To(MatchError(ContainSubstring("destroy failed")))
			})
		})

		Context("when there is on function to cleanup the certificate directory", func() {
			It("does not panic", func() {
				apiServer.CertDir.Cleanup = nil
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())

				var err error
				Expect(func() {
					err = apiServer.Stop()
				}).NotTo(Panic())
				Expect(err).NotTo(HaveOccurred())
			})
		})

		Context("when etcd cannot be stopped", func() {
			It("propagates the error", func() {
				fakeEtcdProcess.StopReturns(fmt.Errorf("stopping etcd failed"))
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())
				err := apiServer.Stop()
				Expect(err).To(MatchError(ContainSubstring("stopping etcd failed")))
			})
		})

		Context("when starting etcd fails", func() {
			It("propagates the error, and does not start the process", func() {
				fakeEtcdProcess.StartReturnsOnCall(0, fmt.Errorf("starting etcd failed"))
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					Expect(true).To(BeFalse(),
						"the api server process starter shouldn't be called if starting etcd fails")
					return nil, nil
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("starting etcd failed")))
			})
		})

		Context("when getting the URL of Etcd fails", func() {
			It("propagates the error, stop Etcd and keep APIServer down", func() {
				fakeEtcdProcess.URLReturns("", fmt.Errorf("no etcd url"))

				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					Expect(true).To(BeFalse(),
						"the api server process starter shouldn't be called if getting etcd's URL fails")
					return nil, nil
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("no etcd url")))
				Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
			})

			Context("and stopping of etcd fails too", func() {
				It("propagates the combined error", func() {
					fakeEtcdProcess.URLReturns("", fmt.Errorf("no etcd url"))
					fakeEtcdProcess.StopReturns(fmt.Errorf("stopping etcd failed"))

					apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
						Expect(true).To(BeFalse(),
							"the api server process starter shouldn't be called if getting etcd's URL fails")
						return nil, nil
					}

					err := apiServer.Start()
					Expect(err).To(MatchError(ContainSubstring("no etcd url")))
					Expect(err).To(MatchError(ContainSubstring("stopping etcd failed")))
					Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
				})
			})
		})

		Context("when the starter returns an error", func() {
			It("propagates the error", func() {
				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					return nil, fmt.Errorf("Some error in the apiserver starter.")
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("Some error in the apiserver starter.")))
			})
		})

		Context("when the starter takes longer than our timeout", func() {
			It("gives us a timeout error", func() {
				apiServer.StartTimeout = 1 * time.Nanosecond
				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					return &gexec.Session{}, nil
				}

				err := apiServer.Start()
				Expect(err).To(MatchError(ContainSubstring("timeout waiting for apiserver to start serving")))
			})
		})

		Context("when we try to stop a server that hasn't been started", func() {
			It("is a noop and does not call exit on the session", func() {
				apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					return fakeSession, nil
				}
				apiServer.Stop()
				Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
			})
		})

		Context("when Stop() times out", func() {
			JustBeforeEach(func() {
				apiServerStopperWillNeverBeUsed := make(chan struct{}, 1)
				fakeSession.TerminateReturns(&gexec.Session{
					Exited: apiServerStopperWillNeverBeUsed,
				})
			})
			It("propagates the error", func() {
				apiServer.Address = &url.URL{Scheme: "http", Host: "this.is.apiserver:1234"}
				apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
					fmt.Fprint(err, "Serving insecurely on this.is.apiserver:1234")
					return fakeSession, nil
				}

				Expect(apiServer.Start()).To(Succeed())
				err := apiServer.Stop()
				Expect(err).To(MatchError(ContainSubstring("timeout")))
			})
		})
	})

	Describe("querying the server for its URL", func() {
		It("can be queried for the URL it listens on", func() {
			apiServerURL, err := apiServer.URL()
			Expect(err).NotTo(HaveOccurred())
			Expect(apiServerURL).To(Equal("http://the.host.for.api.server:5678"))
		})

		Context("before starting the server", func() {
			Context("and therefore the address has not been initialized", func() {
				BeforeEach(func() {
					apiServer = &APIServer{}
				})
				It("gives a sane error", func() {
					_, err := apiServer.URL()
					Expect(err).To(MatchError(ContainSubstring("not initialized")))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package build

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"sync"
)

type Command byte

func (Command) Help() string {
	return strings.TrimSpace(helpText)
}

func (c Command) Run(env packer.Environment, args []string) int {
	var cfgDebug bool
	var cfgExcept []string
	var cfgOnly []string

	cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError)
	cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
	cmdFlags.BoolVar(&cfgDebug, "debug", false, "debug mode for builds")
	cmdFlags.Var((*stringSliceValue)(&cfgExcept), "except", "build all builds except these")
	cmdFlags.Var((*stringSliceValue)(&cfgOnly), "only", "only build the given builds by name")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) != 1 {
		cmdFlags.Usage()
		return 1
	}

	if len(cfgOnly) > 0 && len(cfgExcept) > 0 {
		env.Ui().Error("Only one of '-except' or '-only' may be specified.\n")
		env.Ui().Error(c.Help())
		return 1
	}

	// Read the file into a byte array so that we can parse the template
	log.Printf("Reading template: %s", args[0])
	tplData, err := ioutil.ReadFile(args[0])
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to read template file: %s", err))
		return 1
	}

	// Parse the template into a machine-usable format
	log.Println("Parsing template...")
	tpl, err := packer.ParseTemplate(tplData)
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
		return 1
	}

	// The component finder for our builds
	components := &packer.ComponentFinder{
		Builder:       env.Builder,
		Hook:          env.Hook,
		PostProcessor: env.PostProcessor,
		Provisioner:   env.Provisioner,
	}

	// Go through each builder and compile the builds that we care about
	buildNames := tpl.BuildNames()
	builds := make([]packer.Build, 0, len(buildNames))
	for _, buildName := range buildNames {
		if len(cfgExcept) > 0 {
			found := false
			for _, only := range cfgExcept {
				if buildName == only {
					found = true
					break
				}
			}

			if found {
				log.Printf("Skipping build '%s' because specified by -except.", buildName)
				continue
			}
		}

		if len(cfgOnly) > 0 {
			found := false
			for _, only := range cfgOnly {
				if buildName == only {
					found = true
					break
				}
			}

			if !found {
				log.Printf("Skipping build '%s' because not specified by -only.", buildName)
				continue
			}
		}

		log.Printf("Creating build: %s", buildName)
		build, err := tpl.Build(buildName, components)
		if err != nil {
			env.Ui().Error(fmt.Sprintf("Failed to create build '%s': \n\n%s", buildName, err))
			return 1
		}

		builds = append(builds, build)
	}

	if cfgDebug {
		env.Ui().Say("Debug mode enabled. Builds will not be parallelized.")
	}

	// Compile all the UIs for the builds
	colors := [5]packer.UiColor{
		packer.UiColorGreen,
		packer.UiColorCyan,
		packer.UiColorMagenta,
		packer.UiColorYellow,
		packer.UiColorBlue,
	}

	buildUis := make(map[string]packer.Ui)
	for i, b := range builds {
		var ui packer.Ui

		ui = &packer.ColoredUi{
			Color: colors[i%len(colors)],
			Ui:    env.Ui(),
		}

		ui = &packer.PrefixedUi{
			fmt.Sprintf("==> %s", b.Name()),
			fmt.Sprintf("    %s", b.Name()),
			ui,
		}

		buildUis[b.Name()] = ui
		ui.Say(fmt.Sprintf("%s output will be in this color.", b.Name()))
	}

	// Add a newline between the color output and the actual output
	env.Ui().Say("")

	log.Printf("Build debug mode: %v", cfgDebug)

	// Set the debug mode and prepare all the builds
	for _, b := range builds {
		log.Printf("Preparing build: %s", b.Name())
		b.SetDebug(cfgDebug)
		err := b.Prepare()
		if err != nil {
			env.Ui().Error(err.Error())
			return 1
		}
	}

	// Run all the builds in parallel and wait for them to complete
	var interruptWg, wg sync.WaitGroup
	interrupted := false
	artifacts := make(map[string][]packer.Artifact)
	errors := make(map[string]error)
	for _, b := range builds {
		// Increment the waitgroup so we wait for this item to finish properly
		wg.Add(1)

		// Handle interrupts for this build
		sigCh := make(chan os.Signal, 1)
		signal.Notify(sigCh, os.Interrupt)
		defer signal.Stop(sigCh)
		go func(b packer.Build) {
			<-sigCh
			interruptWg.Add(1)
			defer interruptWg.Done()
			interrupted = true

			log.Printf("Stopping build: %s", b.Name())
			b.Cancel()
			log.Printf("Build cancelled: %s", b.Name())
		}(b)

		// Run the build in a goroutine
		go func(b packer.Build) {
			defer wg.Done()

			name := b.Name()
			log.Printf("Starting build run: %s", name)
			ui := buildUis[name]
			runArtifacts, err := b.Run(ui, env.Cache())

			if err != nil {
				ui.Error(fmt.Sprintf("Build errored: %s", err))
				errors[name] = err
			} else {
				ui.Say("Build finished.")
				artifacts[name] = runArtifacts
			}
		}(b)

		if cfgDebug {
			log.Printf("Debug enabled, so waiting for build to finish: %s", b.Name())
			wg.Wait()
		}

		if interrupted {
			log.Println("Interrupted, not going to start any more builds.")
			break
		}
	}

	// Wait for both the builds to complete and the interrupt handler,
	// if it is interrupted.
	log.Printf("Waiting on builds to complete...")
	wg.Wait()

	log.Printf("Builds completed. Waiting on interrupt barrier...")
	interruptWg.Wait()

	if interrupted {
		env.Ui().Say("Cleanly cancelled builds after being interrupted.")
		return 1
	}

	if len(errors) > 0 {
		env.Ui().Error("\n==> Some builds didn't complete successfully and had errors:")
		for name, err := range errors {
			env.Ui().Error(fmt.Sprintf("--> %s: %s", name, err))
		}
	}

	if len(artifacts) > 0 {
		env.Ui().Say("\n==> Builds finished. The artifacts of successful builds are:")
		for name, buildArtifacts := range artifacts {
			for _, artifact := range buildArtifacts {
				var message bytes.Buffer
				fmt.Fprintf(&message, "--> %s: ", name)

				if artifact != nil {
					fmt.Fprintf(&message, artifact.String())
				} else {
					fmt.Print("<nothing>")
				}

				env.Ui().Say(message.String())
			}
		}
	} else {
		env.Ui().Say("\n==> Builds finished but no artifacts were created.")
	}

	return 0
}

func (Command) Synopsis() string {
	return "build image(s) from template"
}
<commit_msg>command/build: output <nothing> properly if no artifact<commit_after>package build

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"sync"
)

type Command byte

func (Command) Help() string {
	return strings.TrimSpace(helpText)
}

func (c Command) Run(env packer.Environment, args []string) int {
	var cfgDebug bool
	var cfgExcept []string
	var cfgOnly []string

	cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError)
	cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
	cmdFlags.BoolVar(&cfgDebug, "debug", false, "debug mode for builds")
	cmdFlags.Var((*stringSliceValue)(&cfgExcept), "except", "build all builds except these")
	cmdFlags.Var((*stringSliceValue)(&cfgOnly), "only", "only build the given builds by name")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) != 1 {
		cmdFlags.Usage()
		return 1
	}

	if len(cfgOnly) > 0 && len(cfgExcept) > 0 {
		env.Ui().Error("Only one of '-except' or '-only' may be specified.\n")
		env.Ui().Error(c.Help())
		return 1
	}

	// Read the file into a byte array so that we can parse the template
	log.Printf("Reading template: %s", args[0])
	tplData, err := ioutil.ReadFile(args[0])
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to read template file: %s", err))
		return 1
	}

	// Parse the template into a machine-usable format
	log.Println("Parsing template...")
	tpl, err := packer.ParseTemplate(tplData)
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
		return 1
	}

	// The component finder for our builds
	components := &packer.ComponentFinder{
		Builder:       env.Builder,
		Hook:          env.Hook,
		PostProcessor: env.PostProcessor,
		Provisioner:   env.Provisioner,
	}

	// Go through each builder and compile the builds that we care about
	buildNames := tpl.BuildNames()
	builds := make([]packer.Build, 0, len(buildNames))
	for _, buildName := range buildNames {
		if len(cfgExcept) > 0 {
			found := false
			for _, only := range cfgExcept {
				if buildName == only {
					found = true
					break
				}
			}

			if found {
				log.Printf("Skipping build '%s' because specified by -except.", buildName)
				continue
			}
		}

		if len(cfgOnly) > 0 {
			found := false
			for _, only := range cfgOnly {
				if buildName == only {
					found = true
					break
				}
			}

			if !found {
				log.Printf("Skipping build '%s' because not specified by -only.", buildName)
				continue
			}
		}

		log.Printf("Creating build: %s", buildName)
		build, err := tpl.Build(buildName, components)
		if err != nil {
			env.Ui().Error(fmt.Sprintf("Failed to create build '%s': \n\n%s", buildName, err))
			return 1
		}

		builds = append(builds, build)
	}

	if cfgDebug {
		env.Ui().Say("Debug mode enabled. Builds will not be parallelized.")
	}

	// Compile all the UIs for the builds
	colors := [5]packer.UiColor{
		packer.UiColorGreen,
		packer.UiColorCyan,
		packer.UiColorMagenta,
		packer.UiColorYellow,
		packer.UiColorBlue,
	}

	buildUis := make(map[string]packer.Ui)
	for i, b := range builds {
		var ui packer.Ui

		ui = &packer.ColoredUi{
			Color: colors[i%len(colors)],
			Ui:    env.Ui(),
		}

		ui = &packer.PrefixedUi{
			fmt.Sprintf("==> %s", b.Name()),
			fmt.Sprintf("    %s", b.Name()),
			ui,
		}

		buildUis[b.Name()] = ui
		ui.Say(fmt.Sprintf("%s output will be in this color.", b.Name()))
	}

	// Add a newline between the color output and the actual output
	env.Ui().Say("")

	log.Printf("Build debug mode: %v", cfgDebug)

	// Set the debug mode and prepare all the builds
	for _, b := range builds {
		log.Printf("Preparing build: %s", b.Name())
		b.SetDebug(cfgDebug)
		err := b.Prepare()
		if err != nil {
			env.Ui().Error(err.Error())
			return 1
		}
	}

	// Run all the builds in parallel and wait for them to complete
	var interruptWg, wg sync.WaitGroup
	interrupted := false
	artifacts := make(map[string][]packer.Artifact)
	errors := make(map[string]error)
	for _, b := range builds {
		// Increment the waitgroup so we wait for this item to finish properly
		wg.Add(1)

		// Handle interrupts for this build
		sigCh := make(chan os.Signal, 1)
		signal.Notify(sigCh, os.Interrupt)
		defer signal.Stop(sigCh)
		go func(b packer.Build) {
			<-sigCh
			interruptWg.Add(1)
			defer interruptWg.Done()
			interrupted = true

			log.Printf("Stopping build: %s", b.Name())
			b.Cancel()
			log.Printf("Build cancelled: %s", b.Name())
		}(b)

		// Run the build in a goroutine
		go func(b packer.Build) {
			defer wg.Done()

			name := b.Name()
			log.Printf("Starting build run: %s", name)
			ui := buildUis[name]
			runArtifacts, err := b.Run(ui, env.Cache())

			if err != nil {
				ui.Error(fmt.Sprintf("Build errored: %s", err))
				errors[name] = err
			} else {
				ui.Say("Build finished.")
				artifacts[name] = runArtifacts
			}
		}(b)

		if cfgDebug {
			log.Printf("Debug enabled, so waiting for build to finish: %s", b.Name())
			wg.Wait()
		}

		if interrupted {
			log.Println("Interrupted, not going to start any more builds.")
			break
		}
	}

	// Wait for both the builds to complete and the interrupt handler,
	// if it is interrupted.
	log.Printf("Waiting on builds to complete...")
	wg.Wait()

	log.Printf("Builds completed. Waiting on interrupt barrier...")
	interruptWg.Wait()

	if interrupted {
		env.Ui().Say("Cleanly cancelled builds after being interrupted.")
		return 1
	}

	if len(errors) > 0 {
		env.Ui().Error("\n==> Some builds didn't complete successfully and had errors:")
		for name, err := range errors {
			env.Ui().Error(fmt.Sprintf("--> %s: %s", name, err))
		}
	}

	if len(artifacts) > 0 {
		env.Ui().Say("\n==> Builds finished. The artifacts of successful builds are:")
		for name, buildArtifacts := range artifacts {
			for _, artifact := range buildArtifacts {
				var message bytes.Buffer
				fmt.Fprintf(&message, "--> %s: ", name)

				if artifact != nil {
					fmt.Fprintf(&message, artifact.String())
				} else {
					fmt.Fprint(&message, "<nothing>")
				}

				env.Ui().Say(message.String())
			}
		}
	} else {
		env.Ui().Say("\n==> Builds finished but no artifacts were created.")
	}

	return 0
}

func (Command) Synopsis() string {
	return "build image(s) from template"
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Rook Authors. All rights reserved.

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

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

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

// Package config provides default configurations which Rook will set in Ceph clusters.
package config

import (
	"github.com/rook/rook/pkg/operator/ceph/version"
)

// DefaultFlags returns the default configuration flags Rook will set on the command line for all
// calls to Ceph daemons and tools. Values specified here will not be able to be overridden using
// the mon's central KV store, and that is (and should be) by intent.
func DefaultFlags(fsid, mountedKeyringPath string) []string {
	flags := []string{
		// fsid unnecessary but is a safety to make sure daemons can only connect to their cluster
		NewFlag("fsid", fsid),
		NewFlag("keyring", mountedKeyringPath),
	}

	flags = append(flags, LoggingFlags()...)
	flags = append(flags, StoredMonHostEnvVarFlags()...)

	return flags
}

// makes it possible to be slightly less verbose to create a ConfigOverride here
func configOverride(who, option, value string) Option {
	return Option{Who: who, Option: option, Value: value}
}

func LoggingFlags() []string {
	return []string{
		// For containers, we're expected to log everything to stderr
		NewFlag("log-to-stderr", "true"),
		NewFlag("err-to-stderr", "true"),
		NewFlag("mon-cluster-log-to-stderr", "true"),
		// differentiate debug text from audit text, and the space after 'debug' is critical
		NewFlag("log-stderr-prefix", "debug "),
		NewFlag("default-log-to-file", "false"),
		NewFlag("default-mon-cluster-log-to-file", "false"),
	}
}

// DefaultCentralizedConfigs returns the default configuration options Rook will set in Ceph's
// centralized config store.
func DefaultCentralizedConfigs(cephVersion version.CephVersion) []Option {
	overrides := []Option{
		configOverride("global", "mon allow pool delete", "true"),
		configOverride("global", "mon cluster log file", ""),
	}

	// We disable "bluestore warn on legacy statfs"
	// This setting appeared on 14.2.2, so if detected we disable the warning
	// As of 14.2.5 (https://github.com/rook/rook/issues/3539#issuecomment-531287051), Ceph will disable this flag by default so there is no need to apply it
	if cephVersion.IsAtLeast(version.CephVersion{Major: 14, Minor: 2, Extra: 2}) && version.IsInferior(cephVersion, version.CephVersion{Major: 14, Minor: 2, Extra: 5}) {
		overrides = append(overrides, []Option{
			configOverride("global", "bluestore warn on legacy statfs", "false"),
		}...)
	}

	// For Pacific
	if cephVersion.IsAtLeastPacific() {
		overrides = append(overrides, []Option{
			configOverride("global", "mon allow pool size one", "true"),
		}...)
	}

	return overrides
}

// DefaultLegacyConfigs need to be added to the Ceph config file until the integration tests can be
// made to override these options for the Ceph clusters it creates.
func DefaultLegacyConfigs() []Option {
	overrides := []Option{
		// TODO: drop this when FlexVolume is no longer supported
		configOverride("global", "rbd_default_features", "3"),
	}
	return overrides
}
<commit_msg>ceph: enable pg auto repair<commit_after>/*
Copyright 2019 The Rook Authors. All rights reserved.

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

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

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

// Package config provides default configurations which Rook will set in Ceph clusters.
package config

import (
	"github.com/rook/rook/pkg/operator/ceph/version"
)

// DefaultFlags returns the default configuration flags Rook will set on the command line for all
// calls to Ceph daemons and tools. Values specified here will not be able to be overridden using
// the mon's central KV store, and that is (and should be) by intent.
func DefaultFlags(fsid, mountedKeyringPath string) []string {
	flags := []string{
		// fsid unnecessary but is a safety to make sure daemons can only connect to their cluster
		NewFlag("fsid", fsid),
		NewFlag("keyring", mountedKeyringPath),
	}

	flags = append(flags, LoggingFlags()...)
	flags = append(flags, StoredMonHostEnvVarFlags()...)

	return flags
}

// makes it possible to be slightly less verbose to create a ConfigOverride here
func configOverride(who, option, value string) Option {
	return Option{Who: who, Option: option, Value: value}
}

func LoggingFlags() []string {
	return []string{
		// For containers, we're expected to log everything to stderr
		NewFlag("log-to-stderr", "true"),
		NewFlag("err-to-stderr", "true"),
		NewFlag("mon-cluster-log-to-stderr", "true"),
		// differentiate debug text from audit text, and the space after 'debug' is critical
		NewFlag("log-stderr-prefix", "debug "),
		NewFlag("default-log-to-file", "false"),
		NewFlag("default-mon-cluster-log-to-file", "false"),
	}
}

// DefaultCentralizedConfigs returns the default configuration options Rook will set in Ceph's
// centralized config store.
func DefaultCentralizedConfigs(cephVersion version.CephVersion) []Option {
	overrides := []Option{
		configOverride("global", "mon allow pool delete", "true"),
		configOverride("global", "mon cluster log file", ""),
	}

	// We disable "bluestore warn on legacy statfs"
	// This setting appeared on 14.2.2, so if detected we disable the warning
	// As of 14.2.5 (https://github.com/rook/rook/issues/3539#issuecomment-531287051), Ceph will disable this flag by default so there is no need to apply it
	if cephVersion.IsAtLeast(version.CephVersion{Major: 14, Minor: 2, Extra: 2}) && version.IsInferior(cephVersion, version.CephVersion{Major: 14, Minor: 2, Extra: 5}) {
		overrides = append(overrides, []Option{
			configOverride("global", "bluestore warn on legacy statfs", "false"),
		}...)
	}

	// For Pacific
	if cephVersion.IsAtLeastPacific() {
		overrides = append(overrides, []Option{
			configOverride("global", "mon allow pool size one", "true"),
		}...)
	}

	// Every release before Quincy will enable PG auto repair on Bluestore OSDs
	if !cephVersion.IsAtLeastQuincy() {
		overrides = append(overrides, []Option{
			configOverride("global", "osd scrub auto repair", "true"),
		}...)
	}

	return overrides
}

// DefaultLegacyConfigs need to be added to the Ceph config file until the integration tests can be
// made to override these options for the Ceph clusters it creates.
func DefaultLegacyConfigs() []Option {
	overrides := []Option{
		// TODO: drop this when FlexVolume is no longer supported
		configOverride("global", "rbd_default_features", "3"),
	}
	return overrides
}
<|endoftext|>


<commit_before>package oauth2

import (
	"context"
	"strings"

	"github.com/hellofresh/janus/pkg/jwt"
	log "github.com/sirupsen/logrus"
)

const (
	// JWT provides a way to check the `exp` field on the JWT and make sure the token is still valid. This is
	// probably the most versatile way to check for tokens, since it doesn't require any storage or extra calls in
	// each request.
	JWT ManagerType = iota
	// Introspection strategy makes sure to validate the provided token on every request against the authentication provider.
	Introspection
)

var typesMap = map[string]ManagerType{
	"jwt":           JWT,
	"introspection": Introspection,
}

// ParseType takes a string type and returns the Manager type constant.
func ParseType(lvl string) (ManagerType, error) {
	m, ok := typesMap[strings.ToLower(lvl)]
	if !ok {
		var m ManagerType
		return m, ErrUnknownStrategy
	}
	return m, nil
}

// ManagerType type
type ManagerType uint8

// Manager holds the methods to handle tokens
type Manager interface {
	IsKeyAuthorized(ctx context.Context, accessToken string) bool
}

// ManagerFactory is used for creating a new manager
type ManagerFactory struct {
	oAuthServer *OAuth
}

// NewManagerFactory creates a new instance of ManagerFactory
func NewManagerFactory(oAuthServer *OAuth) *ManagerFactory {
	return &ManagerFactory{oAuthServer}
}

// Build creates a manager based on the type
func (f *ManagerFactory) Build(t ManagerType) (Manager, error) {
	// FIXME: make it nicer with BiMap - GetByType, GetByName
	typesMapReversed := make(map[ManagerType]string, len(typesMap))
	for k, v := range typesMap {
		typesMapReversed[v] = k
	}

	log.WithField("name", typesMapReversed[t]).
		Debug("Building token strategy")

	switch t {
	case JWT:
		signingMethods, err := f.oAuthServer.TokenStrategy.GetJWTSigningMethods()
		if nil != err {
			return nil, err
		}

		return NewJWTManager(jwt.NewParser(jwt.NewParserConfig(f.oAuthServer.TokenStrategy.Leeway, signingMethods...))), nil
	case Introspection:
		settings, err := f.oAuthServer.TokenStrategy.GetIntrospectionSettings()
		if nil != err {
			return nil, err
		}

		manager, err := NewIntrospectionManager(f.oAuthServer.Endpoints.Introspect.UpstreamURL, settings)
		if err != nil {
			return nil, err
		}

		return manager, nil
	}

	return nil, ErrUnknownManager
}
<commit_msg>Added logging for JWT parser configuration<commit_after>package oauth2

import (
	"context"
	"fmt"
	"strings"

	"github.com/hellofresh/janus/pkg/jwt"
	log "github.com/sirupsen/logrus"
)

const (
	// JWT provides a way to check the `exp` field on the JWT and make sure the token is still valid. This is
	// probably the most versatile way to check for tokens, since it doesn't require any storage or extra calls in
	// each request.
	JWT ManagerType = iota
	// Introspection strategy makes sure to validate the provided token on every request against the authentication provider.
	Introspection
)

var typesMap = map[string]ManagerType{
	"jwt":           JWT,
	"introspection": Introspection,
}

// ParseType takes a string type and returns the Manager type constant.
func ParseType(lvl string) (ManagerType, error) {
	m, ok := typesMap[strings.ToLower(lvl)]
	if !ok {
		var m ManagerType
		return m, ErrUnknownStrategy
	}
	return m, nil
}

// ManagerType type
type ManagerType uint8

// Manager holds the methods to handle tokens
type Manager interface {
	IsKeyAuthorized(ctx context.Context, accessToken string) bool
}

// ManagerFactory is used for creating a new manager
type ManagerFactory struct {
	oAuthServer *OAuth
}

// NewManagerFactory creates a new instance of ManagerFactory
func NewManagerFactory(oAuthServer *OAuth) *ManagerFactory {
	return &ManagerFactory{oAuthServer}
}

// Build creates a manager based on the type
func (f *ManagerFactory) Build(t ManagerType) (Manager, error) {
	// FIXME: make it nicer with BiMap - GetByType, GetByName
	typesMapReversed := make(map[ManagerType]string, len(typesMap))
	for k, v := range typesMap {
		typesMapReversed[v] = k
	}

	log.WithField("name", typesMapReversed[t]).
		Debug("Building token strategy")

	switch t {
	case JWT:
		signingMethods, err := f.oAuthServer.TokenStrategy.GetJWTSigningMethods()
		if nil != err {
			return nil, err
		}

		logEntry := log.WithField("leeway", f.oAuthServer.TokenStrategy.Leeway)
		for i, signingMethod := range signingMethods {
			logEntry = logEntry.WithField(fmt.Sprintf("alg_%d", i), signingMethod.Alg)
		}
		logEntry.Debug("Building JWT token parser")

		return NewJWTManager(jwt.NewParser(jwt.NewParserConfig(f.oAuthServer.TokenStrategy.Leeway, signingMethods...))), nil
	case Introspection:
		settings, err := f.oAuthServer.TokenStrategy.GetIntrospectionSettings()
		if nil != err {
			return nil, err
		}

		manager, err := NewIntrospectionManager(f.oAuthServer.Endpoints.Introspect.UpstreamURL, settings)
		if err != nil {
			return nil, err
		}

		return manager, nil
	}

	return nil, ErrUnknownManager
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 etcd

import (
	"context"
	"fmt"

	"k8s.io/apimachinery/pkg/api/meta"
	metatable "k8s.io/apimachinery/pkg/api/meta/table"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apiserver/pkg/registry/generic"
	genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
	"k8s.io/apiserver/pkg/registry/rest"
	"k8s.io/kube-aggregator/pkg/apis/apiregistration"
	"k8s.io/kube-aggregator/pkg/registry/apiservice"
)

// REST implements a RESTStorage for API services against etcd
type REST struct {
	*genericregistry.Store
}

// NewREST returns a RESTStorage object that will work against API services.
func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST {
	strategy := apiservice.NewStrategy(scheme)
	store := &genericregistry.Store{
		NewFunc:                  func() runtime.Object { return &apiregistration.APIService{} },
		NewListFunc:              func() runtime.Object { return &apiregistration.APIServiceList{} },
		PredicateFunc:            apiservice.MatchAPIService,
		DefaultQualifiedResource: apiregistration.Resource("apiservices"),

		CreateStrategy: strategy,
		UpdateStrategy: strategy,
		DeleteStrategy: strategy,
	}
	options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: apiservice.GetAttrs}
	if err := store.CompleteWithOptions(options); err != nil {
		panic(err) // TODO: Propagate error up
	}
	return &REST{store}
}

var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()

// ConvertToTable implements the TableConvertor interface for REST.
func (c *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
	table := &metav1.Table{
		ColumnDefinitions: []metav1.TableColumnDefinition{
			{Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]},
			{Name: "Service", Type: "string", Description: "The reference to the service that hosts this API endpoint."},
			{Name: "Available", Type: "string", Description: "Whether this service is available."},
			{Name: "Age", Type: "string", Description: swaggerMetadataDescriptions["creationTimestamp"]},
		},
	}
	if m, err := meta.ListAccessor(obj); err == nil {
		table.ResourceVersion = m.GetResourceVersion()
		table.SelfLink = m.GetSelfLink()
		table.Continue = m.GetContinue()
		table.RemainingItemCount = m.GetRemainingItemCount()
	} else {
		if m, err := meta.CommonAccessor(obj); err == nil {
			table.ResourceVersion = m.GetResourceVersion()
			table.SelfLink = m.GetSelfLink()
		}
	}

	var err error
	table.Rows, err = metatable.MetaToTableRow(obj, func(obj runtime.Object, m metav1.Object, name, age string) ([]interface{}, error) {
		svc := obj.(*apiregistration.APIService)
		service := "Local"
		if svc.Spec.Service != nil {
			service = fmt.Sprintf("%s/%s", svc.Spec.Service.Namespace, svc.Spec.Service.Name)
		}
		status := string(apiregistration.ConditionUnknown)
		if condition := getCondition(svc.Status.Conditions, "Available"); condition != nil {
			switch {
			case condition.Status == apiregistration.ConditionTrue:
				status = string(condition.Status)
			case len(condition.Reason) > 0:
				status = fmt.Sprintf("%s (%s)", condition.Status, condition.Reason)
			default:
				status = string(condition.Status)
			}
		}
		return []interface{}{name, service, status, age}, nil
	})
	return table, err
}

func getCondition(conditions []apiregistration.APIServiceCondition, conditionType apiregistration.APIServiceConditionType) *apiregistration.APIServiceCondition {
	for i, condition := range conditions {
		if condition.Type == conditionType {
			return &conditions[i]
		}
	}
	return nil
}

// NewStatusREST makes a RESTStorage for status that has more limited options.
// It is based on the original REST so that we can share the same underlying store
func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
	statusStore := *rest.Store
	statusStore.CreateStrategy = nil
	statusStore.DeleteStrategy = nil
	statusStore.UpdateStrategy = apiservice.NewStatusStrategy(scheme)
	return &StatusREST{store: &statusStore}
}

// StatusREST implements the REST endpoint for changing the status of an APIService.
type StatusREST struct {
	store *genericregistry.Store
}

var _ = rest.Patcher(&StatusREST{})

// New creates a new APIService object.
func (r *StatusREST) New() runtime.Object {
	return &apiregistration.APIService{}
}

// Get retrieves the object from the storage. It is required to support Patch.
func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
	return r.store.Get(ctx, name, options)
}

// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
	// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
	// subresources should never allow create on update.
	return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
}
<commit_msg>Define default table converters for missing resources<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 etcd

import (
	"context"
	"fmt"

	"k8s.io/apimachinery/pkg/api/meta"
	metatable "k8s.io/apimachinery/pkg/api/meta/table"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apiserver/pkg/registry/generic"
	genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
	"k8s.io/apiserver/pkg/registry/rest"
	"k8s.io/kube-aggregator/pkg/apis/apiregistration"
	"k8s.io/kube-aggregator/pkg/registry/apiservice"
)

// REST implements a RESTStorage for API services against etcd
type REST struct {
	*genericregistry.Store
}

// NewREST returns a RESTStorage object that will work against API services.
func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST {
	strategy := apiservice.NewStrategy(scheme)
	store := &genericregistry.Store{
		NewFunc:                  func() runtime.Object { return &apiregistration.APIService{} },
		NewListFunc:              func() runtime.Object { return &apiregistration.APIServiceList{} },
		PredicateFunc:            apiservice.MatchAPIService,
		DefaultQualifiedResource: apiregistration.Resource("apiservices"),

		CreateStrategy: strategy,
		UpdateStrategy: strategy,
		DeleteStrategy: strategy,

		// TODO: define table converter that exposes more than name/creation timestamp
		TableConvertor: rest.NewDefaultTableConvertor(apiregistration.Resource("apiservices")),
	}
	options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: apiservice.GetAttrs}
	if err := store.CompleteWithOptions(options); err != nil {
		panic(err) // TODO: Propagate error up
	}
	return &REST{store}
}

var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()

// ConvertToTable implements the TableConvertor interface for REST.
func (c *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
	table := &metav1.Table{
		ColumnDefinitions: []metav1.TableColumnDefinition{
			{Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]},
			{Name: "Service", Type: "string", Description: "The reference to the service that hosts this API endpoint."},
			{Name: "Available", Type: "string", Description: "Whether this service is available."},
			{Name: "Age", Type: "string", Description: swaggerMetadataDescriptions["creationTimestamp"]},
		},
	}
	if m, err := meta.ListAccessor(obj); err == nil {
		table.ResourceVersion = m.GetResourceVersion()
		table.SelfLink = m.GetSelfLink()
		table.Continue = m.GetContinue()
		table.RemainingItemCount = m.GetRemainingItemCount()
	} else {
		if m, err := meta.CommonAccessor(obj); err == nil {
			table.ResourceVersion = m.GetResourceVersion()
			table.SelfLink = m.GetSelfLink()
		}
	}

	var err error
	table.Rows, err = metatable.MetaToTableRow(obj, func(obj runtime.Object, m metav1.Object, name, age string) ([]interface{}, error) {
		svc := obj.(*apiregistration.APIService)
		service := "Local"
		if svc.Spec.Service != nil {
			service = fmt.Sprintf("%s/%s", svc.Spec.Service.Namespace, svc.Spec.Service.Name)
		}
		status := string(apiregistration.ConditionUnknown)
		if condition := getCondition(svc.Status.Conditions, "Available"); condition != nil {
			switch {
			case condition.Status == apiregistration.ConditionTrue:
				status = string(condition.Status)
			case len(condition.Reason) > 0:
				status = fmt.Sprintf("%s (%s)", condition.Status, condition.Reason)
			default:
				status = string(condition.Status)
			}
		}
		return []interface{}{name, service, status, age}, nil
	})
	return table, err
}

func getCondition(conditions []apiregistration.APIServiceCondition, conditionType apiregistration.APIServiceConditionType) *apiregistration.APIServiceCondition {
	for i, condition := range conditions {
		if condition.Type == conditionType {
			return &conditions[i]
		}
	}
	return nil
}

// NewStatusREST makes a RESTStorage for status that has more limited options.
// It is based on the original REST so that we can share the same underlying store
func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
	statusStore := *rest.Store
	statusStore.CreateStrategy = nil
	statusStore.DeleteStrategy = nil
	statusStore.UpdateStrategy = apiservice.NewStatusStrategy(scheme)
	return &StatusREST{store: &statusStore}
}

// StatusREST implements the REST endpoint for changing the status of an APIService.
type StatusREST struct {
	store *genericregistry.Store
}

var _ = rest.Patcher(&StatusREST{})

// New creates a new APIService object.
func (r *StatusREST) New() runtime.Object {
	return &apiregistration.APIService{}
}

// Get retrieves the object from the storage. It is required to support Patch.
func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
	return r.store.Get(ctx, name, options)
}

// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
	// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
	// subresources should never allow create on update.
	return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
}
<|endoftext|>


<commit_before>package commands

import (
	"crypto/sha256"
	"encoding/hex"
	"io"
	"os"
	"path/filepath"

	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/spf13/cobra"
)

var (
	fsckDryRun bool
)

// TODO(zeroshirts): 'git fsck' reports status (percentage, current#/total) as
// it checks... we should do the same, as we are rehashing potentially gigs and
// gigs of content.
//
// NOTE(zeroshirts): Ideally git would have hooks for fsck such that we could
// chain a lfs-fsck, but I don't think it does.
func fsckCommand(cmd *cobra.Command, args []string) {
	installHooks(false)
	requireInRepo()

	ref, err := git.CurrentRef()
	if err != nil {
		ExitWithError(err)
	}

	var corruptOids []string
	gitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err == nil {
			var pointerOk bool
			pointerOk, err = fsckPointer(p.Name, p.Oid)
			if !pointerOk {
				corruptOids = append(corruptOids, p.Oid)
			}
		}

		if err != nil {
			Panic(err, "Error checking Git LFS files")
		}
	})

	if err := gitscanner.ScanRef(ref.Sha, nil); err != nil {
		ExitWithError(err)
	}

	if err := gitscanner.ScanIndex("HEAD", nil); err != nil {
		ExitWithError(err)
	}

	gitscanner.Close()

	if len(corruptOids) == 0 {
		Print("Git LFS fsck OK")
		return
	}

	if fsckDryRun {
		return
	}

	badDir := filepath.Join(cfg.LFSStorageDir(), "bad")
	Print("Moving corrupt objects to %s", badDir)

	if err := os.MkdirAll(badDir, 0755); err != nil {
		ExitWithError(err)
	}

	for _, oid := range corruptOids {
		badFile := filepath.Join(badDir, oid)
		if err := os.Rename(cfg.Filesystem().ObjectPathname(oid), badFile); err != nil {
			ExitWithError(err)
		}
	}
}

func fsckPointer(name, oid string) (bool, error) {
	path := cfg.Filesystem().ObjectPathname(oid)

	Debug("Examining %v (%v)", name, path)

	f, err := os.Open(path)
	if pErr, pOk := err.(*os.PathError); pOk {
		Print("Object %s (%s) could not be checked: %s", name, oid, pErr.Err)
		return false, nil
	}

	if err != nil {
		return false, err
	}

	oidHash := sha256.New()
	_, err = io.Copy(oidHash, f)
	f.Close()
	if err != nil {
		return false, err
	}

	recalculatedOid := hex.EncodeToString(oidHash.Sum(nil))
	if recalculatedOid == oid {
		return true, nil
	}

	Print("Object %s (%s) is corrupt", name, oid)
	return false, nil
}

func init() {
	RegisterCommand("fsck", fsckCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&fsckDryRun, "dry-run", "d", false, "List corrupt objects without deleting them.")
	})
}
<commit_msg>commands/fsck: attach a filter to exclude unfetched items from fsck<commit_after>package commands

import (
	"crypto/sha256"
	"encoding/hex"
	"io"
	"os"
	"path/filepath"

	"github.com/git-lfs/git-lfs/filepathfilter"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/spf13/cobra"
)

var (
	fsckDryRun bool
)

// TODO(zeroshirts): 'git fsck' reports status (percentage, current#/total) as
// it checks... we should do the same, as we are rehashing potentially gigs and
// gigs of content.
//
// NOTE(zeroshirts): Ideally git would have hooks for fsck such that we could
// chain a lfs-fsck, but I don't think it does.
func fsckCommand(cmd *cobra.Command, args []string) {
	installHooks(false)
	requireInRepo()

	ref, err := git.CurrentRef()
	if err != nil {
		ExitWithError(err)
	}

	var corruptOids []string
	gitscanner := lfs.NewGitScanner(func(p *lfs.WrappedPointer, err error) {
		if err == nil {
			var pointerOk bool
			pointerOk, err = fsckPointer(p.Name, p.Oid)
			if !pointerOk {
				corruptOids = append(corruptOids, p.Oid)
			}
		}

		if err != nil {
			Panic(err, "Error checking Git LFS files")
		}
	})

	// If 'lfs.fetchexclude' is set and 'git lfs fsck' is run after the
	// initial fetch (i.e., has elected to fetch a subset of Git LFS
	// objects), the "missing" ones will fail the fsck.
	//
	// Attach a filepathfilter to avoid _only_ the excluded paths.
	gitscanner.Filter = filepathfilter.New(nil, cfg.FetchExcludePaths())

	if err := gitscanner.ScanRef(ref.Sha, nil); err != nil {
		ExitWithError(err)
	}

	if err := gitscanner.ScanIndex("HEAD", nil); err != nil {
		ExitWithError(err)
	}

	gitscanner.Close()

	if len(corruptOids) == 0 {
		Print("Git LFS fsck OK")
		return
	}

	if fsckDryRun {
		return
	}

	badDir := filepath.Join(cfg.LFSStorageDir(), "bad")
	Print("Moving corrupt objects to %s", badDir)

	if err := os.MkdirAll(badDir, 0755); err != nil {
		ExitWithError(err)
	}

	for _, oid := range corruptOids {
		badFile := filepath.Join(badDir, oid)
		if err := os.Rename(cfg.Filesystem().ObjectPathname(oid), badFile); err != nil {
			ExitWithError(err)
		}
	}
}

func fsckPointer(name, oid string) (bool, error) {
	path := cfg.Filesystem().ObjectPathname(oid)

	Debug("Examining %v (%v)", name, path)

	f, err := os.Open(path)
	if pErr, pOk := err.(*os.PathError); pOk {
		Print("Object %s (%s) could not be checked: %s", name, oid, pErr.Err)
		return false, nil
	}

	if err != nil {
		return false, err
	}

	oidHash := sha256.New()
	_, err = io.Copy(oidHash, f)
	f.Close()
	if err != nil {
		return false, err
	}

	recalculatedOid := hex.EncodeToString(oidHash.Sum(nil))
	if recalculatedOid == oid {
		return true, nil
	}

	Print("Object %s (%s) is corrupt", name, oid)
	return false, nil
}

func init() {
	RegisterCommand("fsck", fsckCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&fsckDryRun, "dry-run", "d", false, "List corrupt objects without deleting them.")
	})
}
<|endoftext|>


<commit_before>// Package dnode implements a message processor for communication
// via dnode protocol. See the following URL for details:
// https://github.com/substack/dnode-protocol/blob/master/doc/protocol.markdown
package dnode

import (
	"io/ioutil"
	"log"
	"reflect"
)

var l *log.Logger = log.New(ioutil.Discard, "", log.Lshortfile)

// Uncomment following to see log messages.
// var l *log.Logger = log.New(os.Stderr, "", log.Lshortfile)

type Dnode struct {
	// Registered methods are saved in this map.
	handlers map[string]reflect.Value

	// Reference to sent callbacks are saved in this map.
	callbacks map[uint64]reflect.Value

	// Next callback number.
	// Incremented atomically by registerCallback().
	seq uint64

	// For sending and receiving messages
	transport Transport

	// Argument wrappers to be called when sending/receiving.
	WrapMethodArgs   Wrapper
	WrapCallbackArgs Wrapper

	// Dnode message processors.
	RunMethod   Runner
	RunCallback Runner
}

type Wrapper func(args interface{}, tr Transport) []interface{}
type Runner func(method string, handlerFunc reflect.Value, args *Partial, tr Transport)

// Transport is an interface for sending and receiving data on network.
// Each Transport must be unique for each Client.
type Transport interface {
	// Address of the connected client
	RemoteAddr() string

	// Send single message
	Send(msg []byte) error

	// Receive single message
	Receive() ([]byte, error)

	// A place to save/read extra information about the client
	Properties() map[string]interface{}
}

// Message is the JSON object to call a method at the other side.
type Message struct {
	// Method can be an integer or string.
	Method interface{} `json:"method"`

	// Array of arguments
	Arguments *Partial `json:"arguments"`

	// Integer map of callback paths in arguments
	Callbacks map[string]Path `json:"callbacks"`

	// Links are not used for now.
	Links []interface{} `json:"links"`
}

// New returns a pointer to a new Dnode.
func New(transport Transport) *Dnode {
	return &Dnode{
		handlers:  make(map[string]reflect.Value),
		callbacks: make(map[uint64]reflect.Value),
		transport: transport,
	}
}

// Copy returns a pointer to a new Dnode with the same handlers as d but empty callbacks.
func (d *Dnode) Copy(transport Transport) *Dnode {
	return &Dnode{
		handlers:         d.handlers,
		callbacks:        make(map[uint64]reflect.Value),
		transport:        transport,
		WrapMethodArgs:   d.WrapMethodArgs,
		WrapCallbackArgs: d.WrapCallbackArgs,
		RunMethod:        d.RunMethod,
		RunCallback:      d.RunCallback,
	}
}

// HandleFunc registers the handler for the given method.
// If a handler already exists for method, HandleFunc panics.
func (d *Dnode) HandleFunc(method string, handler interface{}) {
	if method == "" {
		panic("dnode: invalid method " + method)
	}
	if handler == nil {
		panic("dnode: nil handler")
	}
	if _, ok := d.handlers[method]; ok {
		panic("dnode: handler already exists for method")
	}
	val := reflect.ValueOf(handler)
	if val.Kind() != reflect.Func {
		panic("dnode: handler must be a func")
	}

	d.handlers[method] = val
}

// Run processes incoming messages. Blocking.
func (d *Dnode) Run() error {
	for {
		msg, err := d.transport.Receive()
		if err != nil {
			return err
		}

		// Do not run this function in a separate goroutine,
		// otherwise the order of the messages may be mixed.
		// If the order of the messages is not important for the user of
		// this package he can choose to start separate gorouitens in his own
		// handler. However, if we make this decision here and start a goroutine
		// for each message the user cannot change this behavior in his handler.
		// This is very important in Kites such as Terminal because the order
		// of the key presses must be preserved.
		d.processMessage(msg)
	}
}

// RemoveCallback removes the callback with id from callbacks.
// Can be used to remove unused callbacks to free memory.
func (d *Dnode) RemoveCallback(id uint64) {
	delete(d.callbacks, id)
}
<commit_msg>kite: handle messages in seperate goroutines<commit_after>// Package dnode implements a message processor for communication
// via dnode protocol. See the following URL for details:
// https://github.com/substack/dnode-protocol/blob/master/doc/protocol.markdown
package dnode

import (
	"io/ioutil"
	"log"
	"reflect"
)

var l *log.Logger = log.New(ioutil.Discard, "", log.Lshortfile)

// Uncomment following to see log messages.
// var l *log.Logger = log.New(os.Stderr, "", log.Lshortfile)

type Dnode struct {
	// Registered methods are saved in this map.
	handlers map[string]reflect.Value

	// Reference to sent callbacks are saved in this map.
	callbacks map[uint64]reflect.Value

	// Next callback number.
	// Incremented atomically by registerCallback().
	seq uint64

	// For sending and receiving messages
	transport Transport

	// Argument wrappers to be called when sending/receiving.
	WrapMethodArgs   Wrapper
	WrapCallbackArgs Wrapper

	// Dnode message processors.
	RunMethod   Runner
	RunCallback Runner
}

type Wrapper func(args interface{}, tr Transport) []interface{}
type Runner func(method string, handlerFunc reflect.Value, args *Partial, tr Transport)

// Transport is an interface for sending and receiving data on network.
// Each Transport must be unique for each Client.
type Transport interface {
	// Address of the connected client
	RemoteAddr() string

	// Send single message
	Send(msg []byte) error

	// Receive single message
	Receive() ([]byte, error)

	// A place to save/read extra information about the client
	Properties() map[string]interface{}
}

// Message is the JSON object to call a method at the other side.
type Message struct {
	// Method can be an integer or string.
	Method interface{} `json:"method"`

	// Array of arguments
	Arguments *Partial `json:"arguments"`

	// Integer map of callback paths in arguments
	Callbacks map[string]Path `json:"callbacks"`

	// Links are not used for now.
	Links []interface{} `json:"links"`
}

// New returns a pointer to a new Dnode.
func New(transport Transport) *Dnode {
	return &Dnode{
		handlers:  make(map[string]reflect.Value),
		callbacks: make(map[uint64]reflect.Value),
		transport: transport,
	}
}

// Copy returns a pointer to a new Dnode with the same handlers as d but empty callbacks.
func (d *Dnode) Copy(transport Transport) *Dnode {
	return &Dnode{
		handlers:         d.handlers,
		callbacks:        make(map[uint64]reflect.Value),
		transport:        transport,
		WrapMethodArgs:   d.WrapMethodArgs,
		WrapCallbackArgs: d.WrapCallbackArgs,
		RunMethod:        d.RunMethod,
		RunCallback:      d.RunCallback,
	}
}

// HandleFunc registers the handler for the given method.
// If a handler already exists for method, HandleFunc panics.
func (d *Dnode) HandleFunc(method string, handler interface{}) {
	if method == "" {
		panic("dnode: invalid method " + method)
	}
	if handler == nil {
		panic("dnode: nil handler")
	}
	if _, ok := d.handlers[method]; ok {
		panic("dnode: handler already exists for method")
	}
	val := reflect.ValueOf(handler)
	if val.Kind() != reflect.Func {
		panic("dnode: handler must be a func")
	}

	d.handlers[method] = val
}

// Run processes incoming messages. Blocking.
func (d *Dnode) Run() error {
	for {
		msg, err := d.transport.Receive()
		if err != nil {
			return err
		}

		go d.processMessage(msg)
	}
}

// RemoveCallback removes the callback with id from callbacks.
// Can be used to remove unused callbacks to free memory.
func (d *Dnode) RemoveCallback(id uint64) {
	delete(d.callbacks, id)
}
<|endoftext|>


<commit_before>package manager

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

	"github.com/ironman-project/ironman/pkg/template"
	"github.com/ironman-project/ironman/pkg/testutils"
)

var (
	testManagerPath        = "testing/repository"
	testTemplatesDirectory = "templates"
	testTemplatesPath      = filepath.Join(testManagerPath, testTemplatesDirectory)
)

func createTestTemplate(t *testing.T, names ...string) (string, func()) {
	tempManager, err := ioutil.TempDir("", "ironman-test-manager")
	if err != nil {
		t.Fatalf("failed to create test manager %s", err)
	}
	sourcePath := filepath.Join(testManagerPath, testTemplatesDirectory, "base")
	for _, name := range names {
		destPath := filepath.Join(tempManager, name)
		testutils.CopyDir(sourcePath, destPath, t)

	}

	return tempManager, func() {
		err := os.RemoveAll(tempManager)
		if err != nil {
			t.Fatalf("failed to clean test manager %s", err)
		}
	}
}

func TestNewBaseManager(t *testing.T) {
	type args struct {
		path string
	}
	tests := []struct {
		name string
		args args
		want Manager
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := NewBaseManager(tt.args.path, "templates"); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("NewBaseManager() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestBaseManager_Uninstall(t *testing.T) {
	type args struct {
		templateID string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{"Uninstall template", args{"valid_removable"}, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			managerPath, clean := createTestTemplate(t, tt.args.templateID)
			defer clean()
			b := NewBaseManager(managerPath, testTemplatesDirectory)
			if err := b.Uninstall(tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Uninstall() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_Find(t *testing.T) {
	type args struct {
		templateID string
	}
	tests := []struct {
		name    string
		b       *BaseManager
		args    args
		wantErr bool
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := &BaseManager{}
			if err := b.Find(tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Find() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_IsInstalled(t *testing.T) {
	type args struct {
		templateID string
	}
	tests := []struct {
		name        string
		managerPath string
		args        args
		want        bool
		wantErr     bool
	}{
		{"Template is installed", testManagerPath, args{"valid"}, true, false},
		{"Template is not installed", testManagerPath, args{"not_installed"}, false, false},
		{"Template invalid empty name", testManagerPath, args{""}, false, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := NewBaseManager(tt.managerPath, testTemplatesDirectory)
			got, err := b.IsInstalled(tt.args.templateID)
			if (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.IsInstalled() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if got != tt.want {
				t.Errorf("BaseManager.IsInstalled() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestBaseManager_Installed(t *testing.T) {
	tests := []struct {
		name        string
		managerPath string
		want        []*template.Metadata
		wantErr     bool
	}{
		{"All the installed templates", testManagerPath, []*template.Metadata{&template.Metadata{ID: "base"}, &template.Metadata{ID: "valid"}}, false},
		{"Non existing manager path", "unexistingPath", nil, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := NewBaseManager(tt.managerPath, testTemplatesDirectory)
			got, err := b.Installed()
			if (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Installed() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("BaseManager.Installed() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestBaseManager_Link(t *testing.T) {
	type args struct {
		templatePath string
		templateID   string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"Link a template",
			args{
				templatePath: filepath.Join("testing", "repository", "templates", "valid"),
				templateID:   "dev-valid",
			},
			false,
		},
		{
			"Link a template with non existing path",
			args{
				templatePath: filepath.Join("nonexisting", "repository", "templates", "valid"),
				templateID:   "dev-nonexisting",
			},
			true,
		},
		{
			"Link a template with invalid ID",
			args{
				templatePath: filepath.Join("nonexisting", "repository", "templates", "valid"),
				templateID:   "",
			},
			true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			b := NewBaseManager(testManagerPath, testTemplatesDirectory)
			createdLinkPath := filepath.Join(testTemplatesPath, tt.args.templateID)
			defer func() {
				_ = os.Remove(createdLinkPath)
			}()

			if _, err := b.Link(tt.args.templatePath, tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Link() error = %v, wantErr %v", err, tt.wantErr)
				return
			} else if tt.wantErr {
				return
			}

			if !testutils.FileExists(createdLinkPath) {
				t.Errorf("BaseManager.Link() %s file should exists", createdLinkPath)
				return
			}

			ymlFilePath := filepath.Join(createdLinkPath, ".ironman.yaml")
			if !testutils.FileExists(ymlFilePath) {
				t.Errorf("BaseManager.Link() %s file should exists", ymlFilePath)
			}
		})
	}
}

func TestBaseManager_Unlink(t *testing.T) {
	type args struct {
		templatePath     string
		templateID       string
		unlinkTemplateID string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"Unlink template",
			args{
				templatePath:     filepath.Join("testing", "repository", "templates", "valid"),
				templateID:       "dev-valid",
				unlinkTemplateID: "dev-valid",
			},
			false,
		},
		{
			"Unlink template with non existing id",
			args{
				templatePath:     filepath.Join("testing", "repository", "templates", "valid"),
				templateID:       "dev-valid",
				unlinkTemplateID: "non-existing",
			},
			true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			b := NewBaseManager(testManagerPath, testTemplatesDirectory)
			createdLinkPath := filepath.Join(testTemplatesPath, tt.args.templateID)
			defer func() {
				_ = os.Remove(createdLinkPath)
			}()
			_, _ = b.Link(tt.args.templatePath, tt.args.templateID)

			if err := b.Unlink(tt.args.unlinkTemplateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Unlink() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_Install(t *testing.T) {
	type args struct {
		templateLocator string
	}
	tests := []struct {
		name    string
		b       *BaseManager
		args    args
		wantErr bool
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := &BaseManager{}
			if err := b.Install(tt.args.templateLocator); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Install() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_Update(t *testing.T) {
	type args struct {
		templateID string
	}
	tests := []struct {
		name    string
		b       *BaseManager
		args    args
		wantErr bool
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := &BaseManager{}
			if err := b.Update(tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Update() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}
<commit_msg>fix broken test<commit_after>package manager

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

	"github.com/ironman-project/ironman/pkg/template"
	"github.com/ironman-project/ironman/pkg/testutils"
)

var (
	testManagerPath        = "testing/repository"
	testTemplatesDirectory = "templates"
	testTemplatesPath      = filepath.Join(testManagerPath, testTemplatesDirectory)
)

func createTestTemplate(t *testing.T, names ...string) (string, func()) {
	tempManager, err := ioutil.TempDir("", "ironman-test-manager")
	if err != nil {
		t.Fatalf("failed to create test manager %s", err)
	}
	sourcePath := filepath.Join(testManagerPath, testTemplatesDirectory, "base")
	for _, name := range names {
		destPath := filepath.Join(tempManager, name)
		testutils.CopyDir(sourcePath, destPath, t)

	}

	return tempManager, func() {
		err := os.RemoveAll(tempManager)
		if err != nil {
			t.Fatalf("failed to clean test manager %s", err)
		}
	}
}

func TestNewBaseManager(t *testing.T) {
	type args struct {
		path string
	}
	tests := []struct {
		name string
		args args
		want Manager
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := NewBaseManager(tt.args.path, "templates"); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("NewBaseManager() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestBaseManager_Uninstall(t *testing.T) {
	type args struct {
		templateID string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{"Uninstall template", args{"valid_removable"}, false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			managerPath, clean := createTestTemplate(t, tt.args.templateID)
			defer clean()
			b := NewBaseManager(managerPath, testTemplatesDirectory)
			if err := b.Uninstall(tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Uninstall() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_Find(t *testing.T) {
	type args struct {
		templateID string
	}
	tests := []struct {
		name    string
		b       *BaseManager
		args    args
		wantErr bool
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := &BaseManager{}
			if err := b.Find(tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Find() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_Installed(t *testing.T) {
	tests := []struct {
		name        string
		managerPath string
		want        []*template.Metadata
		wantErr     bool
	}{
		{"All the installed templates", testManagerPath, []*template.Metadata{&template.Metadata{ID: "base"}, &template.Metadata{ID: "valid"}}, false},
		{"Non existing manager path", "unexistingPath", nil, true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := NewBaseManager(tt.managerPath, testTemplatesDirectory)
			got, err := b.Installed()
			if (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Installed() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("BaseManager.Installed() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestBaseManager_Link(t *testing.T) {
	type args struct {
		templatePath string
		templateID   string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"Link a template",
			args{
				templatePath: filepath.Join("testing", "repository", "templates", "valid"),
				templateID:   "dev-valid",
			},
			false,
		},
		{
			"Link a template with non existing path",
			args{
				templatePath: filepath.Join("nonexisting", "repository", "templates", "valid"),
				templateID:   "dev-nonexisting",
			},
			true,
		},
		{
			"Link a template with invalid ID",
			args{
				templatePath: filepath.Join("nonexisting", "repository", "templates", "valid"),
				templateID:   "",
			},
			true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			b := NewBaseManager(testManagerPath, testTemplatesDirectory)
			createdLinkPath := filepath.Join(testTemplatesPath, tt.args.templateID)
			defer func() {
				_ = os.Remove(createdLinkPath)
			}()

			if _, err := b.Link(tt.args.templatePath, tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Link() error = %v, wantErr %v", err, tt.wantErr)
				return
			} else if tt.wantErr {
				return
			}

			if !testutils.FileExists(createdLinkPath) {
				t.Errorf("BaseManager.Link() %s file should exists", createdLinkPath)
				return
			}

			ymlFilePath := filepath.Join(createdLinkPath, ".ironman.yaml")
			if !testutils.FileExists(ymlFilePath) {
				t.Errorf("BaseManager.Link() %s file should exists", ymlFilePath)
			}
		})
	}
}

func TestBaseManager_Unlink(t *testing.T) {
	type args struct {
		templatePath     string
		templateID       string
		unlinkTemplateID string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"Unlink template",
			args{
				templatePath:     filepath.Join("testing", "repository", "templates", "valid"),
				templateID:       "dev-valid",
				unlinkTemplateID: "dev-valid",
			},
			false,
		},
		{
			"Unlink template with non existing id",
			args{
				templatePath:     filepath.Join("testing", "repository", "templates", "valid"),
				templateID:       "dev-valid",
				unlinkTemplateID: "non-existing",
			},
			true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {

			b := NewBaseManager(testManagerPath, testTemplatesDirectory)
			createdLinkPath := filepath.Join(testTemplatesPath, tt.args.templateID)
			defer func() {
				_ = os.Remove(createdLinkPath)
			}()
			_, _ = b.Link(tt.args.templatePath, tt.args.templateID)

			if err := b.Unlink(tt.args.unlinkTemplateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Unlink() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_Install(t *testing.T) {
	type args struct {
		templateLocator string
	}
	tests := []struct {
		name    string
		b       *BaseManager
		args    args
		wantErr bool
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := &BaseManager{}
			if err := b.Install(tt.args.templateLocator); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Install() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestBaseManager_Update(t *testing.T) {
	type args struct {
		templateID string
	}
	tests := []struct {
		name    string
		b       *BaseManager
		args    args
		wantErr bool
	}{
		// TODO: Add test cases.
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			b := &BaseManager{}
			if err := b.Update(tt.args.templateID); (err != nil) != tt.wantErr {
				t.Errorf("BaseManager.Update() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"github.com/github/git-media/gitmediaclient"
	"github.com/spf13/cobra"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	pushCmd = &cobra.Command{
		Use:   "push",
		Short: "Push files to the media endpoint",
		Run:   pushCommand,
	}
	z40 = "0000000000000000000000000000000000000000"
)

func pushCommand(cmd *cobra.Command, args []string) {
	refsData, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		Panic(err, "Error reading refs on stdin")
	}

	if len(refsData) == 0 {
		return
	}

	// TODO let's pull this into a nice iteratable thing like the queue provides
	refs := strings.Split(strings.TrimSpace(string(refsData)), " ")

	refArgs := []string{"rev-list", "--objects"}
	if len(refs) > 1 {
		refArgs = append(refArgs, refs[1])
	}
	if len(refs) > 3 && refs[3] != z40 {
		refArgs = append(refArgs, "^"+refs[3])
	}

	output, err := exec.Command("git", refArgs...).Output()
	if err != nil {
		Panic(err, "Error running git rev-list --objects %v", refArgs)
	}

	scanner := bufio.NewScanner(bytes.NewBuffer(output))
	blobOids := make([]string, 0)

	for scanner.Scan() {
		line := strings.Split(scanner.Text(), " ")
		sha1 := line[0]

		linkPath := filepath.Join(gitmedia.LocalLinkDir, sha1[0:2], sha1[2:len(sha1)])
		if _, err := os.Stat(linkPath); err == nil {
			oid, err := ioutil.ReadFile(linkPath)
			if err != nil {
				Panic(err, "Error reading link file")
			}
			blobOids = append(blobOids, string(oid))
		}
	}

	// TODO - filename
	for i, oid := range blobOids {
		if wErr := pushAsset(oid, "", i+1, len(blobOids)); wErr != nil {
			Panic(wErr.Err, wErr.Error())
		}
		fmt.Printf("\n")
	}
}

func pushAsset(oid, filename string, index, totalFiles int) *gitmedia.WrappedError {
	path, err := gitmedia.LocalMediaPath(oid)
	if err == nil {
		err = gitmediaclient.Options(path)
	}

	if err == nil {
		cb, file, cbErr := gitmedia.CopyCallbackFile("push", filename, index, totalFiles)
		if cbErr != nil {
			Error(cbErr.Error())
		}

		err = gitmediaclient.Put(path, filename, cb)
		if file != nil {
			file.Close()
		}
	}

	if err != nil {
		return gitmedia.Errorf(err, "Error uploading file %s (%s)", filename, oid)
	}

	return nil
}

func init() {
	RootCmd.AddCommand(pushCmd)
}
<commit_msg>ンンン ンンン ンン<commit_after>package commands

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/github/git-media/gitmedia"
	"github.com/github/git-media/gitmediaclient"
	"github.com/spf13/cobra"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var (
	pushCmd = &cobra.Command{
		Use:   "push",
		Short: "Push files to the media endpoint",
		Run:   pushCommand,
	}
	dryRun = false
	z40    = "0000000000000000000000000000000000000000"
)

func pushCommand(cmd *cobra.Command, args []string) {
	// TODO handle (delete) case, not sending anything
	refsData, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		Panic(err, "Error reading refs on stdin")
	}

	if len(refsData) == 0 {
		return
	}

	// TODO let's pull this into a nice iteratable thing like the queue provides
	refs := strings.Split(strings.TrimSpace(string(refsData)), " ")

	refArgs := []string{"rev-list", "--objects"}
	if len(refs) > 1 {
		refArgs = append(refArgs, refs[1])
	}
	if len(refs) > 3 && refs[3] != z40 {
		refArgs = append(refArgs, "^"+refs[3])
	}

	output, err := exec.Command("git", refArgs...).Output()
	if err != nil {
		Panic(err, "Error running git rev-list --objects %v", refArgs)
	}

	scanner := bufio.NewScanner(bytes.NewBuffer(output))
	blobOids := make([]string, 0)

	for scanner.Scan() {
		line := strings.Split(scanner.Text(), " ")
		sha1 := line[0]

		linkPath := filepath.Join(gitmedia.LocalLinkDir, sha1[0:2], sha1[2:len(sha1)])
		if _, err := os.Stat(linkPath); err == nil {
			oid, err := ioutil.ReadFile(linkPath)
			if err != nil {
				Panic(err, "Error reading link file")
			}
			blobOids = append(blobOids, string(oid))
		}
	}

	// TODO - filename
	for i, oid := range blobOids {
		if dryRun {
			fmt.Println("push", oid)
			continue
		}
		if wErr := pushAsset(oid, "", i+1, len(blobOids)); wErr != nil {
			Panic(wErr.Err, wErr.Error())
		}
		fmt.Printf("\n")
	}
}

func pushAsset(oid, filename string, index, totalFiles int) *gitmedia.WrappedError {
	path, err := gitmedia.LocalMediaPath(oid)
	if err == nil {
		err = gitmediaclient.Options(path)
	}

	if err == nil {
		cb, file, cbErr := gitmedia.CopyCallbackFile("push", filename, index, totalFiles)
		if cbErr != nil {
			Error(cbErr.Error())
		}

		err = gitmediaclient.Put(path, filename, cb)
		if file != nil {
			file.Close()
		}
	}

	if err != nil {
		return gitmedia.Errorf(err, "Error uploading file %s (%s)", filename, oid)
	}

	return nil
}

func init() {
	pushCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "Do everything except actually send the updates")
	RootCmd.AddCommand(pushCmd)
}
<|endoftext|>


<commit_before>package jeeves

import "regexp"

// Result represents a hearthstone basic game result.
type Result struct {
	Player string
	Status string
}

func ParseGameResult(line string) (Result, error) {
	result := Result{}
	r, err := regexp.Compile("Entity=([^\t\n\f\r ]*).*value=(WON|LOST)")

	if err != nil {
		return result, err
	}

	if r.MatchString(line) {
		matches := r.FindStringSubmatch(line)
		result.Player = matches[1]
		result.Status = matches[2]
	}

	return result, nil
}
<commit_msg>Add some godoc.<commit_after>package jeeves

import (
	"errors"
	"regexp"
)

// Result represents a hearthstone basic game result.
type Result struct {
	Player string
	Status string
}

// ParseGameResult parses a string and detects a winner/loser.
// If no result can be detected, an error is returned.
func ParseGameResult(line string) (Result, error) {
	result := Result{}
	r, err := regexp.Compile("Entity=([^\t\n\f\r ]*).*value=(WON|LOST)")

	if err != nil {
		return result, err
	}

	if r.MatchString(line) {
		matches := r.FindStringSubmatch(line)
		result.Player = matches[1]
		result.Status = matches[2]
		return result, nil
	}

	err = errors.New("can't detect game result")
	return result, err
}
<|endoftext|>