<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Parsing of ELF executables (Linux, FreeBSD, and so on).

package objfile

import (
	"debug/dwarf"
	"debug/elf"
	"encoding/binary"
	"fmt"
	"io"
)

type elfFile struct {
	elf *elf.File
}

func openElf(r io.ReaderAt) (rawFile, error) {
	f, err := elf.NewFile(r)
	if err != nil {
		return nil, err
	}
	return &elfFile{f}, nil
}

func (f *elfFile) symbols() ([]Sym, error) {
	elfSyms, err := f.elf.Symbols()
	if err != nil {
		return nil, err
	}

	var syms []Sym
	for _, s := range elfSyms {
		sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'}
		switch s.Section {
		case elf.SHN_UNDEF:
			sym.Code = 'U'
		case elf.SHN_COMMON:
			sym.Code = 'B'
		default:
			i := int(s.Section)
			if i < 0 || i >= len(f.elf.Sections) {
				break
			}
			sect := f.elf.Sections[i]
			switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
			case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
				sym.Code = 'T'
			case elf.SHF_ALLOC:
				sym.Code = 'R'
			case elf.SHF_ALLOC | elf.SHF_WRITE:
				sym.Code = 'D'
			}
		}
		if elf.ST_BIND(s.Info) == elf.STB_LOCAL {
			sym.Code += 'a' - 'A'
		}
		syms = append(syms, sym)
	}

	return syms, nil
}

func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
	if sect := f.elf.Section(".text"); sect != nil {
		textStart = sect.Addr
	}
	if sect := f.elf.Section(".gosymtab"); sect != nil {
		if symtab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	if sect := f.elf.Section(".gopclntab"); sect != nil {
		if pclntab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	return textStart, symtab, pclntab, nil
}

func (f *elfFile) text() (textStart uint64, text []byte, err error) {
	sect := f.elf.Section(".text")
	if sect == nil {
		return 0, nil, fmt.Errorf("text section not found")
	}
	textStart = sect.Addr
	text, err = sect.Data()
	return
}

func (f *elfFile) goarch() string {
	switch f.elf.Machine {
	case elf.EM_386:
		return "386"
	case elf.EM_X86_64:
		return "amd64"
	case elf.EM_ARM:
		return "arm"
	case elf.EM_AARCH64:
		return "arm64"
	case elf.EM_PPC64:
		if f.elf.ByteOrder == binary.LittleEndian {
			return "ppc64le"
		}
		return "ppc64"
	case elf.EM_S390:
		return "s390x"
	}
	return ""
}

func (f *elfFile) loadAddress() (uint64, error) {
	for _, p := range f.elf.Progs {
		if p.Type == elf.PT_LOAD {
			return p.Vaddr, nil
		}
	}
	return 0, fmt.Errorf("unknown load address")
}

func (f *elfFile) dwarf() (*dwarf.Data, error) {
	return f.elf.DWARF()
}
<commit_msg>cmd/internal/objfile: only consider executable segments for load address<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Parsing of ELF executables (Linux, FreeBSD, and so on).

package objfile

import (
	"debug/dwarf"
	"debug/elf"
	"encoding/binary"
	"fmt"
	"io"
)

type elfFile struct {
	elf *elf.File
}

func openElf(r io.ReaderAt) (rawFile, error) {
	f, err := elf.NewFile(r)
	if err != nil {
		return nil, err
	}
	return &elfFile{f}, nil
}

func (f *elfFile) symbols() ([]Sym, error) {
	elfSyms, err := f.elf.Symbols()
	if err != nil {
		return nil, err
	}

	var syms []Sym
	for _, s := range elfSyms {
		sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'}
		switch s.Section {
		case elf.SHN_UNDEF:
			sym.Code = 'U'
		case elf.SHN_COMMON:
			sym.Code = 'B'
		default:
			i := int(s.Section)
			if i < 0 || i >= len(f.elf.Sections) {
				break
			}
			sect := f.elf.Sections[i]
			switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) {
			case elf.SHF_ALLOC | elf.SHF_EXECINSTR:
				sym.Code = 'T'
			case elf.SHF_ALLOC:
				sym.Code = 'R'
			case elf.SHF_ALLOC | elf.SHF_WRITE:
				sym.Code = 'D'
			}
		}
		if elf.ST_BIND(s.Info) == elf.STB_LOCAL {
			sym.Code += 'a' - 'A'
		}
		syms = append(syms, sym)
	}

	return syms, nil
}

func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
	if sect := f.elf.Section(".text"); sect != nil {
		textStart = sect.Addr
	}
	if sect := f.elf.Section(".gosymtab"); sect != nil {
		if symtab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	if sect := f.elf.Section(".gopclntab"); sect != nil {
		if pclntab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	return textStart, symtab, pclntab, nil
}

func (f *elfFile) text() (textStart uint64, text []byte, err error) {
	sect := f.elf.Section(".text")
	if sect == nil {
		return 0, nil, fmt.Errorf("text section not found")
	}
	textStart = sect.Addr
	text, err = sect.Data()
	return
}

func (f *elfFile) goarch() string {
	switch f.elf.Machine {
	case elf.EM_386:
		return "386"
	case elf.EM_X86_64:
		return "amd64"
	case elf.EM_ARM:
		return "arm"
	case elf.EM_AARCH64:
		return "arm64"
	case elf.EM_PPC64:
		if f.elf.ByteOrder == binary.LittleEndian {
			return "ppc64le"
		}
		return "ppc64"
	case elf.EM_S390:
		return "s390x"
	}
	return ""
}

func (f *elfFile) loadAddress() (uint64, error) {
	for _, p := range f.elf.Progs {
		if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 {
			return p.Vaddr, nil
		}
	}
	return 0, fmt.Errorf("unknown load address")
}

func (f *elfFile) dwarf() (*dwarf.Data, error) {
	return f.elf.DWARF()
}
<|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 e2e

import (
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"k8s.io/kubernetes/pkg/api"
	apierrs "k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apis/batch"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/controller/job"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/test/e2e/framework"
)

const (
	// How long to wait for a scheduledjob
	scheduledJobTimeout = 5 * time.Minute
)

var _ = framework.KubeDescribe("ScheduledJob", func() {
	options := framework.FrameworkOptions{
		ClientQPS:    20,
		ClientBurst:  50,
		GroupVersion: &unversioned.GroupVersion{Group: batch.GroupName, Version: "v2alpha1"},
	}
	f := framework.NewFramework("scheduledjob", options, nil)

	BeforeEach(func() {
		if _, err := f.Client.Batch().ScheduledJobs(f.Namespace.Name).List(api.ListOptions{}); err != nil {
			if apierrs.IsNotFound(err) {
				framework.Skipf("Could not find ScheduledJobs resource, skipping test: %#v", err)
			}
		}
	})

	// multiple jobs running at once
	It("should schedule multiple jobs concurrently", func() {
		By("Creating a scheduledjob")
		scheduledJob := newTestScheduledJob("concurrent", "*/1 * * * ?", batch.AllowConcurrent, true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring more than one job is running at a time")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 2)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring at least two running jobs exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		activeJobs := filterActiveJobs(jobs)
		Expect(len(activeJobs) >= 2).To(BeTrue())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// suspended should not schedule jobs
	It("should not schedule jobs when suspended", func() {
		By("Creating a suspended scheduledjob")
		scheduledJob := newTestScheduledJob("suspended", "*/1 * * * ?", batch.AllowConcurrent, true)
		scheduledJob.Spec.Suspend = newBool(true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring no jobs are scheduled")
		err = waitForNoJobs(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).To(HaveOccurred())

		By("Ensuring no job exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		Expect(jobs.Items).To(HaveLen(0))

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// only single active job is allowed for ForbidConcurrent
	It("should not schedule new jobs when ForbidConcurrent", func() {
		By("Creating a ForbidConcurrent scheduledjob")
		scheduledJob := newTestScheduledJob("forbid", "*/1 * * * ?", batch.ForbidConcurrent, true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring a job is scheduled")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 1)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring exactly one is scheduled")
		scheduledJob, err = getScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
		Expect(scheduledJob.Status.Active).Should(HaveLen(1))

		By("Ensuring exaclty one running job exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		activeJobs := filterActiveJobs(jobs)
		Expect(activeJobs).To(HaveLen(1))

		By("Ensuring no more jobs are scheduled")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 2)
		Expect(err).To(HaveOccurred())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// only single active job is allowed for ReplaceConcurrent
	It("should replace jobs when ReplaceConcurrent", func() {
		By("Creating a ReplaceConcurrent scheduledjob")
		scheduledJob := newTestScheduledJob("replace", "*/1 * * * ?", batch.ReplaceConcurrent, true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring a job is scheduled")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 1)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring exactly one is scheduled")
		scheduledJob, err = getScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
		Expect(scheduledJob.Status.Active).Should(HaveLen(1))

		By("Ensuring exaclty one running job exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		activeJobs := filterActiveJobs(jobs)
		Expect(activeJobs).To(HaveLen(1))

		By("Ensuring the job is replaced with a new one")
		err = waitForJobReplaced(f.Client, f.Namespace.Name, jobs.Items[0].Name)
		Expect(err).NotTo(HaveOccurred())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// shouldn't give us unexpected warnings
	It("should not emit unexpected warnings", func() {
		By("Creating a scheduledjob")
		scheduledJob := newTestScheduledJob("concurrent", "*/1 * * * ?", batch.AllowConcurrent, false)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring at least two jobs and at least one finished job exists by listing jobs explicitly")
		err = waitForJobsAtLeast(f.Client, f.Namespace.Name, 2)
		Expect(err).NotTo(HaveOccurred())
		err = waitForAnyFinishedJob(f.Client, f.Namespace.Name)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring no unexpected event has happened")
		err = checkNoUnexpectedEvents(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})
})

// newTestScheduledJob returns a scheduledjob which does one of several testing behaviors.
func newTestScheduledJob(name, schedule string, concurrencyPolicy batch.ConcurrencyPolicy, sleep bool) *batch.ScheduledJob {
	parallelism := int32(1)
	completions := int32(1)
	sj := &batch.ScheduledJob{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Spec: batch.ScheduledJobSpec{
			Schedule:          schedule,
			ConcurrencyPolicy: concurrencyPolicy,
			JobTemplate: batch.JobTemplateSpec{
				Spec: batch.JobSpec{
					Parallelism: &parallelism,
					Completions: &completions,
					Template: api.PodTemplateSpec{
						Spec: api.PodSpec{
							RestartPolicy: api.RestartPolicyOnFailure,
							Volumes: []api.Volume{
								{
									Name: "data",
									VolumeSource: api.VolumeSource{
										EmptyDir: &api.EmptyDirVolumeSource{},
									},
								},
							},
							Containers: []api.Container{
								{
									Name:  "c",
									Image: "gcr.io/google_containers/busybox:1.24",
									VolumeMounts: []api.VolumeMount{
										{
											MountPath: "/data",
											Name:      "data",
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
	if sleep {
		sj.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command = []string{"sleep", "300"}
	}
	return sj
}

func createScheduledJob(c *client.Client, ns string, scheduledJob *batch.ScheduledJob) (*batch.ScheduledJob, error) {
	return c.Batch().ScheduledJobs(ns).Create(scheduledJob)
}

func getScheduledJob(c *client.Client, ns, name string) (*batch.ScheduledJob, error) {
	return c.Batch().ScheduledJobs(ns).Get(name)
}

func deleteScheduledJob(c *client.Client, ns, name string) error {
	return c.Batch().ScheduledJobs(ns).Delete(name, nil)
}

// Wait for at least given amount of active jobs.
func waitForActiveJobs(c *client.Client, ns, scheduledJobName string, active int) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		curr, err := c.Batch().ScheduledJobs(ns).Get(scheduledJobName)
		if err != nil {
			return false, err
		}
		return len(curr.Status.Active) >= active, nil
	})
}

// Wait for no jobs to appear.
func waitForNoJobs(c *client.Client, ns, jobName string) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		curr, err := c.Batch().ScheduledJobs(ns).Get(jobName)
		if err != nil {
			return false, err
		}

		return len(curr.Status.Active) != 0, nil
	})
}

// Wait for a job to be replaced with a new one.
func waitForJobReplaced(c *client.Client, ns, previousJobName string) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		jobs, err := c.Batch().Jobs(ns).List(api.ListOptions{})
		if err != nil {
			return false, err
		}
		if len(jobs.Items) != 1 {
			return false, fmt.Errorf("More than one job is running")
		}
		return jobs.Items[0].Name != previousJobName, nil
	})
}

// waitForJobsAtLeast waits for at least a number of jobs to appear.
func waitForJobsAtLeast(c *client.Client, ns string, atLeast int) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		jobs, err := c.Batch().Jobs(ns).List(api.ListOptions{})
		if err != nil {
			return false, err
		}
		return len(jobs.Items) >= atLeast, nil
	})
}

// waitForAnyFinishedJob waits for any completed job to appear.
func waitForAnyFinishedJob(c *client.Client, ns string) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		jobs, err := c.Batch().Jobs(ns).List(api.ListOptions{})
		if err != nil {
			return false, err
		}
		for i := range jobs.Items {
			if job.IsJobFinished(&jobs.Items[i]) {
				return true, nil
			}
		}
		return false, nil
	})
}

// checkNoUnexpectedEvents checks unexpected events didn't happen.
// Currently only "UnexpectedJob" is checked.
func checkNoUnexpectedEvents(c *client.Client, ns, scheduledJobName string) error {
	sj, err := c.Batch().ScheduledJobs(ns).Get(scheduledJobName)
	if err != nil {
		return fmt.Errorf("error in getting scheduledjob %s/%s: %v", ns, scheduledJobName, err)
	}
	events, err := c.Events(ns).Search(sj)
	if err != nil {
		return fmt.Errorf("error in listing events: %s", err)
	}
	for _, e := range events.Items {
		if e.Reason == "UnexpectedJob" {
			return fmt.Errorf("found unexpected event: %#v", e)
		}
	}
	return nil
}

func filterActiveJobs(jobs *batch.JobList) (active []*batch.Job) {
	for i := range jobs.Items {
		j := jobs.Items[i]
		if !job.IsJobFinished(&j) {
			active = append(active, &j)
		}
	}
	return
}
<commit_msg>Fix race in scheduledjob e2e<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 e2e

import (
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"k8s.io/kubernetes/pkg/api"
	apierrs "k8s.io/kubernetes/pkg/api/errors"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apis/batch"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/controller/job"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/test/e2e/framework"
)

const (
	// How long to wait for a scheduledjob
	scheduledJobTimeout = 5 * time.Minute
)

var _ = framework.KubeDescribe("ScheduledJob", func() {
	options := framework.FrameworkOptions{
		ClientQPS:    20,
		ClientBurst:  50,
		GroupVersion: &unversioned.GroupVersion{Group: batch.GroupName, Version: "v2alpha1"},
	}
	f := framework.NewFramework("scheduledjob", options, nil)

	BeforeEach(func() {
		if _, err := f.Client.Batch().ScheduledJobs(f.Namespace.Name).List(api.ListOptions{}); err != nil {
			if apierrs.IsNotFound(err) {
				framework.Skipf("Could not find ScheduledJobs resource, skipping test: %#v", err)
			}
		}
	})

	// multiple jobs running at once
	It("should schedule multiple jobs concurrently", func() {
		By("Creating a scheduledjob")
		scheduledJob := newTestScheduledJob("concurrent", "*/1 * * * ?", batch.AllowConcurrent, true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring more than one job is running at a time")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 2)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring at least two running jobs exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		activeJobs := filterActiveJobs(jobs)
		Expect(len(activeJobs) >= 2).To(BeTrue())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// suspended should not schedule jobs
	It("should not schedule jobs when suspended", func() {
		By("Creating a suspended scheduledjob")
		scheduledJob := newTestScheduledJob("suspended", "*/1 * * * ?", batch.AllowConcurrent, true)
		scheduledJob.Spec.Suspend = newBool(true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring no jobs are scheduled")
		err = waitForNoJobs(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).To(HaveOccurred())

		By("Ensuring no job exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		Expect(jobs.Items).To(HaveLen(0))

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// only single active job is allowed for ForbidConcurrent
	It("should not schedule new jobs when ForbidConcurrent", func() {
		By("Creating a ForbidConcurrent scheduledjob")
		scheduledJob := newTestScheduledJob("forbid", "*/1 * * * ?", batch.ForbidConcurrent, true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring a job is scheduled")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 1)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring exactly one is scheduled")
		scheduledJob, err = getScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
		Expect(scheduledJob.Status.Active).Should(HaveLen(1))

		By("Ensuring exaclty one running job exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		activeJobs := filterActiveJobs(jobs)
		Expect(activeJobs).To(HaveLen(1))

		By("Ensuring no more jobs are scheduled")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 2)
		Expect(err).To(HaveOccurred())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// only single active job is allowed for ReplaceConcurrent
	It("should replace jobs when ReplaceConcurrent", func() {
		By("Creating a ReplaceConcurrent scheduledjob")
		scheduledJob := newTestScheduledJob("replace", "*/1 * * * ?", batch.ReplaceConcurrent, true)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring a job is scheduled")
		err = waitForActiveJobs(f.Client, f.Namespace.Name, scheduledJob.Name, 1)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring exactly one is scheduled")
		scheduledJob, err = getScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
		Expect(scheduledJob.Status.Active).Should(HaveLen(1))

		By("Ensuring exaclty one running job exists by listing jobs explicitly")
		jobs, err := f.Client.Batch().Jobs(f.Namespace.Name).List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		activeJobs := filterActiveJobs(jobs)
		Expect(activeJobs).To(HaveLen(1))

		By("Ensuring the job is replaced with a new one")
		err = waitForJobReplaced(f.Client, f.Namespace.Name, jobs.Items[0].Name)
		Expect(err).NotTo(HaveOccurred())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})

	// shouldn't give us unexpected warnings
	It("should not emit unexpected warnings", func() {
		By("Creating a scheduledjob")
		scheduledJob := newTestScheduledJob("concurrent", "*/1 * * * ?", batch.AllowConcurrent, false)
		scheduledJob, err := createScheduledJob(f.Client, f.Namespace.Name, scheduledJob)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring at least two jobs and at least one finished job exists by listing jobs explicitly")
		err = waitForJobsAtLeast(f.Client, f.Namespace.Name, 2)
		Expect(err).NotTo(HaveOccurred())
		err = waitForAnyFinishedJob(f.Client, f.Namespace.Name)
		Expect(err).NotTo(HaveOccurred())

		By("Ensuring no unexpected event has happened")
		err = checkNoUnexpectedEvents(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())

		By("Removing scheduledjob")
		err = deleteScheduledJob(f.Client, f.Namespace.Name, scheduledJob.Name)
		Expect(err).NotTo(HaveOccurred())
	})
})

// newTestScheduledJob returns a scheduledjob which does one of several testing behaviors.
func newTestScheduledJob(name, schedule string, concurrencyPolicy batch.ConcurrencyPolicy, sleep bool) *batch.ScheduledJob {
	parallelism := int32(1)
	completions := int32(1)
	sj := &batch.ScheduledJob{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Spec: batch.ScheduledJobSpec{
			Schedule:          schedule,
			ConcurrencyPolicy: concurrencyPolicy,
			JobTemplate: batch.JobTemplateSpec{
				Spec: batch.JobSpec{
					Parallelism: &parallelism,
					Completions: &completions,
					Template: api.PodTemplateSpec{
						Spec: api.PodSpec{
							RestartPolicy: api.RestartPolicyOnFailure,
							Volumes: []api.Volume{
								{
									Name: "data",
									VolumeSource: api.VolumeSource{
										EmptyDir: &api.EmptyDirVolumeSource{},
									},
								},
							},
							Containers: []api.Container{
								{
									Name:  "c",
									Image: "gcr.io/google_containers/busybox:1.24",
									VolumeMounts: []api.VolumeMount{
										{
											MountPath: "/data",
											Name:      "data",
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
	if sleep {
		sj.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command = []string{"sleep", "300"}
	}
	return sj
}

func createScheduledJob(c *client.Client, ns string, scheduledJob *batch.ScheduledJob) (*batch.ScheduledJob, error) {
	return c.Batch().ScheduledJobs(ns).Create(scheduledJob)
}

func getScheduledJob(c *client.Client, ns, name string) (*batch.ScheduledJob, error) {
	return c.Batch().ScheduledJobs(ns).Get(name)
}

func deleteScheduledJob(c *client.Client, ns, name string) error {
	return c.Batch().ScheduledJobs(ns).Delete(name, nil)
}

// Wait for at least given amount of active jobs.
func waitForActiveJobs(c *client.Client, ns, scheduledJobName string, active int) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		curr, err := c.Batch().ScheduledJobs(ns).Get(scheduledJobName)
		if err != nil {
			return false, err
		}
		return len(curr.Status.Active) >= active, nil
	})
}

// Wait for no jobs to appear.
func waitForNoJobs(c *client.Client, ns, jobName string) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		curr, err := c.Batch().ScheduledJobs(ns).Get(jobName)
		if err != nil {
			return false, err
		}

		return len(curr.Status.Active) != 0, nil
	})
}

// Wait for a job to be replaced with a new one.
func waitForJobReplaced(c *client.Client, ns, previousJobName string) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		jobs, err := c.Batch().Jobs(ns).List(api.ListOptions{})
		if err != nil {
			return false, err
		}
		if len(jobs.Items) > 1 {
			return false, fmt.Errorf("More than one job is running %+v", jobs.Items)
		} else if len(jobs.Items) == 0 {
			framework.Logf("Warning: Found 0 jobs in namespace %v", ns)
			return false, nil
		}
		return jobs.Items[0].Name != previousJobName, nil
	})
}

// waitForJobsAtLeast waits for at least a number of jobs to appear.
func waitForJobsAtLeast(c *client.Client, ns string, atLeast int) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		jobs, err := c.Batch().Jobs(ns).List(api.ListOptions{})
		if err != nil {
			return false, err
		}
		return len(jobs.Items) >= atLeast, nil
	})
}

// waitForAnyFinishedJob waits for any completed job to appear.
func waitForAnyFinishedJob(c *client.Client, ns string) error {
	return wait.Poll(framework.Poll, scheduledJobTimeout, func() (bool, error) {
		jobs, err := c.Batch().Jobs(ns).List(api.ListOptions{})
		if err != nil {
			return false, err
		}
		for i := range jobs.Items {
			if job.IsJobFinished(&jobs.Items[i]) {
				return true, nil
			}
		}
		return false, nil
	})
}

// checkNoUnexpectedEvents checks unexpected events didn't happen.
// Currently only "UnexpectedJob" is checked.
func checkNoUnexpectedEvents(c *client.Client, ns, scheduledJobName string) error {
	sj, err := c.Batch().ScheduledJobs(ns).Get(scheduledJobName)
	if err != nil {
		return fmt.Errorf("error in getting scheduledjob %s/%s: %v", ns, scheduledJobName, err)
	}
	events, err := c.Events(ns).Search(sj)
	if err != nil {
		return fmt.Errorf("error in listing events: %s", err)
	}
	for _, e := range events.Items {
		if e.Reason == "UnexpectedJob" {
			return fmt.Errorf("found unexpected event: %#v", e)
		}
	}
	return nil
}

func filterActiveJobs(jobs *batch.JobList) (active []*batch.Job) {
	for i := range jobs.Items {
		j := jobs.Items[i]
		if !job.IsJobFinished(&j) {
			active = append(active, &j)
		}
	}
	return
}
<|endoftext|>


<commit_before>// errchk $G -e $D/$F.go

// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

type I interface { m() }
type T struct { m func() }
type M struct {}
func (M) m() {}

func main() {
	var t T
	var m M
	var i I

	i = m
	i = t	// ERROR "not a method"
	_ = i
}
<commit_msg>Match gccgo error message.<commit_after>// errchk $G -e $D/$F.go

// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

type I interface { m() }
type T struct { m func() }
type M struct {}
func (M) m() {}

func main() {
	var t T
	var m M
	var i I

	i = m
	i = t	// ERROR "not a method|has no methods"
	_ = i
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"
)

type Service struct {
	Name       string `json:"name"`
	BridgeName string
	BridgeIP   string `json:"bridge-ip"`
	NginxConf  string `json:"nginx-config"`
	Containers []Container
	NginxUpStream
}

type Container struct {
	Name        string
	ServiceName string `json:"service-name"`
	Command     string `json:"command"`
	Pid         int
	IP          string
	StartTime   time.Time
	VEth        string
}

type NginxUpStream struct {
	LoadBalanceType string
	Servers         []string
	UpStreamConfig  string `json:"nginx-upstream"`
}

var services map[string]Service
var containers []Container

const (
	bridgeNameBase = "brocker"
	vethNameBase   = "veth"
)

func (c *Container) setName() {
	value := fmt.Sprintf("%s%s%s", c.Name, c.StartTime, c.Command)
	sha := sha1.New()
	sha.Write([]byte(value))
	c.Name = hex.EncodeToString(sha.Sum(nil))[:8]
}

func (n *NginxUpStream) writeConfig() {
	if _, err := os.Stat(n.UpStreamConfig); os.IsNotExist(err) {
		fmt.Println("Cannot update config", err)
		return
	}

	var buffer bytes.Buffer
	buffer.WriteString("upstream myapp1 {\n")
	buffer.WriteString(n.LoadBalanceType)
	buffer.WriteString(";\n")
	for _, s := range n.Servers {
		buffer.WriteString(fmt.Sprintf("server %s:8080;\n", s))
	}
	buffer.WriteString("\n}")

	if err := ioutil.WriteFile(n.UpStreamConfig, buffer.Bytes(), 0644); err != nil {
		fmt.Println(err)
		return
	}
}

func init() {
	services = make(map[string]Service)
}

func main() {
	http.HandleFunc("/api/v1/service/add", service_add)
	http.HandleFunc("/api/v1/container/run", container_run)
	http.HandleFunc("/api/v1/container/list", container_list)
	http.HandleFunc("/api/v1/container/exec", container_exec)
	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		fmt.Println(err)
	}
}

func service_add(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	var s Service
	if err := json.NewDecoder(r.Body).Decode(&s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[s.Name]; ok {
		http.Error(w, "Service already exists", http.StatusInternalServerError)
		return
	}

	if _, err := os.Stat(s.NginxConf); os.IsNotExist(err) {
		http.Error(w, fmt.Sprintf("Cannot open %s\n%s", s.NginxConf, err.Error()), http.StatusInternalServerError)
		return
	}

	s.BridgeName = fmt.Sprintf("%s%d", bridgeNameBase, len(services)+1)

	if err := service_create_network(s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	path, err := exec.LookPath("nginx")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	c := Container{
		Name:        fmt.Sprintf("%s-nginx", s.Name),
		ServiceName: s.Name,
		Command:     fmt.Sprintf("%s -c %s", path, s.NginxConf),
	}

	s.LoadBalanceType = "least_conn"
	go run(c)

	w.WriteHeader(http.StatusCreated)
}

func container_run(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	var c Container
	if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[c.ServiceName]; ok == false {
		http.Error(w, "Service does not exists", http.StatusInternalServerError)
		return
	}

	go run(c)

	w.WriteHeader(http.StatusCreated)
}

func container_list(w http.ResponseWriter, r *http.Request) {
	if err := json.NewEncoder(w).Encode(containers); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func container_exec(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	data := struct {
		Name string `json:"name"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	for _, c := range containers {
		if c.Name == data.Name {
			w.Write([]byte(fmt.Sprintf("%d", c.Pid)))
			return
		}
	}
}

func service_create_network(s Service) error {
	create_bridge := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type bridge", s.BridgeName), " ")
	set_bridge_up := strings.Split(fmt.Sprintf("/sbin/ip link set %s up", s.BridgeName), " ")
	set_bridge_ip := strings.Split(fmt.Sprintf("/sbin/ifconfig %s %s", s.BridgeName, s.BridgeIP), " ")

	if err := exec.Command(create_bridge[0], create_bridge[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_up[0], set_bridge_up[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_ip[0], set_bridge_ip[1:]...).Run(); err != nil {
		return err
	}

	services[s.Name] = s
	return nil
}

func run(c Container) {
	fmt.Println("running parent")
	s := services[c.ServiceName]
	runcmd := "/home/yup/p/containers/brocker-run/brocker-run"

	cmd := &exec.Cmd{
		Path: runcmd,
		Args: append([]string{runcmd}, c.Command),
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWPID |
			syscall.CLONE_NEWNET,
	}

	if err := cmd.Start(); err != nil {
		fmt.Println(err)
	}

	c.Pid = cmd.Process.Pid
	c.VEth = fmt.Sprintf("%s%d", vethNameBase, len(containers))
	link := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type veth peer name veth1 netns %d", c.VEth, c.Pid), " ")
	if err := exec.Command(link[0], link[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	uplink := strings.Split(fmt.Sprintf("/sbin/ifconfig %s up", c.VEth), " ")
	if err := exec.Command(uplink[0], uplink[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridge := strings.Split(fmt.Sprintf("/sbin/ip link set %s master %s", c.VEth, s.BridgeName), " ")
	if err := exec.Command(bridge[0], bridge[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridgeip := net.ParseIP(s.BridgeIP)
	lastOctet := bridgeip[15] + byte(len(s.Containers)+1)
	ip := net.IPv4(bridgeip[12], bridgeip[13], bridgeip[14], lastOctet)
	c.IP = ip.String()

	if err := execInContainter(fmt.Sprintf("/sbin/ifconfig veth1 %s", ip.String()), c.Pid); err != nil {
		fmt.Println(err)
		return
	}

	c.StartTime = time.Now()
	c.setName()
	containers = append(containers, c)

	s.Containers = append(s.Containers, c)
	services[c.ServiceName] = s

	fmt.Println(cmd.Process.Pid)

	cmd.Wait()
}

func execInContainter(cmd string, pid int) error {
	command := strings.Split(fmt.Sprintf("nsenter --target %d --pid --net %s", pid, cmd), " ")
	if err := exec.Command(command[0], command[1:]...).Run(); err != nil {
		return err
	}

	return nil
}
<commit_msg>Now reloads nginx when container added<commit_after>package main

import (
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"
)

type Service struct {
	Name       string `json:"name"`
	BridgeName string
	BridgeIP   string `json:"bridge-ip"`
	NginxConf  string `json:"nginx-config"`
	Pid        int
	Containers []Container
	NginxUpStream
}

type Container struct {
	Name        string
	ServiceName string `json:"service-name"`
	Command     string `json:"command"`
	Pid         int
	IP          string
	StartTime   time.Time
	VEth        string
}

type NginxUpStream struct {
	LoadBalanceType string
	Servers         []string
	UpStreamConfig  string `json:"nginx-upstream"`
}

var services map[string]Service
var containers []Container

const (
	bridgeNameBase = "brocker"
	vethNameBase   = "veth"
)

func (c *Container) setName() {
	value := fmt.Sprintf("%s%s%s", c.Name, c.StartTime, c.Command)
	sha := sha1.New()
	sha.Write([]byte(value))
	c.Name = hex.EncodeToString(sha.Sum(nil))[:8]
}

func (s *Service) reload() {
	if err := execInContainter(fmt.Sprintf("/usr/sbin/nginx -s reload -c %s", s.NginxConf), s.Pid); err != nil {
		fmt.Println("Cannot reload nginx: ", err)
		return
	}
}

func (n *NginxUpStream) writeConfig() {
	if _, err := os.Stat(n.UpStreamConfig); os.IsNotExist(err) {
		fmt.Println("Cannot update config", err)
		return
	}

	var buffer bytes.Buffer
	buffer.WriteString("upstream myapp1 {\n")
	buffer.WriteString(n.LoadBalanceType)
	buffer.WriteString(";\n")
	for _, s := range n.Servers {
		buffer.WriteString(fmt.Sprintf("server %s;\n", s))
	}
	buffer.WriteString("\n}")

	if err := ioutil.WriteFile(n.UpStreamConfig, buffer.Bytes(), 0644); err != nil {
		fmt.Println(err)
		return
	}
}

func init() {
	services = make(map[string]Service)
}

func main() {
	http.HandleFunc("/api/v1/service/add", service_add)
	http.HandleFunc("/api/v1/container/run", container_run)
	http.HandleFunc("/api/v1/container/list", container_list)
	http.HandleFunc("/api/v1/container/exec", container_exec)
	err := http.ListenAndServe(":3000", nil)
	if err != nil {
		fmt.Println(err)
	}
}

func service_add(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	var s Service
	if err := json.NewDecoder(r.Body).Decode(&s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[s.Name]; ok {
		http.Error(w, "Service already exists", http.StatusInternalServerError)
		return
	}

	if _, err := os.Stat(s.NginxConf); os.IsNotExist(err) {
		http.Error(w, fmt.Sprintf("Cannot open %s\n%s", s.NginxConf, err.Error()), http.StatusInternalServerError)
		return
	}

	s.BridgeName = fmt.Sprintf("%s%d", bridgeNameBase, len(services)+1)

	s.LoadBalanceType = "least_conn"
	if err := service_create_network(s); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	path, err := exec.LookPath("nginx")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	c := Container{
		Name:        fmt.Sprintf("%s-nginx", s.Name),
		ServiceName: s.Name,
		Command:     fmt.Sprintf("%s -c %s", path, s.NginxConf),
	}

	go run(c, true)

	w.WriteHeader(http.StatusCreated)
}

func container_run(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	var c Container
	if err := json.NewDecoder(r.Body).Decode(&c); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if _, ok := services[c.ServiceName]; ok == false {
		http.Error(w, "Service does not exists", http.StatusInternalServerError)
		return
	}

	go run(c, false)

	w.WriteHeader(http.StatusCreated)
}

func container_list(w http.ResponseWriter, r *http.Request) {
	if err := json.NewEncoder(w).Encode(containers); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func container_exec(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid Request!", http.StatusMethodNotAllowed)
		return
	}

	data := struct {
		Name string `json:"name"`
	}{}
	if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	for _, c := range containers {
		if c.Name == data.Name {
			w.Write([]byte(fmt.Sprintf("%d", c.Pid)))
			return
		}
	}
}

func service_create_network(s Service) error {
	create_bridge := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type bridge", s.BridgeName), " ")
	set_bridge_up := strings.Split(fmt.Sprintf("/sbin/ip link set %s up", s.BridgeName), " ")
	set_bridge_ip := strings.Split(fmt.Sprintf("/sbin/ifconfig %s %s", s.BridgeName, s.BridgeIP), " ")

	if err := exec.Command(create_bridge[0], create_bridge[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_up[0], set_bridge_up[1:]...).Run(); err != nil {
		return err
	}

	if err := exec.Command(set_bridge_ip[0], set_bridge_ip[1:]...).Run(); err != nil {
		return err
	}

	services[s.Name] = s
	return nil
}

func run(c Container, isNginx bool) {
	fmt.Println("running parent")
	s := services[c.ServiceName]
	runcmd := "/home/yup/p/containers/brocker-run/brocker-run"

	cmd := &exec.Cmd{
		Path: runcmd,
		Args: append([]string{runcmd}, c.Command),
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWPID |
			syscall.CLONE_NEWNET,
	}

	if err := cmd.Start(); err != nil {
		fmt.Println(err)
	}

	c.Pid = cmd.Process.Pid
	c.VEth = fmt.Sprintf("%s%d", vethNameBase, len(containers))
	link := strings.Split(fmt.Sprintf("/sbin/ip link add name %s type veth peer name veth1 netns %d", c.VEth, c.Pid), " ")
	if err := exec.Command(link[0], link[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	uplink := strings.Split(fmt.Sprintf("/sbin/ifconfig %s up", c.VEth), " ")
	if err := exec.Command(uplink[0], uplink[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridge := strings.Split(fmt.Sprintf("/sbin/ip link set %s master %s", c.VEth, s.BridgeName), " ")
	if err := exec.Command(bridge[0], bridge[1:]...).Run(); err != nil {
		fmt.Println(err)
		return
	}

	bridgeip := net.ParseIP(s.BridgeIP)
	lastOctet := bridgeip[15] + byte(len(s.Containers)+1)
	ip := net.IPv4(bridgeip[12], bridgeip[13], bridgeip[14], lastOctet)
	c.IP = ip.String()

	if err := execInContainter(fmt.Sprintf("/sbin/ifconfig veth1 %s", ip.String()), c.Pid); err != nil {
		fmt.Println(err)
		return
	}

	c.StartTime = time.Now()
	c.setName()
	containers = append(containers, c)

	s.Containers = append(s.Containers, c)
	if isNginx {
		s.Pid = c.Pid
	} else {
		s.Servers = append(s.Servers, fmt.Sprintf("%s:8080", c.IP))
		s.writeConfig()
		s.reload()
	}
	services[c.ServiceName] = s

	fmt.Println(cmd.Process.Pid)

	cmd.Wait()
}

func execInContainter(cmd string, pid int) error {
	command := strings.Split(fmt.Sprintf("nsenter --target %d --pid --net %s", pid, cmd), " ")
	if err := exec.Command(command[0], command[1:]...).Run(); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package broker

import (
	"fmt"
	"github.com/intel-data/types-cf"
	"log"
	"net/http"
	"os"
	"os/signal"
)

type broker struct {
	router *router
}

// New creates a loaded instance o the broker
func New(p cf.ServiceProvider) (*broker, error) {
	return &broker{
		router: newRouter(newHandler(p)),
	}, nil
}

// Start the broker
func (b *broker) Start() {

	addr := fmt.Sprintf("%s:%d", Config.CFEnv.Host, Config.CFEnv.Port)
	log.Printf("starting: %s", addr)

	sigCh := make(chan os.Signal, 1)

	// make sure we can shutdown gracefully
	signal.Notify(sigCh, os.Interrupt)

	errCh := make(chan error, 1)

	go func() {
		errCh <- http.ListenAndServe(addr, b.router)
	}()

	// non blocking as some of these cf ops are kind of lengthy
	select {
	case err := <-errCh:
		log.Printf("broker error: %v", err)
	case sig := <-sigCh:
		var _ = sig
		log.Print("broker done")
	}

}
<commit_msg>remove warning around exported Broker<commit_after>package broker

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"

	"github.com/intel-data/types-cf"
)

// Broker represents a running CF Service Broker API
type Broker struct {
	router *router
}

// New creates a loaded instance o the broker
func New(p cf.ServiceProvider) (*Broker, error) {
	return &Broker{
		router: newRouter(newHandler(p)),
	}, nil
}

// Start the broker
func (b *Broker) Start() {

	addr := fmt.Sprintf("%s:%d", Config.CFEnv.Host, Config.CFEnv.Port)
	log.Printf("starting: %s", addr)

	sigCh := make(chan os.Signal, 1)

	// make sure we can shutdown gracefully
	signal.Notify(sigCh, os.Interrupt)

	errCh := make(chan error, 1)

	go func() {
		errCh <- http.ListenAndServe(addr, b.router)
	}()

	// non blocking as some of these cf ops are kind of lengthy
	select {
	case err := <-errCh:
		log.Printf("broker error: %v", err)
	case sig := <-sigCh:
		var _ = sig
		log.Print("broker done")
	}

}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/networkservicemesh/networkservicemesh/pkg/tools"
	"github.com/sirupsen/logrus"
	"k8s.io/api/admission/v1beta1"
	admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/kubernetes/pkg/apis/core/v1"
)

const (
	certFile = "/etc/webhook/certs/cert.pem"
	keyFile  = "/etc/webhook/certs/key.pem"
)

type WebhookServer struct {
	server *http.Server
}

type patchOperation struct {
	Op    string      `json:"op"`
	Path  string      `json:"path"`
	Value interface{} `json:"value,omitempty"`
}

var (
	runtimeScheme = runtime.NewScheme()
	codecs        = serializer.NewCodecFactory(runtimeScheme)
	deserializer  = codecs.UniversalDeserializer()
)

var (
	ignoredNamespaces = []string{
		metav1.NamespaceSystem,
		metav1.NamespacePublic,
	}
)

var (
	repo          string
	initContainer string
	tag           string
)

const (
	nsmAnnotationKey = "ns.networkservicemesh.io"

	repoEnv          = "REPO"
	initContainerEnv = "INITCONTAINER"
	tagEnv           = "TAG"

	repoDefault          = "networkservicemesh"
	initContainerDefault = "nsc"
	tagDefault           = "latest"
)

func init() {
	_ = corev1.AddToScheme(runtimeScheme)
	_ = admissionregistrationv1beta1.AddToScheme(runtimeScheme)
	// defaulting with webhooks:
	// https://github.com/kubernetes/kubernetes/issues/57982
	_ = v1.AddToScheme(runtimeScheme)
}

func getAnnotationValue(ignoredList []string, metadata *metav1.ObjectMeta) (string, bool) {
	// skip special kubernetes system namespaces
	for _, namespace := range ignoredList {
		if metadata.Namespace == namespace {
			logrus.Infof("Skip validation for %v for it's in special namespace:%v", metadata.Name, metadata.Namespace)
			return "", false
		}
	}

	annotations := metadata.GetAnnotations()
	if annotations == nil {
		return "", false
	}

	value, ok := annotations[nsmAnnotationKey]
	return value, ok
}

func validateAnnotationValue(value string) error {
	urls, err := tools.ParseAnnotationValue(value)
	logrus.Infof("Annotation nsurls: %v", urls)
	return err
}

func createPatch(annotationValue string, path string) ([]byte, error) {
	var patch []patchOperation

	value := []interface{}{
		map[string]interface{}{
			"name":            "nsc",
			"image":           fmt.Sprintf("%s/%s:%s", repo, initContainer, tag),
			"imagePullPolicy": "IfNotPresent",
			"env": []interface{}{
				map[string]string{
					"name":  "NS_NETWORKSERVICEMESH_IO",
					"value": annotationValue,
				},
			},
			"resources": map[string]interface{}{
				"limits": map[string]interface{}{
					"networkservicemesh.io/socket": 1,
				},
			},
		},
	}

	patch = append(patch, patchOperation{
		Op:    "add",
		Path:  path,
		Value: value,
	})

	return json.Marshal(patch)
}

func (whsvr *WebhookServer) mutate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
	req := ar.Request

	logrus.Infof("AdmissionReview for Kind=%v, Namespace=%v Name=%v UID=%v patchOperation=%v UserInfo=%v",
		req.Kind, req.Namespace, req.Name, req.UID, req.Operation, req.UserInfo)

	var meta *metav1.ObjectMeta
	var path string

	switch req.Kind.Kind {
	case "Deployment":
		var deployment appsv1.Deployment
		if err := json.Unmarshal(req.Object.Raw, &deployment); err != nil {
			logrus.Errorf("Could not unmarshal raw object: %v", err)
			return &v1beta1.AdmissionResponse{
				Result: &metav1.Status{
					Message: err.Error(),
				},
			}
		}
		meta = &deployment.ObjectMeta
		path = "/spec/template/spec/initContainers"
	case "Pod":
		var pod corev1.Pod
		if err := json.Unmarshal(req.Object.Raw, &pod); err != nil {
			logrus.Errorf("Could not unmarshal raw object: %v", err)
			return &v1beta1.AdmissionResponse{
				Result: &metav1.Status{
					Message: err.Error(),
				},
			}
		}
		meta = &pod.ObjectMeta
		path = "/spec/initContainers"
	default:
		return &v1beta1.AdmissionResponse{
			Allowed: true,
		}
	}

	value, ok := getAnnotationValue(ignoredNamespaces, meta)

	if !ok {
		logrus.Infof("Skipping validation for %s/%s due to policy check", meta.Namespace, meta.Name)
		return &v1beta1.AdmissionResponse{
			Allowed: true,
		}
	}

	err := validateAnnotationValue(value)
	if err != nil {
		return &v1beta1.AdmissionResponse{
			Result: &metav1.Status{
				Message: err.Error(),
			},
		}
	}

	patchBytes, err := createPatch(value, path)
	if err != nil {
		return &v1beta1.AdmissionResponse{
			Result: &metav1.Status{
				Message: err.Error(),
			},
		}
	}

	logrus.Infof("AdmissionResponse: patch=%v\n", string(patchBytes))
	return &v1beta1.AdmissionResponse{
		Allowed: true,
		Patch:   patchBytes,
		PatchType: func() *v1beta1.PatchType {
			pt := v1beta1.PatchTypeJSONPatch
			return &pt
		}(),
	}
}

func (whsvr *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
	var body []byte
	if r.Body != nil {
		if data, err := ioutil.ReadAll(r.Body); err == nil {
			body = data
		}
	}
	if len(body) == 0 {
		logrus.Error("empty body")
		http.Error(w, "empty body", http.StatusBadRequest)
		return
	}

	// verify the content type is accurate
	contentType := r.Header.Get("Content-Type")
	if contentType != "application/json" {
		logrus.Errorf("Content-Type=%s, expect application/json", contentType)
		http.Error(w, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
		return
	}

	var admissionResponse *v1beta1.AdmissionResponse
	ar := v1beta1.AdmissionReview{}
	if _, _, err := deserializer.Decode(body, nil, &ar); err != nil {
		logrus.Errorf("Can't decode body: %v", err)
		admissionResponse = &v1beta1.AdmissionResponse{
			Result: &metav1.Status{
				Message: err.Error(),
			},
		}
	} else {
		admissionResponse = whsvr.mutate(&ar)
	}

	admissionReview := v1beta1.AdmissionReview{}
	if admissionResponse != nil {
		admissionReview.Response = admissionResponse
		if ar.Request != nil {
			admissionReview.Response.UID = ar.Request.UID
		}
	}

	resp, err := json.Marshal(admissionReview)
	if err != nil {
		logrus.Errorf("Can't encode response: %v", err)
		http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
	}
	if _, err := w.Write(resp); err != nil {
		logrus.Errorf("Can't write response: %v", err)
		http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
	}
}

func main() {
	logrus.Info("Admission Webhook starting...")

	repo = os.Getenv(repoEnv)
	if repo == "" {
		repo = repoDefault
	}

	initContainer = os.Getenv(initContainerEnv)
	if initContainer == "" {
		initContainer = initContainerDefault
	}

	tag = os.Getenv(tagEnv)
	if tag == "" {
		tag = tagDefault
	}

	pair, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		logrus.Fatalf("Failed to load key pair: %v", err)
	}

	whsvr := &WebhookServer{
		server: &http.Server{
			Addr:      fmt.Sprintf(":%v", 443),
			TLSConfig: &tls.Config{Certificates: []tls.Certificate{pair}},
		},
	}

	// define http server and server handler
	mux := http.NewServeMux()
	mux.HandleFunc("/mutate", whsvr.serve)
	whsvr.server.Handler = mux

	// start webhook server in new routine
	go func() {
		if err := whsvr.server.ListenAndServeTLS("", ""); err != nil {
			logrus.Fatalf("Failed to listen and serve webhook server: %v", err)
		}
	}()

	logrus.Info("Server started")

	// listening OS shutdown singal
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	<-signalChan
}
<commit_msg>Admission web hook will check if the pod is already processed (#763)<commit_after>package main

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/networkservicemesh/networkservicemesh/pkg/tools"
	"github.com/sirupsen/logrus"
	"k8s.io/api/admission/v1beta1"
	admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	v1 "k8s.io/kubernetes/pkg/apis/core/v1"
)

const (
	certFile = "/etc/webhook/certs/cert.pem"
	keyFile  = "/etc/webhook/certs/key.pem"
)

type WebhookServer struct {
	server *http.Server
}

type patchOperation struct {
	Op    string      `json:"op"`
	Path  string      `json:"path"`
	Value interface{} `json:"value,omitempty"`
}

var (
	runtimeScheme = runtime.NewScheme()
	codecs        = serializer.NewCodecFactory(runtimeScheme)
	deserializer  = codecs.UniversalDeserializer()
)

var (
	ignoredNamespaces = []string{
		metav1.NamespaceSystem,
		metav1.NamespacePublic,
	}
)

var (
	repo          string
	initContainer string
	tag           string
)

const (
	nsmAnnotationKey = "ns.networkservicemesh.io"

	repoEnv          = "REPO"
	initContainerEnv = "INITCONTAINER"
	tagEnv           = "TAG"

	repoDefault          = "networkservicemesh"
	initContainerDefault = "nsc"
	tagDefault           = "latest"

	pathDeploymentInitContainers = "/spec/template/spec/initContainers"
	pathPodInitContainers        = "/spec/initContainers"
)

func init() {
	_ = corev1.AddToScheme(runtimeScheme)
	_ = admissionregistrationv1beta1.AddToScheme(runtimeScheme)
	// defaulting with webhooks:
	// https://github.com/kubernetes/kubernetes/issues/57982
	_ = v1.AddToScheme(runtimeScheme)
}

func getAnnotationValue(ignoredList []string, metadata *metav1.ObjectMeta, spec *corev1.PodSpec) (string, bool) {

	// check if InitContainer already injected
	for _, c := range spec.InitContainers {
		if c.Name == "nsc" {
			return "", false
		}
	}

	// skip special kubernetes system namespaces
	for _, namespace := range ignoredList {
		if metadata.Namespace == namespace {
			logrus.Infof("Skip validation for %v for it's in special namespace:%v", metadata.Name, metadata.Namespace)
			return "", false
		}
	}

	annotations := metadata.GetAnnotations()
	if annotations == nil {
		return "", false
	}

	value, ok := annotations[nsmAnnotationKey]
	return value, ok
}

func validateAnnotationValue(value string) error {
	urls, err := tools.ParseAnnotationValue(value)
	logrus.Infof("Annotation nsurls: %v", urls)
	return err
}

func createPatch(annotationValue string, path string) ([]byte, error) {
	var patch []patchOperation

	value := []interface{}{
		map[string]interface{}{
			"name":            "nsc",
			"image":           fmt.Sprintf("%s/%s:%s", repo, initContainer, tag),
			"imagePullPolicy": "IfNotPresent",
			"env": []interface{}{
				map[string]string{
					"name":  "NS_NETWORKSERVICEMESH_IO",
					"value": annotationValue,
				},
			},
			"resources": map[string]interface{}{
				"limits": map[string]interface{}{
					"networkservicemesh.io/socket": 1,
				},
			},
		},
	}

	patch = append(patch, patchOperation{
		Op:    "add",
		Path:  path,
		Value: value,
	})

	return json.Marshal(patch)
}

func (whsvr *WebhookServer) mutate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse {
	req := ar.Request

	logrus.Infof("AdmissionReview for Kind=%v, Namespace=%v Name=%v UID=%v patchOperation=%v UserInfo=%v",
		req.Kind, req.Namespace, req.Name, req.UID, req.Operation, req.UserInfo)

	var meta *metav1.ObjectMeta
	var spec *corev1.PodSpec
	var path string

	switch req.Kind.Kind {
	case "Deployment":
		var deployment appsv1.Deployment
		if err := json.Unmarshal(req.Object.Raw, &deployment); err != nil {
			logrus.Errorf("Could not unmarshal raw object: %v", err)
			return &v1beta1.AdmissionResponse{
				Result: &metav1.Status{
					Message: err.Error(),
				},
			}
		}
		meta = &deployment.ObjectMeta
		spec = &deployment.Spec.Template.Spec
		path = pathDeploymentInitContainers
	case "Pod":
		var pod corev1.Pod
		if err := json.Unmarshal(req.Object.Raw, &pod); err != nil {
			logrus.Errorf("Could not unmarshal raw object: %v", err)
			return &v1beta1.AdmissionResponse{
				Result: &metav1.Status{
					Message: err.Error(),
				},
			}
		}
		meta = &pod.ObjectMeta
		spec = &pod.Spec
		path = pathPodInitContainers
	default:
		return &v1beta1.AdmissionResponse{
			Allowed: true,
		}
	}

	value, ok := getAnnotationValue(ignoredNamespaces, meta, spec)

	if !ok {
		logrus.Infof("Skipping validation for %s/%s due to policy check", meta.Namespace, meta.Name)
		return &v1beta1.AdmissionResponse{
			Allowed: true,
		}
	}

	err := validateAnnotationValue(value)
	if err != nil {
		return &v1beta1.AdmissionResponse{
			Result: &metav1.Status{
				Message: err.Error(),
			},
		}
	}

	patchBytes, err := createPatch(value, path)
	if err != nil {
		return &v1beta1.AdmissionResponse{
			Result: &metav1.Status{
				Message: err.Error(),
			},
		}
	}

	logrus.Infof("AdmissionResponse: patch=%v\n", string(patchBytes))
	return &v1beta1.AdmissionResponse{
		Allowed: true,
		Patch:   patchBytes,
		PatchType: func() *v1beta1.PatchType {
			pt := v1beta1.PatchTypeJSONPatch
			return &pt
		}(),
	}
}

func (whsvr *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
	var body []byte
	if r.Body != nil {
		if data, err := ioutil.ReadAll(r.Body); err == nil {
			body = data
		}
	}
	if len(body) == 0 {
		logrus.Error("empty body")
		http.Error(w, "empty body", http.StatusBadRequest)
		return
	}

	// verify the content type is accurate
	contentType := r.Header.Get("Content-Type")
	if contentType != "application/json" {
		logrus.Errorf("Content-Type=%s, expect application/json", contentType)
		http.Error(w, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
		return
	}

	var admissionResponse *v1beta1.AdmissionResponse
	ar := v1beta1.AdmissionReview{}
	if _, _, err := deserializer.Decode(body, nil, &ar); err != nil {
		logrus.Errorf("Can't decode body: %v", err)
		admissionResponse = &v1beta1.AdmissionResponse{
			Result: &metav1.Status{
				Message: err.Error(),
			},
		}
	} else {
		admissionResponse = whsvr.mutate(&ar)
	}

	admissionReview := v1beta1.AdmissionReview{}
	if admissionResponse != nil {
		admissionReview.Response = admissionResponse
		if ar.Request != nil {
			admissionReview.Response.UID = ar.Request.UID
		}
	}

	resp, err := json.Marshal(admissionReview)
	if err != nil {
		logrus.Errorf("Can't encode response: %v", err)
		http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
	}
	if _, err := w.Write(resp); err != nil {
		logrus.Errorf("Can't write response: %v", err)
		http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
	}
}

func main() {
	logrus.Info("Admission Webhook starting...")

	repo = os.Getenv(repoEnv)
	if repo == "" {
		repo = repoDefault
	}

	initContainer = os.Getenv(initContainerEnv)
	if initContainer == "" {
		initContainer = initContainerDefault
	}

	tag = os.Getenv(tagEnv)
	if tag == "" {
		tag = tagDefault
	}

	pair, err := tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		logrus.Fatalf("Failed to load key pair: %v", err)
	}

	whsvr := &WebhookServer{
		server: &http.Server{
			Addr:      fmt.Sprintf(":%v", 443),
			TLSConfig: &tls.Config{Certificates: []tls.Certificate{pair}},
		},
	}

	// define http server and server handler
	mux := http.NewServeMux()
	mux.HandleFunc("/mutate", whsvr.serve)
	whsvr.server.Handler = mux

	// start webhook server in new routine
	go func() {
		if err := whsvr.server.ListenAndServeTLS("", ""); err != nil {
			logrus.Fatalf("Failed to listen and serve webhook server: %v", err)
		}
	}()

	logrus.Info("Server started")

	// listening OS shutdown singal
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	<-signalChan
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"regexp"
	"gopkg.in/mgo.v2/bson"
	"strings"
	"encoding/json"
	"github.com/gin-gonic/contrib/sessions"
	"github.com/markbates/goth/gothic"
	"github.com/markbates/goth"
	"github.com/markbates/goth/providers/facebook"
	"github.com/markbates/goth/providers/github"
	"gopkg.in/mgo.v2"
	"html/template"
)

func init() {
	gothic.Store = store
}

func startOAuth(c *gin.Context) {
	// don't like that hack
	// gothic was written for another path
	// I just put provider query
	provider := c.Param("provider")
	c.Request.URL.RawQuery += "provider=" + provider
	_, err := goth.GetProvider(provider)
	if err != nil {
		callbackURL := "http://" + c.Request.Host + "/signup_/" + provider + "/callback"
		if provider == "github" {
			goth.UseProviders(
				github.New(config.Socials[provider].Key, config.Socials[provider].Secret, callbackURL),
			)
		}
		if provider == "facebook" {
			goth.UseProviders(
				facebook.New(config.Socials[provider].Key, config.Socials[provider].Secret, callbackURL),
			)
		}
	}
	gothic.BeginAuthHandler(c.Writer, c.Request)
}

func CompleteUserAuth(c *gin.Context) {
	// gothic was written for another path
	// i just put provider query
	provider := c.Param("provider")
	c.Request.URL.RawQuery += "&provider=" + provider
	// print our state string to the console. Ideally, you should verify
	// that it's the same string as the one you set in `setState`
	userGoth, err := gothic.CompleteUserAuth(c.Writer, c.Request)
	if err != nil {
		render, _ := TemplateStorage["/signup/"]
		render.Data = c.Keys
		c.Render(http.StatusOK, render)
		return
	}
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(USERS)
	user := User{}
	err = collection.Find(bson.M{provider + ".id": userGoth.UserID}).One(&user)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		session := sessions.Default(c)
		session.Set("oauthMessage", "We found a user linked to your " + provider + " account")
		session.Save()
		c.Redirect(http.StatusFound, "/signup/")
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}
	userGothString, err := json.Marshal(userGoth)
	if err != nil {
		panic(err)
	}

	sessionCookie := sessions.Default(c)
	sessionCookie.Set("socialProfile", string(userGothString))
	sessionCookie.Set("provider", provider)
	sessionCookie.Save()

	c.Set("email", template.JS(userGoth.Email))
	render, _ := TemplateStorage["/signup/social/"]
	render.Data = c.Keys
	c.Render(http.StatusOK, render)
}

func SignUpSocial(c *gin.Context) {
	response := Response{}
	defer response.Recover(c)

	decoder := json.NewDecoder(c.Request.Body)
	err := decoder.Decode(&response)
	if err != nil {
		panic(err)
	}
	response.Errors = []string{}
	response.ErrFor = make(map[string]string)

	// validate
	response.ValidateEmail()
	if response.HasErrors() {
		response.Fail(c)
		return
	}

	// check duplicate
	session := sessions.Default(c)

	socialProfile_, ok := session.Get("socialProfile").(string)
	if !ok || len(socialProfile_) == 0 {
		response.Errors = append(response.Errors, "something went wrong. Refresh please")
		response.Fail(c)
		return
	}
	socialProfile := goth.User{}
	err = json.Unmarshal([]byte(socialProfile_), &socialProfile)
	if err != nil {
		panic(err)
	}

	// duplicateEmailCheck
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(USERS)
	user := User{}
	println(response.Email)
	err = collection.Find(bson.M{"email": response.Email}).One(&user)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		response.ErrFor["email"] = "email already registered"
		response.Fail(c)
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}
	// duplicateUsernameCheck
	var username string
	if len(socialProfile.Name) != 0 {
		username = socialProfile.Name
	} else if len(socialProfile.UserID) != 0 {
		username = socialProfile.UserID
	}
	reg, err := regexp.Compile(`/[^a-zA-Z0-9\-\_]/g`)
	if err != nil {
		panic(err)
	}
	usernameSrc := []byte(username)
	reg.ReplaceAll(usernameSrc, []byte(""))
	username = string(usernameSrc)
	if len(user.Username) != 0 {
		response.Fail(c)
	}
	err = collection.Find(bson.M{"username": username}).One(&user)
	if err == nil {
		username += "-gowallUser"
	} else if err != mgo.ErrNotFound {
		panic(err)
	}

	// createUser
	user.ID = bson.NewObjectId()
	user.IsActive = "yes"
	user.Username = user.ID.Hex()
	user.Email = strings.ToLower(response.Email)
	user.Search = []string{username, response.Email}
	user.updateProvider(socialProfile)
	err = collection.Insert(user)
	if err != nil {
		panic(err)
		return
	}

	// createAccount
	account := Account{}

	account.ID = bson.NewObjectId()

	user.Roles.Account = account.ID

	err = collection.UpdateId(user.ID, user)
	if err != nil {
		panic(err)
		return
	}

	if config.RequireAccountVerification {
		account.IsVerified = "no"
	} else {
		account.IsVerified = "yes"
	}
	account.Name.Full = username
	account.User.ID = user.ID
	account.User.Name = user.Username
	account.Search = []string{username}

	collection = db.C(ACCOUNTS)
	err = collection.Insert(account)
	if err != nil {
		panic(err)
		return
	}

	// sendWelcomeEmail
	go func() {
		c.Set("Username", response.Username)
		c.Set("Email", response.Email)
		c.Set("LoginURL", "http://" + c.Request.Host + "/login/")

		mailConf := MailConfig{}
		mailConf.Data = c.Keys
		mailConf.From = config.SMTP.From.Name + " <" + config.SMTP.From.Address + ">"
		mailConf.To = config.SystemEmail
		mailConf.Subject = "Your " + config.ProjectName + " Account"
		mailConf.ReplyTo = response.Email
		mailConf.HtmlPath = "views/signup/email-html.html"

		if err := mailConf.SendMail(); err != nil {
			println("Error Sending Welcome Email: " + err.Error())
		}
	}()

	// logUserIn
	user.login(c)

	response.Success = true
	c.JSON(http.StatusOK, response)
}<commit_msg>[providers] fix callbackURL<commit_after>package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"regexp"
	"gopkg.in/mgo.v2/bson"
	"strings"
	"encoding/json"
	"github.com/gin-gonic/contrib/sessions"
	"github.com/markbates/goth/gothic"
	"github.com/markbates/goth"
	"github.com/markbates/goth/providers/facebook"
	"github.com/markbates/goth/providers/github"
	"gopkg.in/mgo.v2"
	"html/template"
)

func init() {
	gothic.Store = store
}

func startOAuth(c *gin.Context) {
	// don't like that hack
	// gothic was written for another path
	// I just put provider query
	provider := c.Param("provider")
	c.Request.URL.RawQuery += "provider=" + provider
	_, err := goth.GetProvider(provider)
	if err != nil {
		callbackURL := "http://" + c.Request.Host + "/signup/" + provider + "/callback"
		if provider == "github" {
			goth.UseProviders(
				github.New(config.Socials[provider].Key, config.Socials[provider].Secret, callbackURL),
			)
		}
		if provider == "facebook" {
			goth.UseProviders(
				facebook.New(config.Socials[provider].Key, config.Socials[provider].Secret, callbackURL),
			)
		}
	}
	gothic.BeginAuthHandler(c.Writer, c.Request)
}

func CompleteUserAuth(c *gin.Context) {
	// gothic was written for another path
	// i just put provider query
	provider := c.Param("provider")
	c.Request.URL.RawQuery += "&provider=" + provider
	// print our state string to the console. Ideally, you should verify
	// that it's the same string as the one you set in `setState`
	userGoth, err := gothic.CompleteUserAuth(c.Writer, c.Request)
	if err != nil {
		render, _ := TemplateStorage["/signup/"]
		render.Data = c.Keys
		c.Render(http.StatusOK, render)
		return
	}
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(USERS)
	user := User{}
	err = collection.Find(bson.M{provider + ".id": userGoth.UserID}).One(&user)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		session := sessions.Default(c)
		session.Set("oauthMessage", "We found a user linked to your " + provider + " account")
		session.Save()
		c.Redirect(http.StatusFound, "/signup/")
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}
	userGothString, err := json.Marshal(userGoth)
	if err != nil {
		panic(err)
	}

	sessionCookie := sessions.Default(c)
	sessionCookie.Set("socialProfile", string(userGothString))
	sessionCookie.Set("provider", provider)
	sessionCookie.Save()

	c.Set("email", template.JS(userGoth.Email))
	render, _ := TemplateStorage["/signup/social/"]
	render.Data = c.Keys
	c.Render(http.StatusOK, render)
}

func SignUpSocial(c *gin.Context) {
	response := Response{}
	defer response.Recover(c)

	decoder := json.NewDecoder(c.Request.Body)
	err := decoder.Decode(&response)
	if err != nil {
		panic(err)
	}
	response.Errors = []string{}
	response.ErrFor = make(map[string]string)

	// validate
	response.ValidateEmail()
	if response.HasErrors() {
		response.Fail(c)
		return
	}

	// check duplicate
	session := sessions.Default(c)

	socialProfile_, ok := session.Get("socialProfile").(string)
	if !ok || len(socialProfile_) == 0 {
		response.Errors = append(response.Errors, "something went wrong. Refresh please")
		response.Fail(c)
		return
	}
	socialProfile := goth.User{}
	err = json.Unmarshal([]byte(socialProfile_), &socialProfile)
	if err != nil {
		panic(err)
	}

	// duplicateEmailCheck
	db := getMongoDBInstance()
	defer db.Session.Close()
	collection := db.C(USERS)
	user := User{}
	println(response.Email)
	err = collection.Find(bson.M{"email": response.Email}).One(&user)
	// we expect err == mgo.ErrNotFound for success
	if err == nil {
		response.ErrFor["email"] = "email already registered"
		response.Fail(c)
		return
	} else if err != mgo.ErrNotFound {
		panic(err)
	}
	// duplicateUsernameCheck
	var username string
	if len(socialProfile.Name) != 0 {
		username = socialProfile.Name
	} else if len(socialProfile.UserID) != 0 {
		username = socialProfile.UserID
	}
	reg, err := regexp.Compile(`/[^a-zA-Z0-9\-\_]/g`)
	if err != nil {
		panic(err)
	}
	usernameSrc := []byte(username)
	reg.ReplaceAll(usernameSrc, []byte(""))
	username = string(usernameSrc)
	if len(user.Username) != 0 {
		response.Fail(c)
	}
	err = collection.Find(bson.M{"username": username}).One(&user)
	if err == nil {
		username += "-gowallUser"
	} else if err != mgo.ErrNotFound {
		panic(err)
	}

	// createUser
	user.ID = bson.NewObjectId()
	user.IsActive = "yes"
	user.Username = user.ID.Hex()
	user.Email = strings.ToLower(response.Email)
	user.Search = []string{username, response.Email}
	user.updateProvider(socialProfile)
	err = collection.Insert(user)
	if err != nil {
		panic(err)
		return
	}

	// createAccount
	account := Account{}

	account.ID = bson.NewObjectId()

	user.Roles.Account = account.ID

	err = collection.UpdateId(user.ID, user)
	if err != nil {
		panic(err)
		return
	}

	if config.RequireAccountVerification {
		account.IsVerified = "no"
	} else {
		account.IsVerified = "yes"
	}
	account.Name.Full = username
	account.User.ID = user.ID
	account.User.Name = user.Username
	account.Search = []string{username}

	collection = db.C(ACCOUNTS)
	err = collection.Insert(account)
	if err != nil {
		panic(err)
		return
	}

	// sendWelcomeEmail
	go func() {
		c.Set("Username", response.Username)
		c.Set("Email", response.Email)
		c.Set("LoginURL", "http://" + c.Request.Host + "/login/")

		mailConf := MailConfig{}
		mailConf.Data = c.Keys
		mailConf.From = config.SMTP.From.Name + " <" + config.SMTP.From.Address + ">"
		mailConf.To = config.SystemEmail
		mailConf.Subject = "Your " + config.ProjectName + " Account"
		mailConf.ReplyTo = response.Email
		mailConf.HtmlPath = "views/signup/email-html.html"

		if err := mailConf.SendMail(); err != nil {
			println("Error Sending Welcome Email: " + err.Error())
		}
	}()

	// logUserIn
	user.login(c)

	response.Success = true
	c.JSON(http.StatusOK, response)
}<|endoftext|>


<commit_before>// +build linux darwin freebsd

package mounttest

import (
	"syscall"
	"testing"

	"github.com/stretchr/testify/assert"
)

// TestWriteFileDoubleClose tests double close on write
func TestWriteFileDoubleClose(t *testing.T) {
	run.skipIfNoFUSE(t)

	out, err := osCreate(run.path("testdoubleclose"))
	assert.NoError(t, err)
	fd := out.Fd()

	fd1, err := syscall.Dup(int(fd))
	assert.NoError(t, err)

	fd2, err := syscall.Dup(int(fd))
	assert.NoError(t, err)

	// close one of the dups - should produce no error
	err = syscall.Close(fd1)
	assert.NoError(t, err)

	// write to the file
	buf := []byte("hello")
	n, err := out.Write(buf)
	assert.NoError(t, err)
	assert.Equal(t, 5, n)

	// close it
	err = out.Close()
	assert.NoError(t, err)

	// write to the other dup - should produce an error
	_, err = syscall.Write(fd2, buf)
	assert.Error(t, err, "input/output error")

	// close the dup - should not produce an error
	err = syscall.Close(fd2)
	assert.NoError(t, err)

	run.waitForWriters()
	run.rm(t, "testdoubleclose")
}
<commit_msg>mount: disable failing test TestWriteFileDoubleClose on OSX<commit_after>// +build linux darwin freebsd

package mounttest

import (
	"runtime"
	"syscall"
	"testing"

	"github.com/stretchr/testify/assert"
)

// TestWriteFileDoubleClose tests double close on write
func TestWriteFileDoubleClose(t *testing.T) {
	run.skipIfNoFUSE(t)
	if runtime.GOOS == "darwin" {
		t.Skip("Skipping test on OSX")
	}

	out, err := osCreate(run.path("testdoubleclose"))
	assert.NoError(t, err)
	fd := out.Fd()

	fd1, err := syscall.Dup(int(fd))
	assert.NoError(t, err)

	fd2, err := syscall.Dup(int(fd))
	assert.NoError(t, err)

	// close one of the dups - should produce no error
	err = syscall.Close(fd1)
	assert.NoError(t, err)

	// write to the file
	buf := []byte("hello")
	n, err := out.Write(buf)
	assert.NoError(t, err)
	assert.Equal(t, 5, n)

	// close it
	err = out.Close()
	assert.NoError(t, err)

	// write to the other dup - should produce an error
	_, err = syscall.Write(fd2, buf)
	assert.Error(t, err, "input/output error")

	// close the dup - should not produce an error
	err = syscall.Close(fd2)
	assert.NoError(t, err)

	run.waitForWriters()
	run.rm(t, "testdoubleclose")
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The OpenEBS 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 app

import (
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/klog"

	pvController "sigs.k8s.io/sig-storage-lib-external-provisioner/controller"
	//	pvController "github.com/kubernetes-sigs/sig-storage-lib-external-provisioner/controller"
	mKube "github.com/openebs/maya/pkg/kubernetes/client/v1alpha1"
	"github.com/openebs/maya/pkg/util"
)

var (
	cmdName         = "provisioner"
	provisionerName = "openebs.io/local"
	usage           = fmt.Sprintf("%s", cmdName)
)

// StartProvisioner will start a new dynamic Host Path PV provisioner
func StartProvisioner() (*cobra.Command, error) {
	// Create a new command.
	cmd := &cobra.Command{
		Use:   usage,
		Short: "Dynamic Host Path PV Provisioner",
		Long: `Manage the Host Path PVs that includes: validating, creating,
			deleting and cleanup tasks. Host Path PVs are setup with
			node affinity`,
		Run: func(cmd *cobra.Command, args []string) {
			util.CheckErr(Start(cmd), util.Fatal)
		},
	}

	// add the default command line flags as global flags to cobra command
	// flagset
	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)

	// Hack: Without the following line, the logs will be prefixed with Error
	_ = flag.CommandLine.Parse([]string{})

	return cmd, nil
}

// Start will initialize and run the dynamic provisioner daemon
func Start(cmd *cobra.Command) error {
	klog.Infof("Starting Provisioner...")

	// Dynamic Provisioner can run successfully if it can establish
	// connection to the Kubernetes Cluster. mKube helps with
	// establishing the connection either via InCluster or
	// OutOfCluster by using the following ENV variables:
	//   OPENEBS_IO_K8S_MASTER - Kubernetes master IP address
	//   OPENEBS_IO_KUBE_CONFIG - Path to the kubeConfig file.
	kubeClient, err := mKube.New().Clientset()
	if err != nil {
		return errors.Wrap(err, "unable to get k8s client")
	}

	serverVersion, err := kubeClient.Discovery().ServerVersion()
	if err != nil {
		return errors.Wrap(err, "Cannot start Provisioner: failed to get Kubernetes server version")
	}

	err = performPreupgradeTasks(kubeClient)
	if err != nil {
		return errors.Wrap(err, "failure in preupgrade tasks")
	}

	//Create a channel to receive shutdown signal to help
	// with graceful exit of the provisioner.
	stopCh := make(chan struct{})
	RegisterShutdownChannel(stopCh)

	//Create an instance of ProvisionerHandler to handle PV
	// create and delete events.
	provisioner, err := NewProvisioner(stopCh, kubeClient)
	if err != nil {
		return err
	}

	//Create an instance of the Dynamic Provisioner Controller
	// that has the reconciliation loops for PVC create and delete
	// events and invokes the Provisioner Handler.
	pc := pvController.NewProvisionController(
		kubeClient,
		provisionerName,
		provisioner,
		serverVersion.GitVersion,
	)
	klog.V(4).Info("Provisioner started")
	//Run the provisioner till a shutdown signal is received.
	pc.Run(stopCh)
	klog.V(4).Info("Provisioner stopped")

	return nil
}
<commit_msg>refact(localpv): add ENV to allow skipping leader election<commit_after>/*
Copyright 2019 The OpenEBS 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 app

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/klog"

	mKube "github.com/openebs/maya/pkg/kubernetes/client/v1alpha1"
	"github.com/openebs/maya/pkg/util"
	pvController "sigs.k8s.io/sig-storage-lib-external-provisioner/controller"
)

var (
	cmdName         = "provisioner"
	provisionerName = "openebs.io/local"
	// LeaderElectionKey represents ENV for disable/enable leaderElection for
	// localpv provisioner
	LeaderElectionKey = "LEADER_ELECTION_ENABLED"
	usage             = fmt.Sprintf("%s", cmdName)
)

// StartProvisioner will start a new dynamic Host Path PV provisioner
func StartProvisioner() (*cobra.Command, error) {
	// Create a new command.
	cmd := &cobra.Command{
		Use:   usage,
		Short: "Dynamic Host Path PV Provisioner",
		Long: `Manage the Host Path PVs that includes: validating, creating,
			deleting and cleanup tasks. Host Path PVs are setup with
			node affinity`,
		Run: func(cmd *cobra.Command, args []string) {
			util.CheckErr(Start(cmd), util.Fatal)
		},
	}

	// add the default command line flags as global flags to cobra command
	// flagset
	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)

	// Hack: Without the following line, the logs will be prefixed with Error
	_ = flag.CommandLine.Parse([]string{})

	return cmd, nil
}

// Start will initialize and run the dynamic provisioner daemon
func Start(cmd *cobra.Command) error {
	klog.Infof("Starting Provisioner...")

	// Dynamic Provisioner can run successfully if it can establish
	// connection to the Kubernetes Cluster. mKube helps with
	// establishing the connection either via InCluster or
	// OutOfCluster by using the following ENV variables:
	//   OPENEBS_IO_K8S_MASTER - Kubernetes master IP address
	//   OPENEBS_IO_KUBE_CONFIG - Path to the kubeConfig file.
	kubeClient, err := mKube.New().Clientset()
	if err != nil {
		return errors.Wrap(err, "unable to get k8s client")
	}

	serverVersion, err := kubeClient.Discovery().ServerVersion()
	if err != nil {
		return errors.Wrap(err, "Cannot start Provisioner: failed to get Kubernetes server version")
	}

	err = performPreupgradeTasks(kubeClient)
	if err != nil {
		return errors.Wrap(err, "failure in preupgrade tasks")
	}

	//Create a channel to receive shutdown signal to help
	// with graceful exit of the provisioner.
	stopCh := make(chan struct{})
	RegisterShutdownChannel(stopCh)

	//Create an instance of ProvisionerHandler to handle PV
	// create and delete events.
	provisioner, err := NewProvisioner(stopCh, kubeClient)
	if err != nil {
		return err
	}

	//Create an instance of the Dynamic Provisioner Controller
	// that has the reconciliation loops for PVC create and delete
	// events and invokes the Provisioner Handler.
	pc := pvController.NewProvisionController(
		kubeClient,
		provisionerName,
		provisioner,
		serverVersion.GitVersion,
		pvController.LeaderElection(isLeaderElectionEnabled()),
	)
	klog.V(4).Info("Provisioner started")
	//Run the provisioner till a shutdown signal is received.
	pc.Run(stopCh)
	klog.V(4).Info("Provisioner stopped")

	return nil
}

// isLeaderElectionEnabled returns true/false based on the ENV
// LEADER_ELECTION_ENABLED set via provisioner deployment.
// Defaults to true, means leaderElection enabled by default.
func isLeaderElectionEnabled() bool {
	leaderElection := os.Getenv(LeaderElectionKey)

	var leader bool
	switch strings.ToLower(leaderElection) {
	default:
		klog.Info("Leader election enabled for localpv-provisioner")
		leader = true
	case "y", "yes", "true":
		klog.Info("Leader election enabled for localpv-provisioner via leaderElectionKey")
		leader = true
	case "n", "no", "false":
		klog.Info("Leader election disabled for localpv-provisioner via leaderElectionKey")
		leader = false
	}
	return leader
}
<|endoftext|>


<commit_before>package command

import (
	"flag"
	"fmt"
	"net"
	"os/exec"
	"runtime"

	"github.com/hashicorp/errwrap"
	sockaddr "github.com/hashicorp/go-sockaddr"
	"github.com/mitchellh/cli"
)

type TechSupportCommand struct {
	Ui cli.Ui

	// outputMode controls the type of output encoding.
	outputMode string

	// flags is a list of options belonging to this command
	flags *flag.FlagSet
}

// Description is the long-form command help.
func (c *TechSupportCommand) Description() string {
	return `Print out network diagnostic information that can be used by support.

` + "The `sockaddr` library relies on OS-specific commands and output which can potentially be " +
		"brittle.  The `tech-support` subcommand emits all of the platform-specific " +
		"network details required to debug why a given `sockaddr` API call is behaving " +
		"differently than expected.  The `-output` flag controls the output format. " +
		"The default output mode is Markdown (`md`) however a raw mode (`raw`) is " +
		"available to obtain the original output."
}

// Help returns the full help output expected by `sockaddr -h cmd`
func (c *TechSupportCommand) Help() string {
	return MakeHelp(c)
}

// InitOpts is responsible for setup of this command's configuration via the
// command line.  InitOpts() does not parse the arguments (see parseOpts()).
func (c *TechSupportCommand) InitOpts() {
	c.flags = flag.NewFlagSet("tech-support", flag.ContinueOnError)
	c.flags.Usage = func() { c.Ui.Output(c.Help()) }
	c.flags.StringVar(&c.outputMode, "output", "md", `Encode the output using one of Markdown ("md") or Raw ("raw")`)
}

// Run executes this command.
func (c *TechSupportCommand) Run(args []string) int {
	c.InitOpts()
	rest, err := c.parseOpts(args)
	if err != nil {
		if errwrap.Contains(err, "flag: help requested") {
			return 0
		}
		return 1
	}
	if len(rest) != 0 {
		c.Ui.Error(c.Help())
		return 1
	}

	ri, err := sockaddr.NewRouteInfo()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("error loading route information: %v", err))
		return 1
	}

	const initNumCmds = 4
	type cmdResult struct {
		cmd []string
		out string
	}
	output := make(map[string]cmdResult, initNumCmds)
	ri.VisitCommands(func(name string, cmd []string) {
		out, err := exec.Command(cmd[0], cmd[1:]...).Output()
		if err != nil {
			out = []byte(fmt.Sprintf("ERROR: command %q failed: %v", name, err))
		}

		output[name] = cmdResult{
			cmd: cmd,
			out: string(out),
		}
	})

	var intFmt, keyFmt string
	var fmtMap map[string]string
	switch c.outputMode {
	case "md":
		intFmt = "%02d."
		keyFmt = "%s"
		fmtMap = map[string]string{
			"s":  "`%s`",
			"-s": "%s",
			"v":  "`%v`",
			"+v": "`%#v`",
		}
	case "raw":
		intFmt = "%02d:"
		keyFmt = "-s"
		fmtMap = map[string]string{
			"s":  "%q",
			"-s": "%s",
			"v":  "%v",
			"+v": "%#v",
		}
	default:
		c.Ui.Error(fmt.Sprintf("Unsupported output type: %q", c.outputMode))
		return 1
	}

	var count int
	out := func(fmtType, k string, v interface{}) {
		count++

		fmtStr, ok := fmtMap[fmtType]
		if !ok {
			panic(fmt.Sprintf("Invalid fmtType: %v", fmtType))
		}

		strFmt, ok := fmtMap[keyFmt]
		if !ok {
			panic(fmt.Sprintf("Invalid strFmt: %v", keyFmt))
		}

		outFmt := fmt.Sprintf("%s %s:\t%s", intFmt, strFmt, fmtStr)
		c.Ui.Output(fmt.Sprintf(outFmt, count, k, v))
	}

	for cmdName, result := range output {
		switch c.outputMode {
		case "md":
			c.Ui.Output(fmt.Sprintf("## cmd: `%s`", cmdName))
			c.Ui.Output("")
			c.Ui.Output(fmt.Sprintf("Command: `%#v`", result.cmd))
			c.Ui.Output("```")
			c.Ui.Output(result.out)
			c.Ui.Output("```")
			c.Ui.Output("")
		case "raw":
			c.Ui.Output(fmt.Sprintf("cmd: %q: %#v", cmdName, result.cmd))
			c.Ui.Output("")
			c.Ui.Output(result.out)
			c.Ui.Output("")
		default:
			c.Ui.Error(fmt.Sprintf("Unsupported output type: %q", c.outputMode))
			return 1
		}

		out("s", "GOOS", runtime.GOOS)
		out("s", "GOARCH", runtime.GOARCH)
		out("s", "Compiler", runtime.Compiler)
		out("s", "Version", runtime.Version())
		ifs, err := net.Interfaces()
		if err != nil {
			out("v", "net.Interfaces", err)
		} else {
			for i, intf := range ifs {
				out("s", fmt.Sprintf("net.Interfaces[%d].Name", i), intf.Name)
				out("s", fmt.Sprintf("net.Interfaces[%d].Flags", i), intf.Flags)
				out("+v", fmt.Sprintf("net.Interfaces[%d].Raw", i), intf)
				addrs, err := intf.Addrs()
				if err != nil {
					out("v", fmt.Sprintf("net.Interfaces[%d].Addrs", i), err)
				} else {
					for j, addr := range addrs {
						out("s", fmt.Sprintf("net.Interfaces[%d].Addrs[%d]", i, j), addr)
					}
				}
			}
		}
	}

	return 0
}

// Synopsis returns a terse description used when listing sub-commands.
func (c *TechSupportCommand) Synopsis() string {
	return `Dumps diagnostic information about a platform's network`
}

// Usage is the one-line usage description
func (c *TechSupportCommand) Usage() string {
	return `sockaddr tech-support [options]`
}

// VisitAllFlags forwards the visitor function to the FlagSet
func (c *TechSupportCommand) VisitAllFlags(fn func(*flag.Flag)) {
	c.flags.VisitAll(fn)
}

// parseOpts is responsible for parsing the options set in InitOpts().  Returns
// a list of non-parsed flags.
func (c *TechSupportCommand) parseOpts(args []string) ([]string, error) {
	if err := c.flags.Parse(args); err != nil {
		return nil, err
	}

	switch c.outputMode {
	case "md", "markdown":
		c.outputMode = "md"
	case "raw":
	default:
		return nil, fmt.Errorf(`Invalid output mode %q, supported output types are "md" (default) and "raw"`, c.outputMode)
	}
	return c.flags.Args(), nil
}
<commit_msg>Oh wow was this a bad thing to have unstaged and not committed.<commit_after>package command

import (
	"flag"
	"fmt"
	"net"
	"os/exec"
	"runtime"

	"github.com/hashicorp/errwrap"
	sockaddr "github.com/hashicorp/go-sockaddr"
	"github.com/mitchellh/cli"
)

type TechSupportCommand struct {
	Ui cli.Ui

	// outputMode controls the type of output encoding.
	outputMode string

	// flags is a list of options belonging to this command
	flags *flag.FlagSet
}

// Description is the long-form command help.
func (c *TechSupportCommand) Description() string {
	return `Print out network diagnostic information that can be used by support.

` + "The `sockaddr` library relies on OS-specific commands and output which can potentially be " +
		"brittle.  The `tech-support` subcommand emits all of the platform-specific " +
		"network details required to debug why a given `sockaddr` API call is behaving " +
		"differently than expected.  The `-output` flag controls the output format. " +
		"The default output mode is Markdown (`md`) however a raw mode (`raw`) is " +
		"available to obtain the original output."
}

// Help returns the full help output expected by `sockaddr -h cmd`
func (c *TechSupportCommand) Help() string {
	return MakeHelp(c)
}

// InitOpts is responsible for setup of this command's configuration via the
// command line.  InitOpts() does not parse the arguments (see parseOpts()).
func (c *TechSupportCommand) InitOpts() {
	c.flags = flag.NewFlagSet("tech-support", flag.ContinueOnError)
	c.flags.Usage = func() { c.Ui.Output(c.Help()) }
	c.flags.StringVar(&c.outputMode, "output", "md", `Encode the output using one of Markdown ("md") or Raw ("raw")`)
}

// Run executes this command.
func (c *TechSupportCommand) Run(args []string) int {
	c.InitOpts()
	rest, err := c.parseOpts(args)
	if err != nil {
		if errwrap.Contains(err, "flag: help requested") {
			return 0
		}
		return 1
	}
	if len(rest) != 0 {
		c.Ui.Error(c.Help())
		return 1
	}

	ri, err := sockaddr.NewRouteInfo()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("error loading route information: %v", err))
		return 1
	}

	const initNumCmds = 4
	type cmdResult struct {
		cmd []string
		out string
	}
	output := make(map[string]cmdResult, initNumCmds)
	ri.VisitCommands(func(name string, cmd []string) {
		out, err := exec.Command(cmd[0], cmd[1:]...).Output()
		if err != nil {
			out = []byte(fmt.Sprintf("ERROR: command %q failed: %v", name, err))
		}

		output[name] = cmdResult{
			cmd: cmd,
			out: string(out),
		}
	})

	var intFmt, keyFmt string
	var fmtMap map[string]string
	switch c.outputMode {
	case "md":
		intFmt = "%02d."
		keyFmt = "s"
		fmtMap = map[string]string{
			"s":  "`%s`",
			"-s": "%s",
			"v":  "`%v`",
			"+v": "`%#v`",
		}
	case "raw":
		intFmt = "%02d:"
		keyFmt = "-s"
		fmtMap = map[string]string{
			"s":  "%q",
			"-s": "%s",
			"v":  "%v",
			"+v": "%#v",
		}
	default:
		c.Ui.Error(fmt.Sprintf("Unsupported output type: %q", c.outputMode))
		return 1
	}

	var count int
	out := func(fmtType, k string, v interface{}) {
		count++

		fmtStr, ok := fmtMap[fmtType]
		if !ok {
			panic(fmt.Sprintf("Invalid fmtType: %v", fmtType))
		}

		strFmt, ok := fmtMap[keyFmt]
		if !ok {
			panic(fmt.Sprintf("Invalid strFmt: %v", keyFmt))
		}

		outFmt := fmt.Sprintf("%s %s:\t%s", intFmt, strFmt, fmtStr)
		c.Ui.Output(fmt.Sprintf(outFmt, count, k, v))
	}

	for cmdName, result := range output {
		switch c.outputMode {
		case "md":
			c.Ui.Output(fmt.Sprintf("## cmd: `%s`", cmdName))
			c.Ui.Output("")
			c.Ui.Output(fmt.Sprintf("Command: `%#v`", result.cmd))
			c.Ui.Output("```")
			c.Ui.Output(result.out)
			c.Ui.Output("```")
			c.Ui.Output("")
		case "raw":
			c.Ui.Output(fmt.Sprintf("cmd: %q: %#v", cmdName, result.cmd))
			c.Ui.Output("")
			c.Ui.Output(result.out)
			c.Ui.Output("")
		default:
			c.Ui.Error(fmt.Sprintf("Unsupported output type: %q", c.outputMode))
			return 1
		}

		out("s", "GOOS", runtime.GOOS)
		out("s", "GOARCH", runtime.GOARCH)
		out("s", "Compiler", runtime.Compiler)
		out("s", "Version", runtime.Version())
		ifs, err := net.Interfaces()
		if err != nil {
			out("v", "net.Interfaces", err)
		} else {
			for i, intf := range ifs {
				out("s", fmt.Sprintf("net.Interfaces[%d].Name", i), intf.Name)
				out("s", fmt.Sprintf("net.Interfaces[%d].Flags", i), intf.Flags)
				out("+v", fmt.Sprintf("net.Interfaces[%d].Raw", i), intf)
				addrs, err := intf.Addrs()
				if err != nil {
					out("v", fmt.Sprintf("net.Interfaces[%d].Addrs", i), err)
				} else {
					for j, addr := range addrs {
						out("s", fmt.Sprintf("net.Interfaces[%d].Addrs[%d]", i, j), addr)
					}
				}
			}
		}
	}

	return 0
}

// Synopsis returns a terse description used when listing sub-commands.
func (c *TechSupportCommand) Synopsis() string {
	return `Dumps diagnostic information about a platform's network`
}

// Usage is the one-line usage description
func (c *TechSupportCommand) Usage() string {
	return `sockaddr tech-support [options]`
}

// VisitAllFlags forwards the visitor function to the FlagSet
func (c *TechSupportCommand) VisitAllFlags(fn func(*flag.Flag)) {
	c.flags.VisitAll(fn)
}

// parseOpts is responsible for parsing the options set in InitOpts().  Returns
// a list of non-parsed flags.
func (c *TechSupportCommand) parseOpts(args []string) ([]string, error) {
	if err := c.flags.Parse(args); err != nil {
		return nil, err
	}

	switch c.outputMode {
	case "md", "markdown":
		c.outputMode = "md"
	case "raw":
	default:
		return nil, fmt.Errorf(`Invalid output mode %q, supported output types are "md" (default) and "raw"`, c.outputMode)
	}
	return c.flags.Args(), nil
}
<|endoftext|>