<commit_before>package lifecycle_test

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

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

	"github.com/cloudfoundry-incubator/garden/api"
	gclient "github.com/cloudfoundry-incubator/garden/client"
	gconn "github.com/cloudfoundry-incubator/garden/client/connection"
)

var _ = Describe("When nested", func() {
	var container api.Container
	var nestedGardenAddress string

	nestedRootfsPath := os.Getenv("GARDEN_NESTABLE_TEST_ROOTFS")
	if nestedRootfsPath == "" {
		log.Println("GARDEN_NESTABLE_TEST_ROOTFS undefined; skipping nesting test")
		return
	}

	BeforeEach(func() {
		var err error
		client = startGarden()

		tmpdir, err := ioutil.TempDir("", "nested-garden-test")
		Ω(err).ShouldNot(HaveOccurred())

		absoluteBinPath, err := filepath.Abs(binPath)
		Ω(err).ShouldNot(HaveOccurred())

		container, err = client.Create(api.ContainerSpec{
			RootFSPath: nestedRootfsPath,
			// only privileged containers support nesting
			Privileged: true,
			BindMounts: []api.BindMount{
				{
					SrcPath: filepath.Dir(gardenBin),
					DstPath: "/home/vcap/bin/",
					Mode:    api.BindMountModeRO,
				},
				{
					SrcPath: absoluteBinPath,
					DstPath: "/home/vcap/binpath/bin",
					Mode:    api.BindMountModeRO,
				},
				{
					SrcPath: filepath.Join(absoluteBinPath, "..", "skeleton"),
					DstPath: "/home/vcap/binpath/skeleton",
					Mode:    api.BindMountModeRO,
				},
				{
					SrcPath: rootFSPath,
					DstPath: "/home/vcap/rootfs",
					Mode:    api.BindMountModeRO,
				},
				{
					SrcPath: tmpdir,
					DstPath: "/tmp/nested/",
					Mode:    api.BindMountModeRW,
				},
			},
		})
		Ω(err).ShouldNot(HaveOccurred())

		nestedServerOutput := gbytes.NewBuffer()

		// start nested garden, again need to be root
		_, err = container.Run(api.ProcessSpec{
			Path: "sh",
			User: "root",
			Dir:  "/home/vcap",
			Args: []string{
				"-c",
				`
				mkdir /tmp/overlays /tmp/containers /tmp/snapshots /tmp/graph;
				./bin/garden-linux \
					-bin /home/vcap/binpath/bin \
					-rootfs /home/vcap/rootfs \
					-depot /tmp/containers \
					-overlays /tmp/overlays \
					-snapshots /tmp/snapshots \
					-graph /tmp/graph \
					-disableQuotas \
					-listenNetwork tcp \
					-listenAddr 0.0.0.0:7778;
				`,
			},
		}, api.ProcessIO{
			Stdout: io.MultiWriter(nestedServerOutput, gexec.NewPrefixedWriter("\x1b[32m[o]\x1b[34m[nested-garden-linux]\x1b[0m ", GinkgoWriter)),
			Stderr: gexec.NewPrefixedWriter("\x1b[91m[e]\x1b[34m[nested-garden-linux]\x1b[0m ", GinkgoWriter),
		})

		info, err := container.Info()
		Ω(err).ShouldNot(HaveOccurred())

		nestedGardenAddress = fmt.Sprintf("%s:7778", info.ContainerIP)
		Eventually(nestedServerOutput).Should(gbytes.Say("garden-linux.started"))
	})

	AfterEach(func() {
		Ω(client.Destroy(container.Handle())).Should(Succeed())
	})

	It("can start a nested garden-linux and run a container inside it", func() {
		nestedClient := gclient.New(gconn.New("tcp", nestedGardenAddress))
		nestedContainer, err := nestedClient.Create(api.ContainerSpec{})
		Ω(err).ShouldNot(HaveOccurred())

		nestedOutput := gbytes.NewBuffer()
		_, err = nestedContainer.Run(api.ProcessSpec{
			Path: "/bin/echo",
			Args: []string{
				"I am nested!",
			},
		}, api.ProcessIO{Stdout: nestedOutput, Stderr: nestedOutput})
		Ω(err).ShouldNot(HaveOccurred())

		Eventually(nestedOutput).Should(gbytes.Say("I am nested!"))
	})
})
<commit_msg>remove old bind mount from before using http api<commit_after>package lifecycle_test

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"

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

	"github.com/cloudfoundry-incubator/garden/api"
	gclient "github.com/cloudfoundry-incubator/garden/client"
	gconn "github.com/cloudfoundry-incubator/garden/client/connection"
)

var _ = Describe("When nested", func() {
	var container api.Container
	var nestedGardenAddress string

	nestedRootfsPath := os.Getenv("GARDEN_NESTABLE_TEST_ROOTFS")
	if nestedRootfsPath == "" {
		log.Println("GARDEN_NESTABLE_TEST_ROOTFS undefined; skipping nesting test")
		return
	}

	BeforeEach(func() {
		var err error
		client = startGarden()

		absoluteBinPath, err := filepath.Abs(binPath)
		Ω(err).ShouldNot(HaveOccurred())

		container, err = client.Create(api.ContainerSpec{
			RootFSPath: nestedRootfsPath,
			// only privileged containers support nesting
			Privileged: true,
			BindMounts: []api.BindMount{
				{
					SrcPath: filepath.Dir(gardenBin),
					DstPath: "/home/vcap/bin/",
					Mode:    api.BindMountModeRO,
				},
				{
					SrcPath: absoluteBinPath,
					DstPath: "/home/vcap/binpath/bin",
					Mode:    api.BindMountModeRO,
				},
				{
					SrcPath: filepath.Join(absoluteBinPath, "..", "skeleton"),
					DstPath: "/home/vcap/binpath/skeleton",
					Mode:    api.BindMountModeRO,
				},
				{
					SrcPath: rootFSPath,
					DstPath: "/home/vcap/rootfs",
					Mode:    api.BindMountModeRO,
				},
			},
		})
		Ω(err).ShouldNot(HaveOccurred())

		nestedServerOutput := gbytes.NewBuffer()

		// start nested garden, again need to be root
		_, err = container.Run(api.ProcessSpec{
			Path: "sh",
			User: "root",
			Dir:  "/home/vcap",
			Args: []string{
				"-c",
				`
				mkdir /tmp/overlays /tmp/containers /tmp/snapshots /tmp/graph;
				./bin/garden-linux \
					-bin /home/vcap/binpath/bin \
					-rootfs /home/vcap/rootfs \
					-depot /tmp/containers \
					-overlays /tmp/overlays \
					-snapshots /tmp/snapshots \
					-graph /tmp/graph \
					-disableQuotas \
					-listenNetwork tcp \
					-listenAddr 0.0.0.0:7778;
				`,
			},
		}, api.ProcessIO{
			Stdout: io.MultiWriter(nestedServerOutput, gexec.NewPrefixedWriter("\x1b[32m[o]\x1b[34m[nested-garden-linux]\x1b[0m ", GinkgoWriter)),
			Stderr: gexec.NewPrefixedWriter("\x1b[91m[e]\x1b[34m[nested-garden-linux]\x1b[0m ", GinkgoWriter),
		})

		info, err := container.Info()
		Ω(err).ShouldNot(HaveOccurred())

		nestedGardenAddress = fmt.Sprintf("%s:7778", info.ContainerIP)
		Eventually(nestedServerOutput).Should(gbytes.Say("garden-linux.started"))
	})

	AfterEach(func() {
		Ω(client.Destroy(container.Handle())).Should(Succeed())
	})

	It("can start a nested garden-linux and run a container inside it", func() {
		nestedClient := gclient.New(gconn.New("tcp", nestedGardenAddress))
		nestedContainer, err := nestedClient.Create(api.ContainerSpec{})
		Ω(err).ShouldNot(HaveOccurred())

		nestedOutput := gbytes.NewBuffer()
		_, err = nestedContainer.Run(api.ProcessSpec{
			Path: "/bin/echo",
			Args: []string{
				"I am nested!",
			},
		}, api.ProcessIO{Stdout: nestedOutput, Stderr: nestedOutput})
		Ω(err).ShouldNot(HaveOccurred())

		Eventually(nestedOutput).Should(gbytes.Say("I am nested!"))
	})
})
<|endoftext|>


<commit_before>package main

import (
	"time"

	"github.com/huin/goupnp"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/support"
	"github.com/ninjasphere/goupnp/dcps/av"
)

var info = ninja.LoadModuleInfo("./package.json")
var log = logger.GetLogger(info.Name)

type Driver struct {
	support.DriverSupport
	devices map[string]*MediaPlayer
}

func NewDriver() (*Driver, error) {

	driver := &Driver{
		devices: make(map[string]*MediaPlayer),
	}

	err := driver.Init(info)
	if err != nil {
		log.Fatalf("Failed to initialize driver: %s", err)
	}

	err = driver.Export(driver)
	if err != nil {
		log.Fatalf("Failed to export driver: %s", err)
	}

	return driver, nil
}

func (d *Driver) getDevice(upnpDevice goupnp.Device) (*MediaPlayer, error) {
	id := upnpDevice.UDN

	player, ok := d.devices[id]

	var err error

	if !ok {
		player, err = NewMediaPlayer(d, d.Conn, id, upnpDevice)
		d.devices[id] = player
	}

	return player, err
}

func (d *Driver) Start(_ interface{}) error {
	log.Infof("Driver Starting")

	go func() {
		for {
			d.Search()
			time.Sleep(time.Minute)
		}
	}()

	return nil
}

func (d *Driver) Search() error {

	transportClients, errors, err := av.NewAVTransport1Clients()

	if err != nil {
		log.Fatalf("Failed to find transport clients: %s", err)
	}

	for _, e := range errors {
		log.Warningf("Error finding transport clients: %s", e)
	}

	for _, client := range transportClients {
		device, err := d.getDevice(client.ServiceClient.RootDevice.Device)
		if err != nil {
			log.Warningf("Found a transport client, but couldn't create the device. %s", err)
			continue
		}
		device.SetTransportClient(client)
	}

	renderingClients, errors, err := av.NewRenderingControl1Clients()

	if err != nil {
		log.Fatalf("Failed to find transport clients: %s", err)
	}

	for _, e := range errors {
		log.Warningf("Error finding transport clients: %s", e)
	}

	for _, client := range renderingClients {
		device, err := d.getDevice(client.ServiceClient.RootDevice.Device)
		if err != nil {
			log.Warningf("Found a transport client, but couldn't create the device. %s", err)
			continue
		}
		device.SetRenderingClient(client)
	}

	return nil
}
<commit_msg>Add some extra logging<commit_after>package main

import (
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/huin/goupnp"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/support"
	"github.com/ninjasphere/goupnp/dcps/av"
)

var info = ninja.LoadModuleInfo("./package.json")
var log = logger.GetLogger(info.Name)

type Driver struct {
	support.DriverSupport
	devices map[string]*MediaPlayer
}

func NewDriver() (*Driver, error) {

	driver := &Driver{
		devices: make(map[string]*MediaPlayer),
	}

	err := driver.Init(info)
	if err != nil {
		log.Fatalf("Failed to initialize driver: %s", err)
	}

	err = driver.Export(driver)
	if err != nil {
		log.Fatalf("Failed to export driver: %s", err)
	}

	return driver, nil
}

func (d *Driver) getDevice(upnpDevice goupnp.Device) (*MediaPlayer, error) {
	id := upnpDevice.UDN

	player, ok := d.devices[id]

	var err error

	if !ok {
		player, err = NewMediaPlayer(d, d.Conn, id, upnpDevice)
		d.devices[id] = player
	}

	return player, err
}

func (d *Driver) Start(_ interface{}) error {
	log.Infof("Driver Starting")

	go func() {
		for {
			d.Search()
			time.Sleep(time.Minute)
		}
	}()

	return nil
}

func (d *Driver) Search() error {

	transportClients, errors, err := av.NewAVTransport1Clients()

	if err != nil {
		log.Fatalf("Failed to find transport clients: %s", err)
	}

	for _, e := range errors {
		log.Warningf("Error finding transport clients: %s", e)
	}

	for _, client := range transportClients {
		spew.Dump(client)
		device, err := d.getDevice(client.ServiceClient.RootDevice.Device)
		if err != nil {
			log.Warningf("Found a transport client, but couldn't create the device. %s", err)
			continue
		}
		device.SetTransportClient(client)
	}

	renderingClients, errors, err := av.NewRenderingControl1Clients()

	if err != nil {
		log.Fatalf("Failed to find rendering clients: %s", err)
	}

	for _, e := range errors {
		log.Warningf("Error finding rendering clients: %s", e)
	}

	for _, client := range renderingClients {
		spew.Dump(client)
		device, err := d.getDevice(client.ServiceClient.RootDevice.Device)
		if err != nil {
			log.Warningf("Found a rendering client, but couldn't create the device. %s", err)
			continue
		}
		device.SetRenderingClient(client)
	}

	return nil
}
<|endoftext|>


<commit_before>package ar

import (
	"io"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"
)

var testCommon = "!<arch>\n" +
	"debian-binary   1385068169  0     0     100644  4         `\n" +
	"2.0\n" +
	"control.tar.gz  1385068169  0     0     100644  0         `\n"

// I really miss this...
func timeMustParse(layout, value string) time.Time {
	t, err := time.Parse(layout, value)
	if err != nil {
		panic(err)
	}
	return t
}

var testCommonFileHeaders = []struct {
	in   string
	want *fileInfo
	err  string
}{
	{
		in: "debian-binary   1385068169  0     0     100644  4         `\n",
		want: &fileInfo{
			name:  "debian-binary",
			owner: "0",
			group: "0",
			mtime: time.Unix(1385068169, 0),
			mode:  os.FileMode(0100644) & os.ModePerm,
			size:  4,
		},
	},
	{
		in: "debian-binary   1385068169  0     0     644     4         `\n",
		want: &fileInfo{
			name:  "debian-binary",
			owner: "0",
			group: "0",
			mtime: time.Unix(1385068169, 0),
			mode:  os.FileMode(0644),
			size:  4,
		},
	},
	{
		in:  "debian-binary   1385068169  a     0     100644  4         `\n",
		err: "corrupt archive: strconv.ParseInt: parsing \"a\": invalid syntax",
	},
	{
		in:  "debian-binary   1385068169  0     b     100644  4         `\n",
		err: "corrupt archive: strconv.ParseInt: parsing \"b\": invalid syntax",
	},
	{
		in:  "debian-binary   1385068169  0     0     120644  4         `\n",
		err: "corrupt archive: only regular files supported",
	},
	{
		in:  "debian-binary   1385068169  0     0     220644  4         `\n",
		err: "corrupt archive: invalid file mode",
	},
}

func TestReadFileHeader(t *testing.T) {
	for i, test := range testCommonFileHeaders {
		got, err := readFileHeader(strings.NewReader(test.in))
		switch {
		case err == nil && test.err != "":
			t.Errorf("%d: got no err, expected err %v", i, test.err)
			continue
		case err != nil && test.err != err.Error():
			t.Errorf("%d: got err %q, expected err %q", i, err, test.err)
			continue
		case err == nil && test.err == "":
			// no error as expected
		case err != nil && test.err == err.Error():
			t.Logf("%d: got expected error %q", i, err)
			continue
		}

		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("%d: got %#v, expected %+v", i, got, test.want)
		} else {
			t.Logf("%d: got %#v", i, got)
		}
	}
}

func BenchmarkReadFileHeader(b *testing.B) {
	r := strings.NewReader("debian-binary   1385068169  0     0     100644  4         `\n")
	for i := 0; i < b.N; i++ {
		_, _ = readFileHeader(r)
		r.Seek(0, 0)
	}

}

var testMagic = []struct {
	in   io.Reader
	want bool
}{
	{
		in:   strings.NewReader(Magic),
		want: true,
	},
	{
		in:   strings.NewReader(strings.Repeat("a", len(Magic))),
		want: false,
	},
}

func TestReadMagic(t *testing.T) {
	for i, test := range testMagic {
		got := hasMagic(test.in)
		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("%d: got %#v, expected %+v", i, got, test.want)
		} else {
			t.Logf("%d: got %#v", i, got)
		}
	}
}
<commit_msg>Remove superflous function<commit_after>package ar

import (
	"io"
	"os"
	"reflect"
	"strings"
	"testing"
	"time"
)

var testCommon = "!<arch>\n" +
	"debian-binary   1385068169  0     0     100644  4         `\n" +
	"2.0\n" +
	"control.tar.gz  1385068169  0     0     100644  0         `\n"

var testCommonFileHeaders = []struct {
	in   string
	want *fileInfo
	err  string
}{
	{
		in: "debian-binary   1385068169  0     0     100644  4         `\n",
		want: &fileInfo{
			name:  "debian-binary",
			owner: "0",
			group: "0",
			mtime: time.Unix(1385068169, 0),
			mode:  os.FileMode(0100644) & os.ModePerm,
			size:  4,
		},
	},
	{
		in: "debian-binary   1385068169  0     0     644     4         `\n",
		want: &fileInfo{
			name:  "debian-binary",
			owner: "0",
			group: "0",
			mtime: time.Unix(1385068169, 0),
			mode:  os.FileMode(0644),
			size:  4,
		},
	},
	{
		in:  "debian-binary   1385068169  a     0     100644  4         `\n",
		err: "corrupt archive: strconv.ParseInt: parsing \"a\": invalid syntax",
	},
	{
		in:  "debian-binary   1385068169  0     b     100644  4         `\n",
		err: "corrupt archive: strconv.ParseInt: parsing \"b\": invalid syntax",
	},
	{
		in:  "debian-binary   1385068169  0     0     120644  4         `\n",
		err: "corrupt archive: only regular files supported",
	},
	{
		in:  "debian-binary   1385068169  0     0     220644  4         `\n",
		err: "corrupt archive: invalid file mode",
	},
}

func TestReadFileHeader(t *testing.T) {
	for i, test := range testCommonFileHeaders {
		got, err := readFileHeader(strings.NewReader(test.in))
		switch {
		case err == nil && test.err != "":
			t.Errorf("%d: got no err, expected err %v", i, test.err)
			continue
		case err != nil && test.err != err.Error():
			t.Errorf("%d: got err %q, expected err %q", i, err, test.err)
			continue
		case err == nil && test.err == "":
			// no error as expected
		case err != nil && test.err == err.Error():
			t.Logf("%d: got expected error %q", i, err)
			continue
		}

		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("%d: got %#v, expected %+v", i, got, test.want)
		} else {
			t.Logf("%d: got %#v", i, got)
		}
	}
}

func BenchmarkReadFileHeader(b *testing.B) {
	r := strings.NewReader("debian-binary   1385068169  0     0     100644  4         `\n")
	for i := 0; i < b.N; i++ {
		_, _ = readFileHeader(r)
		r.Seek(0, 0)
	}

}

var testMagic = []struct {
	in   io.Reader
	want bool
}{
	{
		in:   strings.NewReader(Magic),
		want: true,
	},
	{
		in:   strings.NewReader(strings.Repeat("a", len(Magic))),
		want: false,
	},
}

func TestReadMagic(t *testing.T) {
	for i, test := range testMagic {
		got := hasMagic(test.in)
		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("%d: got %#v, expected %+v", i, got, test.want)
		} else {
			t.Logf("%d: got %#v", i, got)
		}
	}
}
<|endoftext|>


<commit_before>/* Copyright 2018 Google Inc.

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

    https://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 entity provides a lightweight method for generating certificates.
package entity

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"math/big"
	"time"
)

var (
	bigInt         = big.NewInt(0).Lsh(big.NewInt(1), 128)
	rsaBitSize     = 2048
	randReader     = rand.Reader
	certMaxPathLen = 5
	certExpiration = (365 * 24 * time.Hour)
)

// CreateSelfSigned creates an Entity with a self signed certificate.
func CreateSelfSigned(cn string, priv crypto.PrivateKey) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(ca); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSignedCA creates an Entity with a CA certificate signed by parent.
func CreateSignedCA(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSigned creates an Entity with a certificate signed by parent.
func CreateSigned(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(Template(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// Entity contains a certificate, associated template, public and private keys.
type Entity struct {
	Template    *x509.Certificate
	PrivateKey  crypto.PrivateKey
	PublicKey   crypto.PublicKey
	Certificate *tls.Certificate
}

// FromFile loads an Entity with a certificate and private key from file.
func FromFile(certFile, privKeyFile string) (*Entity, error) {
	cert, err := tls.LoadX509KeyPair(certFile, privKeyFile)
	if err != nil {
		return nil, fmt.Errorf("failed to load x509 key pair: %v", err)
	}
	if cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]); err != nil {
		return nil, fmt.Errorf("failed to parse certificate: %v", err)
	}

	return &Entity{PrivateKey: cert.PrivateKey, Certificate: &cert}, nil
}

// FromSigningRequest creates the boilerplate for a new certificate out of a Signing Request.
func FromSigningRequest(csr *x509.CertificateRequest) (*Entity, error) {
	template := &x509.Certificate{
		BasicConstraintsValid: true,
		DNSNames:              csr.DNSNames,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:              time.Now().Add(certExpiration),
		NotBefore:             time.Now().Add(-1 * time.Hour),
		SignatureAlgorithm:    csr.SignatureAlgorithm,
		Subject:               csr.Subject,
		Signature:             csr.Signature,
		Extensions:            csr.Extensions,
		Version:               csr.Version,
		ExtraExtensions:       csr.ExtraExtensions,
		EmailAddresses:        csr.EmailAddresses,
		IPAddresses:           csr.IPAddresses,
		// URIs:                  csr.URIs,
		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
	}
	var err error
	if template.SubjectKeyId, err = keyID(csr.PublicKey); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}
	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}
	return &Entity{Template: template, PublicKey: csr.PublicKey}, nil
}

// NewEntity creates the boilerplate for a new certificate out of a template.
func NewEntity(template *x509.Certificate, privateKey crypto.PrivateKey) (*Entity, error) {
	priv, err := rsa.GenerateKey(randReader, rsaBitSize)
	if err != nil {
		return nil, fmt.Errorf("failed to generate key: %v", err)
	}
	if privateKey != nil {
		priv = privateKey.(*rsa.PrivateKey)
	}
	if template.SubjectKeyId, err = keyID(priv.Public()); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}

	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}

	return &Entity{Template: template, PrivateKey: priv, PublicKey: priv.Public(), Certificate: nil}, nil
}

func keyID(pub crypto.PublicKey) ([]byte, error) {
	pk, ok := pub.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("failed to parse public key, not a rsa.PublicKey type")
	}
	pkBytes, err := asn1.Marshal(*pk)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal public key: %v", err)
	}
	subjectKeyID := sha1.Sum(pkBytes)
	return subjectKeyID[:], nil
}

// SignWith signs the boilerplate certificate with the parent certificate.
func (e *Entity) SignWith(parent *Entity) error {
	parentTemplate := parent.Template
	if parent.Certificate != nil && parent.Certificate.Leaf != nil {
		parentTemplate = parent.Certificate.Leaf
	}
	if parentTemplate == nil {
		return fmt.Errorf("no template found for signing the certificate")
	}

	e.Template.Issuer = parentTemplate.Subject
	e.Template.AuthorityKeyId = parentTemplate.SubjectKeyId
	if len(e.Template.DNSNames) == 0 {
		e.Template.DNSNames = []string{e.Template.Subject.CommonName}
	}

	derCert, err := x509.CreateCertificate(randReader, e.Template, parentTemplate, e.PublicKey, parent.PrivateKey)
	if err != nil {
		return fmt.Errorf("failed to create certificate: %v", err)
	}

	tlsCert := &tls.Certificate{}
	tlsCert.Leaf, err = x509.ParseCertificate(derCert)
	if err != nil {
		return fmt.Errorf("failed to parse the certificate: %v", err)
	}
	tlsCert.Certificate = [][]byte{tlsCert.Leaf.Raw}
	tlsCert.PrivateKey = e.PrivateKey
	e.Certificate = tlsCert

	return nil
}

// SigningRequest generates a Certificate Signing Request out of the Entity.
func (e *Entity) SigningRequest() ([]byte, error) {
	csr := &x509.CertificateRequest{
		Attributes:      []pkix.AttributeTypeAndValueSET{},
		DNSNames:        e.Template.DNSNames,
		EmailAddresses:  e.Template.EmailAddresses,
		ExtraExtensions: e.Template.ExtraExtensions,
		IPAddresses:     e.Template.IPAddresses,
		// URIs:               e.Template.URIs,
		SignatureAlgorithm: e.Template.SignatureAlgorithm,
		Subject:            e.Template.Subject,
	}
	return x509.CreateCertificateRequest(randReader, csr, e.PrivateKey)
}

// SignedBy returns error if the certificate is not signed by parent.
func (e *Entity) SignedBy(parent *Entity) error {
	return e.Certificate.Leaf.CheckSignatureFrom(parent.Certificate.Leaf)
}

// TemplateCA returns a CA x509 template with cn as common name.
func TemplateCA(cn string) *x509.Certificate {
	ca := Template(cn)
	ca.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign
	ca.IsCA = true
	ca.MaxPathLen = certMaxPathLen
	ca.MaxPathLenZero = true
	return ca
}

// Template returns a leaf x509 template with cn as common name.
func Template(cn string) *x509.Certificate {
	subject := pkix.Name{
		Country:            []string{"NZ"},
		Organization:       []string{"gNxI"},
		OrganizationalUnit: []string{"gNxI"},
		Locality:           []string{"gNxI"},
		Province:           []string{"gNxI"},
		StreetAddress:      []string{"gNxI"},
		PostalCode:         []string{},
		CommonName:         cn,
		Names:              []pkix.AttributeTypeAndValue{},
		ExtraNames:         []pkix.AttributeTypeAndValue{},
	}

	return &x509.Certificate{
		// AuthorityKeyId,
		BasicConstraintsValid: true,
		DNSNames:              []string{cn},
		// ExcludedDNSDomains,
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		// IsCA,
		KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:  time.Now().Add(24 * 365 * time.Hour),
		NotBefore: time.Now().Add(-1 * time.Hour),
		// PermittedDNSDomains,
		// PermittedDNSDomainsCritical,
		// SerialNumber,
		SignatureAlgorithm: x509.SHA256WithRSA,
		Subject:            subject,
		// SubjectKeyId,
		// UnknownExtKeyUsage,
	}
}
<commit_msg>deprecate the use of sha1 (#254)<commit_after>/* Copyright 2018 Google Inc.

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

    https://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 entity provides a lightweight method for generating certificates.
package entity

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"math/big"
	"time"
)

var (
	bigInt         = big.NewInt(0).Lsh(big.NewInt(1), 128)
	rsaBitSize     = 2048
	randReader     = rand.Reader
	certMaxPathLen = 5
	certExpiration = (365 * 24 * time.Hour)
)

// CreateSelfSigned creates an Entity with a self signed certificate.
func CreateSelfSigned(cn string, priv crypto.PrivateKey) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(ca); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSignedCA creates an Entity with a CA certificate signed by parent.
func CreateSignedCA(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSigned creates an Entity with a certificate signed by parent.
func CreateSigned(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(Template(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// Entity contains a certificate, associated template, public and private keys.
type Entity struct {
	Template    *x509.Certificate
	PrivateKey  crypto.PrivateKey
	PublicKey   crypto.PublicKey
	Certificate *tls.Certificate
}

// FromFile loads an Entity with a certificate and private key from file.
func FromFile(certFile, privKeyFile string) (*Entity, error) {
	cert, err := tls.LoadX509KeyPair(certFile, privKeyFile)
	if err != nil {
		return nil, fmt.Errorf("failed to load x509 key pair: %v", err)
	}
	if cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]); err != nil {
		return nil, fmt.Errorf("failed to parse certificate: %v", err)
	}

	return &Entity{PrivateKey: cert.PrivateKey, Certificate: &cert}, nil
}

// FromSigningRequest creates the boilerplate for a new certificate out of a Signing Request.
func FromSigningRequest(csr *x509.CertificateRequest) (*Entity, error) {
	template := &x509.Certificate{
		BasicConstraintsValid: true,
		DNSNames:              csr.DNSNames,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:              time.Now().Add(certExpiration),
		NotBefore:             time.Now().Add(-1 * time.Hour),
		SignatureAlgorithm:    csr.SignatureAlgorithm,
		Subject:               csr.Subject,
		Signature:             csr.Signature,
		Extensions:            csr.Extensions,
		Version:               csr.Version,
		ExtraExtensions:       csr.ExtraExtensions,
		EmailAddresses:        csr.EmailAddresses,
		IPAddresses:           csr.IPAddresses,
		// URIs:                  csr.URIs,
		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
	}
	var err error
	if template.SubjectKeyId, err = keyID(csr.PublicKey); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}
	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}
	return &Entity{Template: template, PublicKey: csr.PublicKey}, nil
}

// NewEntity creates the boilerplate for a new certificate out of a template.
func NewEntity(template *x509.Certificate, privateKey crypto.PrivateKey) (*Entity, error) {
	priv, err := rsa.GenerateKey(randReader, rsaBitSize)
	if err != nil {
		return nil, fmt.Errorf("failed to generate key: %v", err)
	}
	if privateKey != nil {
		priv = privateKey.(*rsa.PrivateKey)
	}
	if template.SubjectKeyId, err = keyID(priv.Public()); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}

	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}

	return &Entity{Template: template, PrivateKey: priv, PublicKey: priv.Public(), Certificate: nil}, nil
}

func keyID(pub crypto.PublicKey) ([]byte, error) {
	pk, ok := pub.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("failed to parse public key, not a rsa.PublicKey type")
	}
	pkBytes, err := asn1.Marshal(*pk)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal public key: %v", err)
	}
	subjectKeyID := sha256.Sum256(pkBytes)
	return subjectKeyID[:], nil
}

// SignWith signs the boilerplate certificate with the parent certificate.
func (e *Entity) SignWith(parent *Entity) error {
	parentTemplate := parent.Template
	if parent.Certificate != nil && parent.Certificate.Leaf != nil {
		parentTemplate = parent.Certificate.Leaf
	}
	if parentTemplate == nil {
		return fmt.Errorf("no template found for signing the certificate")
	}

	e.Template.Issuer = parentTemplate.Subject
	e.Template.AuthorityKeyId = parentTemplate.SubjectKeyId
	if len(e.Template.DNSNames) == 0 {
		e.Template.DNSNames = []string{e.Template.Subject.CommonName}
	}

	derCert, err := x509.CreateCertificate(randReader, e.Template, parentTemplate, e.PublicKey, parent.PrivateKey)
	if err != nil {
		return fmt.Errorf("failed to create certificate: %v", err)
	}

	tlsCert := &tls.Certificate{}
	tlsCert.Leaf, err = x509.ParseCertificate(derCert)
	if err != nil {
		return fmt.Errorf("failed to parse the certificate: %v", err)
	}
	tlsCert.Certificate = [][]byte{tlsCert.Leaf.Raw}
	tlsCert.PrivateKey = e.PrivateKey
	e.Certificate = tlsCert

	return nil
}

// SigningRequest generates a Certificate Signing Request out of the Entity.
func (e *Entity) SigningRequest() ([]byte, error) {
	csr := &x509.CertificateRequest{
		Attributes:      []pkix.AttributeTypeAndValueSET{},
		DNSNames:        e.Template.DNSNames,
		EmailAddresses:  e.Template.EmailAddresses,
		ExtraExtensions: e.Template.ExtraExtensions,
		IPAddresses:     e.Template.IPAddresses,
		// URIs:               e.Template.URIs,
		SignatureAlgorithm: e.Template.SignatureAlgorithm,
		Subject:            e.Template.Subject,
	}
	return x509.CreateCertificateRequest(randReader, csr, e.PrivateKey)
}

// SignedBy returns error if the certificate is not signed by parent.
func (e *Entity) SignedBy(parent *Entity) error {
	return e.Certificate.Leaf.CheckSignatureFrom(parent.Certificate.Leaf)
}

// TemplateCA returns a CA x509 template with cn as common name.
func TemplateCA(cn string) *x509.Certificate {
	ca := Template(cn)
	ca.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign
	ca.IsCA = true
	ca.MaxPathLen = certMaxPathLen
	ca.MaxPathLenZero = true
	return ca
}

// Template returns a leaf x509 template with cn as common name.
func Template(cn string) *x509.Certificate {
	subject := pkix.Name{
		Country:            []string{"NZ"},
		Organization:       []string{"gNxI"},
		OrganizationalUnit: []string{"gNxI"},
		Locality:           []string{"gNxI"},
		Province:           []string{"gNxI"},
		StreetAddress:      []string{"gNxI"},
		PostalCode:         []string{},
		CommonName:         cn,
		Names:              []pkix.AttributeTypeAndValue{},
		ExtraNames:         []pkix.AttributeTypeAndValue{},
	}

	return &x509.Certificate{
		// AuthorityKeyId,
		BasicConstraintsValid: true,
		DNSNames:              []string{cn},
		// ExcludedDNSDomains,
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		// IsCA,
		KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:  time.Now().Add(24 * 365 * time.Hour),
		NotBefore: time.Now().Add(-1 * time.Hour),
		// PermittedDNSDomains,
		// PermittedDNSDomainsCritical,
		// SerialNumber,
		SignatureAlgorithm: x509.SHA256WithRSA,
		Subject:            subject,
		// SubjectKeyId,
		// UnknownExtKeyUsage,
	}
}
<|endoftext|>


<commit_before>/* Copyright 2018 Google Inc.

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

    https://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 entity provides a lightweight method for generating certificates.
package entity

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"math/big"
	"time"
)

var (
	bigInt         = big.NewInt(0).Lsh(big.NewInt(1), 128)
	rsaBitSize     = 2048
	randReader     = rand.Reader
	certMaxPathLen = 5
	certExpiration = (365 * 24 * time.Hour)
)

// CreateSelfSigned creates an Entity with a self signed certificate.
func CreateSelfSigned(cn string, priv crypto.PrivateKey) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(ca); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSignedCA creates an Entity with a CA certificate signed by parent.
func CreateSignedCA(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSigned creates an Entity with a certificate signed by parent.
func CreateSigned(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(Template(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// Entity contains a certificate, associated template, public and private keys.
type Entity struct {
	Template    *x509.Certificate
	PrivateKey  crypto.PrivateKey
	PublicKey   crypto.PublicKey
	Certificate *tls.Certificate
}

// FromFile loads an Entity with a certificate and private key from file.
func FromFile(certFile, privKeyFile string) (*Entity, error) {
	cert, err := tls.LoadX509KeyPair(certFile, privKeyFile)
	if err != nil {
		return nil, fmt.Errorf("failed to load x509 key pair: %v", err)
	}
	if cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]); err != nil {
		return nil, fmt.Errorf("failed to parse certificate: %v", err)
	}

	return &Entity{PrivateKey: cert.PrivateKey, Certificate: &cert}, nil
}

// FromSigningRequest creates the boilerplate for a new certificate out of a Signing Request.
func FromSigningRequest(csr *x509.CertificateRequest) (*Entity, error) {
	template := &x509.Certificate{
		BasicConstraintsValid: true,
		DNSNames:              csr.DNSNames,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:              time.Now().Add(certExpiration),
		NotBefore:             time.Now(),
		SignatureAlgorithm:    csr.SignatureAlgorithm,
		Subject:               csr.Subject,
		Signature:             csr.Signature,
		Extensions:            csr.Extensions,
		Version:               csr.Version,
		ExtraExtensions:       csr.ExtraExtensions,
		EmailAddresses:        csr.EmailAddresses,
		IPAddresses:           csr.IPAddresses,
		// URIs:                  csr.URIs,
		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
	}
	var err error
	if template.SubjectKeyId, err = keyID(csr.PublicKey); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}
	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}
	return &Entity{Template: template, PublicKey: csr.PublicKey}, nil
}

// NewEntity creates the boilerplate for a new certificate out of a template.
func NewEntity(template *x509.Certificate, privateKey crypto.PrivateKey) (*Entity, error) {
	priv, err := rsa.GenerateKey(randReader, rsaBitSize)
	if err != nil {
		return nil, fmt.Errorf("failed to generate key: %v", err)
	}
	if privateKey != nil {
		priv = privateKey.(*rsa.PrivateKey)
	}
	if template.SubjectKeyId, err = keyID(priv.Public()); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}

	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}

	return &Entity{Template: template, PrivateKey: priv, PublicKey: priv.Public(), Certificate: nil}, nil
}

func keyID(pub crypto.PublicKey) ([]byte, error) {
	pk, ok := pub.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("failed to parse public key, not a rsa.PublicKey type")
	}
	pkBytes, err := asn1.Marshal(*pk)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal public key: %v", err)
	}
	subjectKeyID := sha1.Sum(pkBytes)
	return subjectKeyID[:], nil
}

// SignWith signs the boilerplate certificate with the parent certificate.
func (e *Entity) SignWith(parent *Entity) error {
	parentTemplate := parent.Template
	if parent.Certificate != nil && parent.Certificate.Leaf != nil {
		parentTemplate = parent.Certificate.Leaf
	}
	if parentTemplate == nil {
		return fmt.Errorf("no template found for signing the certificate")
	}

	e.Template.Issuer = parentTemplate.Subject
	e.Template.AuthorityKeyId = parentTemplate.SubjectKeyId
	e.Template.DNSNames = []string{e.Template.Issuer.CommonName}
	derCert, err := x509.CreateCertificate(randReader, e.Template, parentTemplate, e.PublicKey, parent.PrivateKey)
	if err != nil {
		return fmt.Errorf("failed to create certificate: %v", err)
	}

	tlsCert := &tls.Certificate{}
	tlsCert.Leaf, err = x509.ParseCertificate(derCert)
	if err != nil {
		return fmt.Errorf("failed to parse the certificate: %v", err)
	}
	tlsCert.Certificate = [][]byte{tlsCert.Leaf.Raw}
	tlsCert.PrivateKey = e.PrivateKey
	e.Certificate = tlsCert

	return nil
}

// SigningRequest generates a Certificate Signing Request out of the Entity.
func (e *Entity) SigningRequest() ([]byte, error) {
	csr := &x509.CertificateRequest{
		Attributes:      []pkix.AttributeTypeAndValueSET{},
		DNSNames:        e.Template.DNSNames,
		EmailAddresses:  e.Template.EmailAddresses,
		ExtraExtensions: e.Template.ExtraExtensions,
		IPAddresses:     e.Template.IPAddresses,
		// URIs:               e.Template.URIs,
		SignatureAlgorithm: e.Template.SignatureAlgorithm,
		Subject:            e.Template.Subject,
	}
	return x509.CreateCertificateRequest(randReader, csr, e.PrivateKey)
}

// SignedBy returns error if the certificate is not signed by parent.
func (e *Entity) SignedBy(parent *Entity) error {
	return e.Certificate.Leaf.CheckSignatureFrom(parent.Certificate.Leaf)
}

// TemplateCA returns a CA x509 template with cn as common name.
func TemplateCA(cn string) *x509.Certificate {
	ca := Template(cn)
	ca.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign
	ca.IsCA = true
	ca.MaxPathLen = certMaxPathLen
	ca.MaxPathLenZero = true
	return ca
}

// Template returns a leaf x509 template with cn as common name.
func Template(cn string) *x509.Certificate {
	subject := pkix.Name{
		Country:            []string{"NZ"},
		Organization:       []string{"gNxI"},
		OrganizationalUnit: []string{"gNxI"},
		Locality:           []string{"gNxI"},
		Province:           []string{"gNxI"},
		StreetAddress:      []string{"gNxI"},
		PostalCode:         []string{},
		CommonName:         cn,
		Names:              []pkix.AttributeTypeAndValue{},
		ExtraNames:         []pkix.AttributeTypeAndValue{},
	}

	return &x509.Certificate{
		// AuthorityKeyId,
		BasicConstraintsValid: true,
		DNSNames:              []string{cn},
		// ExcludedDNSDomains,
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		// IsCA,
		KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:  time.Now().Add(24 * 365 * time.Hour),
		NotBefore: time.Now(),
		// PermittedDNSDomains,
		// PermittedDNSDomainsCritical,
		// SerialNumber,
		SignatureAlgorithm: x509.SHA256WithRSA,
		Subject:            subject,
		// SubjectKeyId,
		// UnknownExtKeyUsage,
	}
}
<commit_msg>use earlier NotBefore time in cert (#242)<commit_after>/* Copyright 2018 Google Inc.

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

    https://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 entity provides a lightweight method for generating certificates.
package entity

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"math/big"
	"time"
)

var (
	bigInt         = big.NewInt(0).Lsh(big.NewInt(1), 128)
	rsaBitSize     = 2048
	randReader     = rand.Reader
	certMaxPathLen = 5
	certExpiration = (365 * 24 * time.Hour)
)

// CreateSelfSigned creates an Entity with a self signed certificate.
func CreateSelfSigned(cn string, priv crypto.PrivateKey) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(ca); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSignedCA creates an Entity with a CA certificate signed by parent.
func CreateSignedCA(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(TemplateCA(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// CreateSigned creates an Entity with a certificate signed by parent.
func CreateSigned(cn string, priv crypto.PrivateKey, parent *Entity) (*Entity, error) {
	ca, err := NewEntity(Template(cn), priv)
	if err != nil {
		return nil, fmt.Errorf("failed to create a new Entity: %v", err)
	}
	if err := ca.SignWith(parent); err != nil {
		return nil, fmt.Errorf("failed to sign Entity: %v", err)
	}
	return ca, nil
}

// Entity contains a certificate, associated template, public and private keys.
type Entity struct {
	Template    *x509.Certificate
	PrivateKey  crypto.PrivateKey
	PublicKey   crypto.PublicKey
	Certificate *tls.Certificate
}

// FromFile loads an Entity with a certificate and private key from file.
func FromFile(certFile, privKeyFile string) (*Entity, error) {
	cert, err := tls.LoadX509KeyPair(certFile, privKeyFile)
	if err != nil {
		return nil, fmt.Errorf("failed to load x509 key pair: %v", err)
	}
	if cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]); err != nil {
		return nil, fmt.Errorf("failed to parse certificate: %v", err)
	}

	return &Entity{PrivateKey: cert.PrivateKey, Certificate: &cert}, nil
}

// FromSigningRequest creates the boilerplate for a new certificate out of a Signing Request.
func FromSigningRequest(csr *x509.CertificateRequest) (*Entity, error) {
	template := &x509.Certificate{
		BasicConstraintsValid: true,
		DNSNames:              csr.DNSNames,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:              time.Now().Add(certExpiration),
		NotBefore:             time.Now().Add(-1 * time.Hour),
		SignatureAlgorithm:    csr.SignatureAlgorithm,
		Subject:               csr.Subject,
		Signature:             csr.Signature,
		Extensions:            csr.Extensions,
		Version:               csr.Version,
		ExtraExtensions:       csr.ExtraExtensions,
		EmailAddresses:        csr.EmailAddresses,
		IPAddresses:           csr.IPAddresses,
		// URIs:                  csr.URIs,
		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
	}
	var err error
	if template.SubjectKeyId, err = keyID(csr.PublicKey); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}
	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}
	return &Entity{Template: template, PublicKey: csr.PublicKey}, nil
}

// NewEntity creates the boilerplate for a new certificate out of a template.
func NewEntity(template *x509.Certificate, privateKey crypto.PrivateKey) (*Entity, error) {
	priv, err := rsa.GenerateKey(randReader, rsaBitSize)
	if err != nil {
		return nil, fmt.Errorf("failed to generate key: %v", err)
	}
	if privateKey != nil {
		priv = privateKey.(*rsa.PrivateKey)
	}
	if template.SubjectKeyId, err = keyID(priv.Public()); err != nil {
		return nil, fmt.Errorf("failed to generate Subject Key ID: %v", err)
	}

	if template.SerialNumber, err = rand.Int(randReader, bigInt); err != nil {
		return nil, fmt.Errorf("failed to randomize a big int: %v", err)
	}

	return &Entity{Template: template, PrivateKey: priv, PublicKey: priv.Public(), Certificate: nil}, nil
}

func keyID(pub crypto.PublicKey) ([]byte, error) {
	pk, ok := pub.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("failed to parse public key, not a rsa.PublicKey type")
	}
	pkBytes, err := asn1.Marshal(*pk)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal public key: %v", err)
	}
	subjectKeyID := sha1.Sum(pkBytes)
	return subjectKeyID[:], nil
}

// SignWith signs the boilerplate certificate with the parent certificate.
func (e *Entity) SignWith(parent *Entity) error {
	parentTemplate := parent.Template
	if parent.Certificate != nil && parent.Certificate.Leaf != nil {
		parentTemplate = parent.Certificate.Leaf
	}
	if parentTemplate == nil {
		return fmt.Errorf("no template found for signing the certificate")
	}

	e.Template.Issuer = parentTemplate.Subject
	e.Template.AuthorityKeyId = parentTemplate.SubjectKeyId
	e.Template.DNSNames = []string{e.Template.Issuer.CommonName}
	derCert, err := x509.CreateCertificate(randReader, e.Template, parentTemplate, e.PublicKey, parent.PrivateKey)
	if err != nil {
		return fmt.Errorf("failed to create certificate: %v", err)
	}

	tlsCert := &tls.Certificate{}
	tlsCert.Leaf, err = x509.ParseCertificate(derCert)
	if err != nil {
		return fmt.Errorf("failed to parse the certificate: %v", err)
	}
	tlsCert.Certificate = [][]byte{tlsCert.Leaf.Raw}
	tlsCert.PrivateKey = e.PrivateKey
	e.Certificate = tlsCert

	return nil
}

// SigningRequest generates a Certificate Signing Request out of the Entity.
func (e *Entity) SigningRequest() ([]byte, error) {
	csr := &x509.CertificateRequest{
		Attributes:      []pkix.AttributeTypeAndValueSET{},
		DNSNames:        e.Template.DNSNames,
		EmailAddresses:  e.Template.EmailAddresses,
		ExtraExtensions: e.Template.ExtraExtensions,
		IPAddresses:     e.Template.IPAddresses,
		// URIs:               e.Template.URIs,
		SignatureAlgorithm: e.Template.SignatureAlgorithm,
		Subject:            e.Template.Subject,
	}
	return x509.CreateCertificateRequest(randReader, csr, e.PrivateKey)
}

// SignedBy returns error if the certificate is not signed by parent.
func (e *Entity) SignedBy(parent *Entity) error {
	return e.Certificate.Leaf.CheckSignatureFrom(parent.Certificate.Leaf)
}

// TemplateCA returns a CA x509 template with cn as common name.
func TemplateCA(cn string) *x509.Certificate {
	ca := Template(cn)
	ca.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign
	ca.IsCA = true
	ca.MaxPathLen = certMaxPathLen
	ca.MaxPathLenZero = true
	return ca
}

// Template returns a leaf x509 template with cn as common name.
func Template(cn string) *x509.Certificate {
	subject := pkix.Name{
		Country:            []string{"NZ"},
		Organization:       []string{"gNxI"},
		OrganizationalUnit: []string{"gNxI"},
		Locality:           []string{"gNxI"},
		Province:           []string{"gNxI"},
		StreetAddress:      []string{"gNxI"},
		PostalCode:         []string{},
		CommonName:         cn,
		Names:              []pkix.AttributeTypeAndValue{},
		ExtraNames:         []pkix.AttributeTypeAndValue{},
	}

	return &x509.Certificate{
		// AuthorityKeyId,
		BasicConstraintsValid: true,
		DNSNames:              []string{cn},
		// ExcludedDNSDomains,
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
		// IsCA,
		KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
		NotAfter:  time.Now().Add(24 * 365 * time.Hour),
		NotBefore: time.Now().Add(-1 * time.Hour),
		// PermittedDNSDomains,
		// PermittedDNSDomainsCritical,
		// SerialNumber,
		SignatureAlgorithm: x509.SHA256WithRSA,
		Subject:            subject,
		// SubjectKeyId,
		// UnknownExtKeyUsage,
	}
}
<|endoftext|>


<commit_before>package lifecycle

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/cpg1111/maestrod/datastore"
	"github.com/cpg1111/maestrod/manager"
)

// QueueEntry is an entry in the waiting and running queue
type QueueEntry struct {
	Project    string
	Branch     string
	PrevCommit string
	CurrCommit string
	CreatedAt  time.Time
	FinishedAt time.Time
	Status     string
}

type aliveKey struct {
	Project string
	Branch  string
}

// Running is the running queue
type Running struct {
	Builds    []*QueueEntry
	Alive     map[aliveKey]*QueueEntry
	KeepAlive map[aliveKey]bool
}

// CheckIn changes whether a build is alive or not
func (r *Running) CheckIn(project, branch string) {
	key := aliveKey{
		Project: project,
		Branch:  branch,
	}
	if r.Alive[key] != nil {
		r.KeepAlive[key] = true
	}
}

// Watch watches running maestro builds
func (r *Running) Watch(manager *manager.Driver) {
	for b := range r.Builds {
		key := aliveKey{
			Project: r.Builds[b].Project,
			Branch:  r.Builds[b].Branch,
		}
		if r.Alive[key] == nil {
			r.Builds = append(r.Builds[:b], r.Builds[b+1:]...)
			break
		}
		if !r.KeepAlive[key] {
			r.Alive[key] = nil
			mgrDRef := *manager
			mgrDRef.DestroyWorker(key.Project, key.Branch)
		}
	}
}

// Queue is the qaiting queue
type Queue struct {
	Queue []*QueueEntry
	store datastore.Datastore
}

// NewQueue returns a pointer to an instanc of a queue
func NewQueue(store datastore.Datastore) *Queue {
	return &Queue{
		Queue: []*QueueEntry{},
		store: store,
	}
}

func (q *Queue) set(queue []*QueueEntry) {
	q.Queue = queue
}

type lastSuccess struct {
	Commit string
}

func (q *Queue) getLastSuccess(proj, branch string) (string, error) {
	resChan := make(chan string)
	errChan := make(chan error)
	key := fmt.Sprintf("success-%s-%s", proj, branch)
	q.store.Find(key, func(res []byte, err error) {
		if err != nil {
			errChan <- err
			close(resChan)
			return
		}
		if len(res) == 0 {
			innerChan := make(chan []byte)
			innerKey := fmt.Sprintf("success-%s", proj)
			q.store.Find(innerKey, func(innerRes []byte, innerErr error) {
				if innerErr != nil {
					errChan <- err
					close(innerChan)
					return
				}
				innerChan <- innerRes
			})
			res = <-innerChan
		}
		decRes := &lastSuccess{}
		errChan <- json.Unmarshal(res, decRes)
		resChan <- decRes.Commit
	})
	commit := <-resChan
	cErr := <-errChan
	return commit, cErr
}

func (q *Queue) saveLastSuccess(proj, branch, last string) error {
	errChan := make(chan error)
	key1 := fmt.Sprintf("success-%s-%s", proj, branch)
	key2 := fmt.Sprintf("success-%s", proj)
	lastSucc := lastSuccess{Commit: last}
	q.store.Save(key1, lastSucc, func(err error) {
		errChan <- err
	})
	q.store.Save(key2, lastSucc, func(err error) {
		errChan <- err
	})
	for errCount := 0; errCount < 2; {
		err := <-errChan
		if err != nil {
			return err
		}
		errCount++
	}
	close(errChan)
	return nil
}

// Add adds a project to the queue
func (q *Queue) Add(proj, branch, prevCommit, currCommit string) {
	last, lastErr := q.getLastSuccess(proj, branch)
	if lastErr != nil || len(last) == 0 {
		if lastErr != nil {
			fmt.Println("WARNING:", lastErr.Error())
		}
		last = prevCommit
	}
	newEntry := &QueueEntry{
		Project:    proj,
		Branch:     branch,
		PrevCommit: last,
		CurrCommit: currCommit,
		CreatedAt:  time.Now(),
		Status:     "queued",
	}
	q.Queue = append(q.Queue, newEntry)
}

// Pop pops the index 0 of the queue if it can run
func (q *Queue) Pop(r *Running, maxBuilds int) *QueueEntry {
	if len(q.Queue) == 0 {
		return nil
	}
	next := q.Queue[0]
	if len(r.Builds) == 0 {
		r.Builds = []*QueueEntry{next}
		q.Queue = q.Queue[1:]
		return next
	} else if len(r.Builds) < maxBuilds {
		for i := range r.Builds {
			if !(r.Builds[i].Project == next.Project && r.Builds[i].Branch == next.Branch) {
				r.Builds = append(r.Builds, next)
				key := aliveKey{
					Project: next.Project,
					Branch:  next.Branch,
				}
				r.Alive[key] = next
				q.Queue = q.Queue[1:]
				return next
			}
		}
	}
	return nil
}

// SnapShot saves the queue's current state
func (q *Queue) SnapShot() error {
	errChan := make(chan error)
	q.store.Save("queue", q.Queue, func(err error) {
		errChan <- err
	})
	saveErr := <-errChan
	return saveErr
}
<commit_msg>make last success methods public<commit_after>package lifecycle

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/cpg1111/maestrod/datastore"
	"github.com/cpg1111/maestrod/manager"
)

// QueueEntry is an entry in the waiting and running queue
type QueueEntry struct {
	Project    string
	Branch     string
	PrevCommit string
	CurrCommit string
	CreatedAt  time.Time
	FinishedAt time.Time
	Status     string
}

type aliveKey struct {
	Project string
	Branch  string
}

// Running is the running queue
type Running struct {
	Builds    []*QueueEntry
	Alive     map[aliveKey]*QueueEntry
	KeepAlive map[aliveKey]bool
}

// CheckIn changes whether a build is alive or not
func (r *Running) CheckIn(project, branch string) {
	key := aliveKey{
		Project: project,
		Branch:  branch,
	}
	if r.Alive[key] != nil {
		r.KeepAlive[key] = true
	}
}

// Watch watches running maestro builds
func (r *Running) Watch(manager *manager.Driver) {
	for b := range r.Builds {
		key := aliveKey{
			Project: r.Builds[b].Project,
			Branch:  r.Builds[b].Branch,
		}
		if r.Alive[key] == nil {
			r.Builds = append(r.Builds[:b], r.Builds[b+1:]...)
			break
		}
		if !r.KeepAlive[key] {
			r.Alive[key] = nil
			mgrDRef := *manager
			mgrDRef.DestroyWorker(key.Project, key.Branch)
		}
	}
}

// Queue is the qaiting queue
type Queue struct {
	Queue []*QueueEntry
	store datastore.Datastore
}

// NewQueue returns a pointer to an instanc of a queue
func NewQueue(store datastore.Datastore) *Queue {
	return &Queue{
		Queue: []*QueueEntry{},
		store: store,
	}
}

func (q *Queue) set(queue []*QueueEntry) {
	q.Queue = queue
}

type lastSuccess struct {
	Commit string
}

func (q *Queue) GetLastSuccess(proj, branch string) (string, error) {
	resChan := make(chan string)
	errChan := make(chan error)
	key := fmt.Sprintf("success-%s-%s", proj, branch)
	q.store.Find(key, func(res []byte, err error) {
		if err != nil {
			errChan <- err
			close(resChan)
			return
		}
		if len(res) == 0 {
			innerChan := make(chan []byte)
			innerKey := fmt.Sprintf("success-%s", proj)
			q.store.Find(innerKey, func(innerRes []byte, innerErr error) {
				if innerErr != nil {
					errChan <- err
					close(innerChan)
					return
				}
				innerChan <- innerRes
			})
			res = <-innerChan
		}
		decRes := &lastSuccess{}
		errChan <- json.Unmarshal(res, decRes)
		resChan <- decRes.Commit
	})
	commit := <-resChan
	cErr := <-errChan
	return commit, cErr
}

func (q *Queue) SaveLastSuccess(proj, branch, last string) error {
	errChan := make(chan error)
	key1 := fmt.Sprintf("success-%s-%s", proj, branch)
	key2 := fmt.Sprintf("success-%s", proj)
	lastSucc := lastSuccess{Commit: last}
	q.store.Save(key1, lastSucc, func(err error) {
		errChan <- err
	})
	q.store.Save(key2, lastSucc, func(err error) {
		errChan <- err
	})
	for errCount := 0; errCount < 2; {
		err := <-errChan
		if err != nil {
			return err
		}
		errCount++
	}
	close(errChan)
	return nil
}

// Add adds a project to the queue
func (q *Queue) Add(proj, branch, prevCommit, currCommit string) {
	last, lastErr := q.getLastSuccess(proj, branch)
	if lastErr != nil || len(last) == 0 {
		if lastErr != nil {
			fmt.Println("WARNING:", lastErr.Error())
		}
		last = prevCommit
	}
	newEntry := &QueueEntry{
		Project:    proj,
		Branch:     branch,
		PrevCommit: last,
		CurrCommit: currCommit,
		CreatedAt:  time.Now(),
		Status:     "queued",
	}
	q.Queue = append(q.Queue, newEntry)
}

// Pop pops the index 0 of the queue if it can run
func (q *Queue) Pop(r *Running, maxBuilds int) *QueueEntry {
	if len(q.Queue) == 0 {
		return nil
	}
	next := q.Queue[0]
	if len(r.Builds) == 0 {
		r.Builds = []*QueueEntry{next}
		q.Queue = q.Queue[1:]
		return next
	} else if len(r.Builds) < maxBuilds {
		for i := range r.Builds {
			if !(r.Builds[i].Project == next.Project && r.Builds[i].Branch == next.Branch) {
				r.Builds = append(r.Builds, next)
				key := aliveKey{
					Project: next.Project,
					Branch:  next.Branch,
				}
				r.Alive[key] = next
				q.Queue = q.Queue[1:]
				return next
			}
		}
	}
	return nil
}

// SnapShot saves the queue's current state
func (q *Queue) SnapShot() error {
	errChan := make(chan error)
	q.store.Save("queue", q.Queue, func(err error) {
		errChan <- err
	})
	saveErr := <-errChan
	return saveErr
}
<|endoftext|>


<commit_before>package manifests

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/ghodss/yaml"
	"github.com/pkg/errors"

	"github.com/openshift/installer/pkg/asset"
	"github.com/openshift/installer/pkg/asset/installconfig"
	"github.com/openshift/installer/pkg/asset/templates/content"

	configv1 "github.com/openshift/api/config/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
	ingCrdFilename = "cluster-ingress-01-crd.yaml"
	ingCfgFilename = filepath.Join(manifestDir, "cluster-ingress-02-config.yml")
)

// Ingress generates the cluster-ingress-*.yml files.
type Ingress struct {
	config   *configv1.Ingress
	FileList []*asset.File
}

var _ asset.WritableAsset = (*Ingress)(nil)

// Name returns a human friendly name for the asset.
func (*Ingress) Name() string {
	return "Ingress Config"
}

// Dependencies returns all of the dependencies directly needed to generate
// the asset.
func (*Ingress) Dependencies() []asset.Asset {
	return []asset.Asset{
		&installconfig.InstallConfig{},
	}
}

// Generate generates the ingress config and its CRD.
func (ing *Ingress) Generate(dependencies asset.Parents) error {
	installConfig := &installconfig.InstallConfig{}
	dependencies.Get(installConfig)

	ing.config = &configv1.Ingress{
		TypeMeta: metav1.TypeMeta{
			APIVersion: configv1.SchemeGroupVersion.String(),
			Kind:       "Ingress",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: "default",
			// not namespaced
		},
		Spec: configv1.IngressSpec{
			Domain: fmt.Sprintf("apps.%s.%s", installConfig.Config.ObjectMeta.Name, installConfig.Config.BaseDomain),
		},
	}

	configData, err := yaml.Marshal(ing.config)
	if err != nil {
		return errors.Wrapf(err, "failed to create %s manifests from InstallConfig", ing.Name())
	}

	crdData, err := content.GetBootkubeTemplate(ingCrdFilename)
	if err != nil {
		return err
	}

	ing.FileList = []*asset.File{
		{
			Filename: filepath.Join(content.TemplateDir, ingCrdFilename),
			Data:     []byte(crdData),
		},
		{
			Filename: ingCfgFilename,
			Data:     configData,
		},
	}

	return nil
}

// Files returns the files generated by the asset.
func (ing *Ingress) Files() []*asset.File {
	return ing.FileList
}

// Load loads the already-rendered files back from disk.
func (ing *Ingress) Load(f asset.FileFetcher) (bool, error) {
	crdFile, err := f.FetchByName(ingCrdFilename)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}

	cfgFile, err := f.FetchByName(ingCfgFilename)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}

		return false, err
	}

	ingressConfig := &configv1.Ingress{}
	if err := yaml.Unmarshal(cfgFile.Data, ingressConfig); err != nil {
		return false, errors.Wrapf(err, "failed to unmarshal %s", ingCfgFilename)
	}

	fileList := []*asset.File{crdFile, cfgFile}

	ing.FileList, ing.config = fileList, ingressConfig

	return true, nil
}
<commit_msg>asset/manifests: fix filepath for ingress crd<commit_after>package manifests

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/ghodss/yaml"
	"github.com/pkg/errors"

	"github.com/openshift/installer/pkg/asset"
	"github.com/openshift/installer/pkg/asset/installconfig"
	"github.com/openshift/installer/pkg/asset/templates/content"

	configv1 "github.com/openshift/api/config/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
	ingCrdFilename = "cluster-ingress-01-crd.yaml"
	ingCfgFilename = filepath.Join(manifestDir, "cluster-ingress-02-config.yml")
)

// Ingress generates the cluster-ingress-*.yml files.
type Ingress struct {
	config   *configv1.Ingress
	FileList []*asset.File
}

var _ asset.WritableAsset = (*Ingress)(nil)

// Name returns a human friendly name for the asset.
func (*Ingress) Name() string {
	return "Ingress Config"
}

// Dependencies returns all of the dependencies directly needed to generate
// the asset.
func (*Ingress) Dependencies() []asset.Asset {
	return []asset.Asset{
		&installconfig.InstallConfig{},
	}
}

// Generate generates the ingress config and its CRD.
func (ing *Ingress) Generate(dependencies asset.Parents) error {
	installConfig := &installconfig.InstallConfig{}
	dependencies.Get(installConfig)

	ing.config = &configv1.Ingress{
		TypeMeta: metav1.TypeMeta{
			APIVersion: configv1.SchemeGroupVersion.String(),
			Kind:       "Ingress",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: "default",
			// not namespaced
		},
		Spec: configv1.IngressSpec{
			Domain: fmt.Sprintf("apps.%s.%s", installConfig.Config.ObjectMeta.Name, installConfig.Config.BaseDomain),
		},
	}

	configData, err := yaml.Marshal(ing.config)
	if err != nil {
		return errors.Wrapf(err, "failed to create %s manifests from InstallConfig", ing.Name())
	}

	crdData, err := content.GetBootkubeTemplate(ingCrdFilename)
	if err != nil {
		return err
	}

	ing.FileList = []*asset.File{
		{
			Filename: filepath.Join(manifestDir, ingCrdFilename),
			Data:     []byte(crdData),
		},
		{
			Filename: ingCfgFilename,
			Data:     configData,
		},
	}

	return nil
}

// Files returns the files generated by the asset.
func (ing *Ingress) Files() []*asset.File {
	return ing.FileList
}

// Load loads the already-rendered files back from disk.
func (ing *Ingress) Load(f asset.FileFetcher) (bool, error) {
	crdFile, err := f.FetchByName(filepath.Join(manifestDir, ingCrdFilename))
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}

	cfgFile, err := f.FetchByName(ingCfgFilename)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}

		return false, err
	}

	ingressConfig := &configv1.Ingress{}
	if err := yaml.Unmarshal(cfgFile.Data, ingressConfig); err != nil {
		return false, errors.Wrapf(err, "failed to unmarshal %s", ingCfgFilename)
	}

	fileList := []*asset.File{crdFile, cfgFile}

	ing.FileList, ing.config = fileList, ingressConfig

	return true, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 controller

import (
	"fmt"
	"github.com/golang/glog"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/types"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/utils"
	"k8s.io/ingress/core/pkg/ingress"
	"reflect"
	"sort"
)

// convert a list of ingress backends to a map with backend names as keys
func ingressBackendsRemap(backends []*ingress.Backend) (map[string]*ingress.Backend, []string) {
	backendsMap := map[string]*ingress.Backend{}
	keys := []string{}
	for _, ingBackend := range backends {
		backendsMap[ingBackend.Name] = ingBackend
		keys = append(keys, ingBackend.Name)
	}
	sort.Strings(keys)
	return backendsMap, keys
}

// convert a list of endpoints to a map with address:port as keys
func ingressEndpointsRemap(endpoints []ingress.Endpoint) map[string]*ingress.Endpoint {
	endpointMap := map[string]*ingress.Endpoint{}
	for i, e := range endpoints {
		endpointMap[fmt.Sprintf("%s:%s", e.Address, e.Port)] = &endpoints[i]
	}
	return endpointMap
}

// return elements in s1 but not in s2
func endpointsSubtract(s1, s2 map[string]*ingress.Endpoint) map[string]*ingress.Endpoint {
	s3 := map[string]*ingress.Endpoint{}
	for k, v := range s1 {
		_, ok := s2[k]
		if !ok {
			s3[k] = v
		}
	}
	return s3
}

// remove Ingress Endpoint from a backend by disabling a specific server slot
func removeEndpoint(statsSocket, backendName, backendServerName string) bool {
	err := utils.SendToSocket(statsSocket,
		fmt.Sprintf("set server %s/%s state maint\n", backendName, backendServerName))
	if err != nil {
		glog.Warningln("failed socket command srv remove")
		return false
	}
	return true
}

// add Ingress Endpoint to a backend in a specific server slot
func addEndpoint(statsSocket, backendName, backendServerName, address, port string) bool {
	err1 := utils.SendToSocket(statsSocket,
		fmt.Sprintf("set server %s/%s addr %s port %s\n", backendName, backendServerName, address, port))
	err2 := utils.SendToSocket(statsSocket,
		fmt.Sprintf("set server %s/%s state ready\n", backendName, backendServerName))
	if err1 != nil || err2 != nil {
		glog.Warningln("failed socket command srv add")
		return false
	}
	return true
}

// populate template variables and optionally issue socket commands to reconfigure haproxy without reloading
func reconfigureBackends(currentConfig, updatedConfig *types.ControllerConfig) bool {
	reloadRequired := true
	reconfigureEmptySlots := false

	if !updatedConfig.Cfg.DynamicScaling {
		reconfigureEmptySlots = true
	} else if currentConfig != nil {
		// store backend lists for retrieval
		curBackends := currentConfig.Backends
		updBackends := updatedConfig.Backends
		// store BackendSlots for retrieval
		curBackendSlots := currentConfig.BackendSlots

		// exclude backend lists and slots from reflect.DeepEqual
		updatedConfig.Backends = []*ingress.Backend{}
		currentConfig.Backends = updatedConfig.Backends
		currentConfig.BackendSlots = updatedConfig.BackendSlots

		// check equality of everything but backends
		if !reflect.DeepEqual(updatedConfig, currentConfig) {
			reconfigureEmptySlots = true
		} else {
			// set up maps
			curBackendsMap, curKeys := ingressBackendsRemap(curBackends)
			updBackendsMap, updKeys := ingressBackendsRemap(updBackends)

			if !reflect.DeepEqual(curKeys, updKeys) {
				// backend names or number of backends is different
				reconfigureEmptySlots = true
			} else {
				// same names and nr of backends, we can modify existing HAProxyBackendSlots, should not need reloading
				reloadRequired = false
				updatedConfig.BackendSlots = curBackendSlots
				for _, backendName := range curKeys {
					updLen := len(updBackendsMap[backendName].Endpoints)
					totalSlots := len(curBackendSlots[backendName].EmptySlots) + len(curBackendSlots[backendName].FullSlots)
					if updLen > totalSlots || updLen < (totalSlots-updatedConfig.Cfg.BackendServerSlotsIncrement) {
						// need to resize number of empty slots by BackendServerSlotsIncrement amount
						reconfigureEmptySlots = true
					} else {
						// everything fits so reconfigure endpoints without reloading
						// do it with maps posing as sets
						curEndpoints := ingressEndpointsRemap(curBackendsMap[backendName].Endpoints)
						updEndpoints := ingressEndpointsRemap(updBackendsMap[backendName].Endpoints)

						toRemoveEndpoints := endpointsSubtract(curEndpoints, updEndpoints)
						toAddEndpoints := endpointsSubtract(updEndpoints, curEndpoints)

						// check for new/removed entries in this backend, issue socket commands
						backendSlots := updatedConfig.BackendSlots[backendName]
						// remove endpoints
						for k := range toRemoveEndpoints {
							reloadRequired = !removeEndpoint(currentConfig.Cfg.StatsSocket, backendName, backendSlots.FullSlots[k].BackendServerName)
							backendSlots.EmptySlots = append(backendSlots.EmptySlots, backendSlots.FullSlots[k].BackendServerName)
							delete(backendSlots.FullSlots, k)
						}
						sort.Strings(backendSlots.EmptySlots)
						// add endpoints
						for k, endpoint := range toAddEndpoints {
							// rearrange slots
							backendSlots.FullSlots[k] = types.HAProxyBackendSlot{
								BackendServerName: backendSlots.EmptySlots[0],
								BackendEndpoint:   endpoint,
							}
							backendSlots.EmptySlots = backendSlots.EmptySlots[1:]
							reloadRequired = !addEndpoint(currentConfig.Cfg.StatsSocket, backendName, backendSlots.FullSlots[k].BackendServerName, endpoint.Address, endpoint.Port)
						}
						updatedConfig.BackendSlots[backendName] = backendSlots
					}
				}
			}
		}
		// restore backend lists
		currentConfig.Backends = curBackends
		updatedConfig.Backends = updBackends
		// restore backend slots
		currentConfig.BackendSlots = curBackendSlots
	}

	if currentConfig == nil || reconfigureEmptySlots {
		fillBackendServerSlots(updatedConfig)
		reloadRequired = true
	}

	return reloadRequired
}

// fill-out backends with available endpoints, add empty slots if required
func fillBackendServerSlots(updatedConfig *types.ControllerConfig) {
	updBackendsMap, updKeys := ingressBackendsRemap(updatedConfig.Backends)
	updatedConfig.BackendSlots = map[string]types.HAProxyBackendSlots{}

	for _, backendName := range updKeys {
		newBackend := types.HAProxyBackendSlots{}
		newBackend.FullSlots = map[string]types.HAProxyBackendSlot{}
		if updatedConfig.Cfg.DynamicScaling {
			for i, endpoint := range updBackendsMap[backendName].Endpoints {
				newBackend.FullSlots[fmt.Sprintf("%s:%s", endpoint.Address, endpoint.Port)] = types.HAProxyBackendSlot{
					BackendServerName: fmt.Sprintf("server%04d", i),
					BackendEndpoint:   &endpoint,
				}
			}
			// add up to BackendServerSlotsIncrement empty slots
			fullSlotCnt := len(newBackend.FullSlots)
			extraSlotCnt := (int(fullSlotCnt/updatedConfig.Cfg.BackendServerSlotsIncrement)+1)*updatedConfig.Cfg.BackendServerSlotsIncrement - fullSlotCnt
			for i := 0; i < extraSlotCnt; i++ {
				newBackend.EmptySlots = append(newBackend.EmptySlots, fmt.Sprintf("server%04d", i+fullSlotCnt))
			}
		} else {
			// use addr:port as BackendServerName, don't generate empty slots
			for _, endpoint := range updBackendsMap[backendName].Endpoints {
				target := fmt.Sprintf("%s:%s", endpoint.Address, endpoint.Port)
				newBackend.FullSlots[target] = types.HAProxyBackendSlot{
					BackendServerName: target,
					BackendEndpoint:   &endpoint,
				}
			}
		}
		updatedConfig.BackendSlots[backendName] = newBackend
	}
}
<commit_msg>fix reloadRequired potentially not set correctly if only some socket commands fail<commit_after>/*
Copyright 2017 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 controller

import (
	"fmt"
	"github.com/golang/glog"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/types"
	"github.com/jcmoraisjr/haproxy-ingress/pkg/utils"
	"k8s.io/ingress/core/pkg/ingress"
	"reflect"
	"sort"
)

// convert a list of ingress backends to a map with backend names as keys
func ingressBackendsRemap(backends []*ingress.Backend) (map[string]*ingress.Backend, []string) {
	backendsMap := map[string]*ingress.Backend{}
	keys := []string{}
	for _, ingBackend := range backends {
		backendsMap[ingBackend.Name] = ingBackend
		keys = append(keys, ingBackend.Name)
	}
	sort.Strings(keys)
	return backendsMap, keys
}

// convert a list of endpoints to a map with address:port as keys
func ingressEndpointsRemap(endpoints []ingress.Endpoint) map[string]*ingress.Endpoint {
	endpointMap := map[string]*ingress.Endpoint{}
	for i, e := range endpoints {
		endpointMap[fmt.Sprintf("%s:%s", e.Address, e.Port)] = &endpoints[i]
	}
	return endpointMap
}

// return elements in s1 but not in s2
func endpointsSubtract(s1, s2 map[string]*ingress.Endpoint) map[string]*ingress.Endpoint {
	s3 := map[string]*ingress.Endpoint{}
	for k, v := range s1 {
		_, ok := s2[k]
		if !ok {
			s3[k] = v
		}
	}
	return s3
}

// remove Ingress Endpoint from a backend by disabling a specific server slot
func removeEndpoint(statsSocket, backendName, backendServerName string) bool {
	err := utils.SendToSocket(statsSocket,
		fmt.Sprintf("set server %s/%s state maint\n", backendName, backendServerName))
	if err != nil {
		glog.Warningln("failed socket command srv remove")
		return false
	}
	return true
}

// add Ingress Endpoint to a backend in a specific server slot
func addEndpoint(statsSocket, backendName, backendServerName, address, port string) bool {
	err1 := utils.SendToSocket(statsSocket,
		fmt.Sprintf("set server %s/%s addr %s port %s\n", backendName, backendServerName, address, port))
	err2 := utils.SendToSocket(statsSocket,
		fmt.Sprintf("set server %s/%s state ready\n", backendName, backendServerName))
	if err1 != nil || err2 != nil {
		glog.Warningln("failed socket command srv add")
		return false
	}
	return true
}

// populate template variables and optionally issue socket commands to reconfigure haproxy without reloading
func reconfigureBackends(currentConfig, updatedConfig *types.ControllerConfig) bool {
	reloadRequired := true
	reconfigureEmptySlots := false

	if !updatedConfig.Cfg.DynamicScaling {
		reconfigureEmptySlots = true
	} else if currentConfig != nil {
		// store backend lists for retrieval
		curBackends := currentConfig.Backends
		updBackends := updatedConfig.Backends
		// store BackendSlots for retrieval
		curBackendSlots := currentConfig.BackendSlots

		// exclude backend lists and slots from reflect.DeepEqual
		updatedConfig.Backends = []*ingress.Backend{}
		currentConfig.Backends = updatedConfig.Backends
		currentConfig.BackendSlots = updatedConfig.BackendSlots

		// check equality of everything but backends
		if !reflect.DeepEqual(updatedConfig, currentConfig) {
			reconfigureEmptySlots = true
		} else {
			// set up maps
			curBackendsMap, curKeys := ingressBackendsRemap(curBackends)
			updBackendsMap, updKeys := ingressBackendsRemap(updBackends)

			if !reflect.DeepEqual(curKeys, updKeys) {
				// backend names or number of backends is different
				reconfigureEmptySlots = true
			} else {
				// same names and nr of backends, we can modify existing HAProxyBackendSlots, should not need reloading
				reloadRequired = false
				updatedConfig.BackendSlots = curBackendSlots
				for _, backendName := range curKeys {
					updLen := len(updBackendsMap[backendName].Endpoints)
					totalSlots := len(curBackendSlots[backendName].EmptySlots) + len(curBackendSlots[backendName].FullSlots)
					if updLen > totalSlots || updLen < (totalSlots-updatedConfig.Cfg.BackendServerSlotsIncrement) {
						// need to resize number of empty slots by BackendServerSlotsIncrement amount
						reconfigureEmptySlots = true
					} else {
						// everything fits so reconfigure endpoints without reloading
						// do it with maps posing as sets
						curEndpoints := ingressEndpointsRemap(curBackendsMap[backendName].Endpoints)
						updEndpoints := ingressEndpointsRemap(updBackendsMap[backendName].Endpoints)

						toRemoveEndpoints := endpointsSubtract(curEndpoints, updEndpoints)
						toAddEndpoints := endpointsSubtract(updEndpoints, curEndpoints)

						// check for new/removed entries in this backend, issue socket commands
						backendSlots := updatedConfig.BackendSlots[backendName]
						// remove endpoints
						for k := range toRemoveEndpoints {
							reloadRequired = reloadRequired || !removeEndpoint(currentConfig.Cfg.StatsSocket, backendName, backendSlots.FullSlots[k].BackendServerName)
							backendSlots.EmptySlots = append(backendSlots.EmptySlots, backendSlots.FullSlots[k].BackendServerName)
							delete(backendSlots.FullSlots, k)
						}
						sort.Strings(backendSlots.EmptySlots)
						// add endpoints
						for k, endpoint := range toAddEndpoints {
							// rearrange slots
							backendSlots.FullSlots[k] = types.HAProxyBackendSlot{
								BackendServerName: backendSlots.EmptySlots[0],
								BackendEndpoint:   endpoint,
							}
							backendSlots.EmptySlots = backendSlots.EmptySlots[1:]
							reloadRequired = reloadRequired || !addEndpoint(currentConfig.Cfg.StatsSocket, backendName, backendSlots.FullSlots[k].BackendServerName, endpoint.Address, endpoint.Port)
						}
						updatedConfig.BackendSlots[backendName] = backendSlots
					}
				}
			}
		}
		// restore backend lists
		currentConfig.Backends = curBackends
		updatedConfig.Backends = updBackends
		// restore backend slots
		currentConfig.BackendSlots = curBackendSlots
	}

	if currentConfig == nil || reconfigureEmptySlots {
		fillBackendServerSlots(updatedConfig)
		reloadRequired = true
	}

	return reloadRequired
}

// fill-out backends with available endpoints, add empty slots if required
func fillBackendServerSlots(updatedConfig *types.ControllerConfig) {
	updBackendsMap, updKeys := ingressBackendsRemap(updatedConfig.Backends)
	updatedConfig.BackendSlots = map[string]types.HAProxyBackendSlots{}

	for _, backendName := range updKeys {
		newBackend := types.HAProxyBackendSlots{}
		newBackend.FullSlots = map[string]types.HAProxyBackendSlot{}
		if updatedConfig.Cfg.DynamicScaling {
			for i, endpoint := range updBackendsMap[backendName].Endpoints {
				newBackend.FullSlots[fmt.Sprintf("%s:%s", endpoint.Address, endpoint.Port)] = types.HAProxyBackendSlot{
					BackendServerName: fmt.Sprintf("server%04d", i),
					BackendEndpoint:   &endpoint,
				}
			}
			// add up to BackendServerSlotsIncrement empty slots
			fullSlotCnt := len(newBackend.FullSlots)
			extraSlotCnt := (int(fullSlotCnt/updatedConfig.Cfg.BackendServerSlotsIncrement)+1)*updatedConfig.Cfg.BackendServerSlotsIncrement - fullSlotCnt
			for i := 0; i < extraSlotCnt; i++ {
				newBackend.EmptySlots = append(newBackend.EmptySlots, fmt.Sprintf("server%04d", i+fullSlotCnt))
			}
		} else {
			// use addr:port as BackendServerName, don't generate empty slots
			for _, endpoint := range updBackendsMap[backendName].Endpoints {
				target := fmt.Sprintf("%s:%s", endpoint.Address, endpoint.Port)
				newBackend.FullSlots[target] = types.HAProxyBackendSlot{
					BackendServerName: target,
					BackendEndpoint:   &endpoint,
				}
			}
		}
		updatedConfig.BackendSlots[backendName] = newBackend
	}
}
<|endoftext|>


<commit_before>package templates

const Dockerfile = `
# {{.ImageName}}
FROM openshift/base-centos7

# TODO: Put the maintainer name in the image metadata
# MAINTAINER Your Name <your@email.com>

# TODO: Rename the builder environment variable to inform users about application you provide them
# ENV BUILDER_VERSION 1.0

# TODO: Set labels used in OpenShift to describe the builder image
#LABEL io.k8s.description="Platform for building xyz" \
#      io.k8s.display-name="builder x.y.z" \
#      io.openshift.expose-services="8080:http" \
#      io.openshift.tags="builder,x.y.z,etc."

# TODO: Install required packages here:
# RUN yum install -y ... && yum clean all -y

# TODO (optional): Copy the builder files into /opt/openshift
# COPY ./<builder_folder>/ /opt/openshift/

# TODO: Copy the S2I scripts to /usr/local/sti, since openshift/base-centos7 image sets io.openshift.s2i.scripts-url label that way, or update that label
# COPY ./.sti/bin/ /usr/local/sti

# TODO: Drop the root user and make the content of /opt/openshift owned by user 1001
# RUN chown -R 1001:1001 /opt/openshift

# This default user is created in the openshift/base-centos7 image
USER 1001

# TODO: Set the default port for applications built using this image
# EXPOSE 8080

# TODO: Set the default CMD for the image
# CMD ["usage"]
`
<commit_msg>Rename /opt/openshift to /opt/app-root<commit_after>package templates

const Dockerfile = `
# {{.ImageName}}
FROM openshift/base-centos7

# TODO: Put the maintainer name in the image metadata
# MAINTAINER Your Name <your@email.com>

# TODO: Rename the builder environment variable to inform users about application you provide them
# ENV BUILDER_VERSION 1.0

# TODO: Set labels used in OpenShift to describe the builder image
#LABEL io.k8s.description="Platform for building xyz" \
#      io.k8s.display-name="builder x.y.z" \
#      io.openshift.expose-services="8080:http" \
#      io.openshift.tags="builder,x.y.z,etc."

# TODO: Install required packages here:
# RUN yum install -y ... && yum clean all -y

# TODO (optional): Copy the builder files into /opt/app-root
# COPY ./<builder_folder>/ /opt/app-root/

# TODO: Copy the S2I scripts to /usr/local/sti, since openshift/base-centos7 image sets io.openshift.s2i.scripts-url label that way, or update that label
# COPY ./.sti/bin/ /usr/local/sti

# TODO: Drop the root user and make the content of /opt/app-root owned by user 1001
# RUN chown -R 1001:1001 /opt/app-root

# This default user is created in the openshift/base-centos7 image
USER 1001

# TODO: Set the default port for applications built using this image
# EXPOSE 8080

# TODO: Set the default CMD for the image
# CMD ["usage"]
`
<|endoftext|>