<commit_before>package nginx

import (
	"fmt"
	"strings"
	"sync"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
)

const emptyHost = ""

// Configurator transforms an Ingress resource into NGINX Configuration
type Configurator struct {
	nginx  *NginxController
	config *Config
	lock   sync.Mutex
}

// NewConfigurator creates a new Configurator
func NewConfigurator(nginx *NginxController, config *Config) *Configurator {
	cnf := Configurator{
		nginx:  nginx,
		config: config,
	}

	return &cnf
}

// UpdateEndpoints updates endpoints in NGINX configuration for an Ingress resource
func (cnf *Configurator) UpdateEndpoints(name string, ingEx *IngressEx) {
	cnf.AddOrUpdateIngress(name, ingEx)
}

// AddOrUpdateIngress adds or updates NGINX configuration for an Ingress resource
func (cnf *Configurator) AddOrUpdateIngress(name string, ingEx *IngressEx) {
	cnf.lock.Lock()
	defer cnf.lock.Unlock()

	pems := cnf.updateCertificates(ingEx)
	nginxCfg := cnf.generateNginxCfg(ingEx, pems)
	glog.V(3).Infof("Generated IngressNginxConfig: \n%v", nginxCfg)
	cnf.nginx.AddOrUpdateIngress(name, nginxCfg)
	if err := cnf.nginx.Reload(); err != nil {
		glog.Errorf("Error when adding or updating ingress %q: %q", name, err)
	}
}

func (cnf *Configurator) updateCertificates(ingEx *IngressEx) map[string]string {
	pems := make(map[string]string)

	for _, tls := range ingEx.Ingress.Spec.TLS {
		secretName := tls.SecretName
		secret, exist := ingEx.Secrets[secretName]
		if !exist {
			continue
		}
		cert, ok := secret.Data[api.TLSCertKey]
		if !ok {
			glog.Warningf("Secret %v has no private key", secretName)
			continue
		}
		key, ok := secret.Data[api.TLSPrivateKeyKey]
		if !ok {
			glog.Warningf("Secret %v has no cert", secretName)
			continue
		}

		name := ingEx.Ingress.Namespace + "-" + secretName
		pemFileName := cnf.nginx.AddOrUpdateCertAndKey(name, string(cert), string(key))

		for _, host := range tls.Hosts {
			pems[host] = pemFileName
		}
		if len(tls.Hosts) == 0 {
			pems[emptyHost] = pemFileName
		}
	}

	return pems
}

func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]string) IngressNginxConfig {
	ingCfg := cnf.createConfig(ingEx)

	upstreams := make(map[string]Upstream)

	wsServices := getWebsocketServices(ingEx)

	labels := ingEx.Ingress.ObjectMeta.Labels

	if ingEx.Ingress.Spec.Backend != nil {
		name := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)
		upstream := cnf.createUpstream(ingEx, name, ingEx.Ingress.Spec.Backend, ingEx.Ingress.Namespace)
		upstreams[name] = upstream
	}

	var servers []Server

	for _, rule := range ingEx.Ingress.Spec.Rules {
		if rule.IngressRuleValue.HTTP == nil {
			continue
		}

		serverName := rule.Host

		if rule.Host == emptyHost {
			glog.Warningf("Host field of ingress rule in %v/%v is empty", ingEx.Ingress.Namespace, ingEx.Ingress.Name)
		}

		server := Server{Name: serverName}

		if pemFile, ok := pems[serverName]; ok {
			server.SSL = true
			server.SSLCertificate = pemFile
			server.SSLCertificateKey = pemFile
		}

		var locations []Location
		rootLocation := false

		for _, path := range rule.HTTP.Paths {
			upsName := getNameForUpstream(ingEx.Ingress, rule.Host, path.Backend.ServiceName)

			if _, exists := upstreams[upsName]; !exists {
				upstream := cnf.createUpstream(ingEx, upsName, &path.Backend, ingEx.Ingress.Namespace)
				upstreams[upsName] = upstream
			}

			loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName])
			locations = append(locations, loc)

			if loc.Path == "/" {
				rootLocation = true
			}
		}

		if rootLocation == false && ingEx.Ingress.Spec.Backend != nil {
			upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)
			loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
			locations = append(locations, loc)
		}

		server.Locations = locations
		servers = append(servers, server)
	}

	if len(ingEx.Ingress.Spec.Rules) == 0 && ingEx.Ingress.Spec.Backend != nil {
		server := Server{Name: emptyHost}

		if pemFile, ok := pems[emptyHost]; ok {
			server.SSL = true
			server.SSLCertificate = pemFile
			server.SSLCertificateKey = pemFile
		}

		var locations []Location

		upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName)

		loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
		locations = append(locations, loc)

		server.Locations = locations
		servers = append(servers, server)
	}

	return IngressNginxConfig{Upstreams: upstreamMapToSlice(upstreams), Servers: servers, Labels: labels}
}

func (cnf *Configurator) createConfig(ingEx *IngressEx) Config {
	ingCfg := *cnf.config
	if proxyConnectTimeout, exists := ingEx.Ingress.Annotations["nginx.org/proxy-connect-timeout"]; exists {
		ingCfg.ProxyConnectTimeout = proxyConnectTimeout
	}
	if proxyReadTimeout, exists := ingEx.Ingress.Annotations["nginx.org/proxy-read-timeout"]; exists {
		ingCfg.ProxyReadTimeout = proxyReadTimeout
	}
	if clientMaxBodySize, exists := ingEx.Ingress.Annotations["nginx.org/client-max-body-size"]; exists {
		ingCfg.ClientMaxBodySize = clientMaxBodySize
	}

	return ingCfg
}

func getWebsocketServices(ingEx *IngressEx) map[string]bool {
	wsServices := make(map[string]bool)

	if services, exists := ingEx.Ingress.Annotations["nginx.org/websocket-services"]; exists {
		for _, svc := range strings.Split(services, ",") {
			wsServices[svc] = true
		}
	}

	return wsServices
}

func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) Location {
	loc := Location{
		Path:                path,
		Upstream:            upstream,
		ProxyConnectTimeout: cfg.ProxyConnectTimeout,
		ProxyReadTimeout:    cfg.ProxyReadTimeout,
		ClientMaxBodySize:   cfg.ClientMaxBodySize,
		Websocket:           websocket,
	}

	return loc
}

func (cnf *Configurator) createUpstream(ingEx *IngressEx, name string, backend *extensions.IngressBackend, namespace string) Upstream {
	ups := NewUpstreamWithDefaultServer(name)

	endps, exists := ingEx.Endpoints[backend.ServiceName]
	if exists {
		upsServers := endpointsToUpstreamServers(*endps, backend.ServicePort.IntValue())
		if len(upsServers) > 0 {
			ups.UpstreamServers = upsServers
		}
	}

	return ups
}

func pathOrDefault(path string) string {
	if path == "" {
		return "/"
	}
	return path
}

func endpointsToUpstreamServers(endps api.Endpoints, servicePort int) []UpstreamServer {
	var upsServers []UpstreamServer
	for _, subset := range endps.Subsets {
		for _, port := range subset.Ports {
			if port.Port == servicePort {
				for _, address := range subset.Addresses {
					ups := UpstreamServer{Address: address.IP, Port: fmt.Sprintf("%v", servicePort)}
					upsServers = append(upsServers, ups)
				}
				break
			}
		}
	}

	return upsServers
}

func getNameForUpstream(ing *extensions.Ingress, host string, service string) string {
	return fmt.Sprintf("%v-%v-%v-%v", ing.Namespace, ing.Name, host, service)
}

func upstreamMapToSlice(upstreams map[string]Upstream) []Upstream {
	result := make([]Upstream, 0, len(upstreams))

	for _, ups := range upstreams {
		result = append(result, ups)
	}

	return result
}

// DeleteIngress deletes NGINX configuration for an Ingress resource
func (cnf *Configurator) DeleteIngress(name string) {
	cnf.lock.Lock()
	defer cnf.lock.Unlock()

	cnf.nginx.DeleteIngress(name)
	if err := cnf.nginx.Reload(); err != nil {
		glog.Errorf("Error when removing ingress %q: %q", name, err)
	}
}

// UpdateConfig updates NGINX Configuration parameters
func (cnf *Configurator) UpdateConfig(config *Config) {
	cnf.lock.Lock()
	defer cnf.lock.Unlock()

	cnf.config = config
	mainCfg := &NginxMainConfig{
		ServerNamesHashBucketSize: config.MainServerNamesHashBucketSize,
		ServerNamesHashMaxSize:    config.MainServerNamesHashMaxSize,
	}

	cnf.nginx.UpdateMainConfigFile(mainCfg)
}
<commit_msg>added port to name of upstream<commit_after>package nginx

import (
	"fmt"
	"strings"
	"sync"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
)

const emptyHost = ""

// Configurator transforms an Ingress resource into NGINX Configuration
type Configurator struct {
	nginx  *NginxController
	config *Config
	lock   sync.Mutex
}

// NewConfigurator creates a new Configurator
func NewConfigurator(nginx *NginxController, config *Config) *Configurator {
	cnf := Configurator{
		nginx:  nginx,
		config: config,
	}

	return &cnf
}

// UpdateEndpoints updates endpoints in NGINX configuration for an Ingress resource
func (cnf *Configurator) UpdateEndpoints(name string, ingEx *IngressEx) {
	cnf.AddOrUpdateIngress(name, ingEx)
}

// AddOrUpdateIngress adds or updates NGINX configuration for an Ingress resource
func (cnf *Configurator) AddOrUpdateIngress(name string, ingEx *IngressEx) {
	cnf.lock.Lock()
	defer cnf.lock.Unlock()

	pems := cnf.updateCertificates(ingEx)
	nginxCfg := cnf.generateNginxCfg(ingEx, pems)
	glog.V(3).Infof("Generated IngressNginxConfig: \n%v", nginxCfg)
	cnf.nginx.AddOrUpdateIngress(name, nginxCfg)
	if err := cnf.nginx.Reload(); err != nil {
		glog.Errorf("Error when adding or updating ingress %q: %q", name, err)
	}
}

func (cnf *Configurator) updateCertificates(ingEx *IngressEx) map[string]string {
	pems := make(map[string]string)

	for _, tls := range ingEx.Ingress.Spec.TLS {
		secretName := tls.SecretName
		secret, exist := ingEx.Secrets[secretName]
		if !exist {
			continue
		}
		cert, ok := secret.Data[api.TLSCertKey]
		if !ok {
			glog.Warningf("Secret %v has no private key", secretName)
			continue
		}
		key, ok := secret.Data[api.TLSPrivateKeyKey]
		if !ok {
			glog.Warningf("Secret %v has no cert", secretName)
			continue
		}

		name := ingEx.Ingress.Namespace + "-" + secretName
		pemFileName := cnf.nginx.AddOrUpdateCertAndKey(name, string(cert), string(key))

		for _, host := range tls.Hosts {
			pems[host] = pemFileName
		}
		if len(tls.Hosts) == 0 {
			pems[emptyHost] = pemFileName
		}
	}

	return pems
}

func (cnf *Configurator) generateNginxCfg(ingEx *IngressEx, pems map[string]string) IngressNginxConfig {
	ingCfg := cnf.createConfig(ingEx)

	upstreams := make(map[string]Upstream)

	wsServices := getWebsocketServices(ingEx)

	labels := ingEx.Ingress.ObjectMeta.Labels

	if ingEx.Ingress.Spec.Backend != nil {
		name := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName, ingEx.Ingress.Spec.Backend.ServicePort.String())
		upstream := cnf.createUpstream(ingEx, name, ingEx.Ingress.Spec.Backend, ingEx.Ingress.Namespace)
		upstreams[name] = upstream
	}

	var servers []Server

	for _, rule := range ingEx.Ingress.Spec.Rules {
		if rule.IngressRuleValue.HTTP == nil {
			continue
		}

		serverName := rule.Host

		if rule.Host == emptyHost {
			glog.Warningf("Host field of ingress rule in %v/%v is empty", ingEx.Ingress.Namespace, ingEx.Ingress.Name)
		}

		server := Server{Name: serverName}

		if pemFile, ok := pems[serverName]; ok {
			server.SSL = true
			server.SSLCertificate = pemFile
			server.SSLCertificateKey = pemFile
		}

		var locations []Location
		rootLocation := false

		for _, path := range rule.HTTP.Paths {
			upsName := getNameForUpstream(ingEx.Ingress, rule.Host, path.Backend.ServiceName, ingEx.Ingress.Spec.Backend.ServicePort.String())

			if _, exists := upstreams[upsName]; !exists {
				upstream := cnf.createUpstream(ingEx, upsName, &path.Backend, ingEx.Ingress.Namespace)
				upstreams[upsName] = upstream
			}

			loc := createLocation(pathOrDefault(path.Path), upstreams[upsName], &ingCfg, wsServices[path.Backend.ServiceName])
			locations = append(locations, loc)

			if loc.Path == "/" {
				rootLocation = true
			}
		}

		if rootLocation == false && ingEx.Ingress.Spec.Backend != nil {
			upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName, ingEx.Ingress.Spec.Backend.ServicePort.String())
			loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
			locations = append(locations, loc)
		}

		server.Locations = locations
		servers = append(servers, server)
	}

	if len(ingEx.Ingress.Spec.Rules) == 0 && ingEx.Ingress.Spec.Backend != nil {
		server := Server{Name: emptyHost}

		if pemFile, ok := pems[emptyHost]; ok {
			server.SSL = true
			server.SSLCertificate = pemFile
			server.SSLCertificateKey = pemFile
		}

		var locations []Location

		upsName := getNameForUpstream(ingEx.Ingress, emptyHost, ingEx.Ingress.Spec.Backend.ServiceName, ingEx.Ingress.Spec.Backend.ServicePort.String())

		loc := createLocation(pathOrDefault("/"), upstreams[upsName], &ingCfg, wsServices[ingEx.Ingress.Spec.Backend.ServiceName])
		locations = append(locations, loc)

		server.Locations = locations
		servers = append(servers, server)
	}

	return IngressNginxConfig{Upstreams: upstreamMapToSlice(upstreams), Servers: servers, Labels: labels}
}

func (cnf *Configurator) createConfig(ingEx *IngressEx) Config {
	ingCfg := *cnf.config
	if proxyConnectTimeout, exists := ingEx.Ingress.Annotations["nginx.org/proxy-connect-timeout"]; exists {
		ingCfg.ProxyConnectTimeout = proxyConnectTimeout
	}
	if proxyReadTimeout, exists := ingEx.Ingress.Annotations["nginx.org/proxy-read-timeout"]; exists {
		ingCfg.ProxyReadTimeout = proxyReadTimeout
	}
	if clientMaxBodySize, exists := ingEx.Ingress.Annotations["nginx.org/client-max-body-size"]; exists {
		ingCfg.ClientMaxBodySize = clientMaxBodySize
	}

	return ingCfg
}

func getWebsocketServices(ingEx *IngressEx) map[string]bool {
	wsServices := make(map[string]bool)

	if services, exists := ingEx.Ingress.Annotations["nginx.org/websocket-services"]; exists {
		for _, svc := range strings.Split(services, ",") {
			wsServices[svc] = true
		}
	}

	return wsServices
}

func createLocation(path string, upstream Upstream, cfg *Config, websocket bool) Location {
	loc := Location{
		Path:                path,
		Upstream:            upstream,
		ProxyConnectTimeout: cfg.ProxyConnectTimeout,
		ProxyReadTimeout:    cfg.ProxyReadTimeout,
		ClientMaxBodySize:   cfg.ClientMaxBodySize,
		Websocket:           websocket,
	}

	return loc
}

func (cnf *Configurator) createUpstream(ingEx *IngressEx, name string, backend *extensions.IngressBackend, namespace string) Upstream {
	ups := NewUpstreamWithDefaultServer(name)

	endps, exists := ingEx.Endpoints[backend.ServiceName]
	if exists {
		upsServers := endpointsToUpstreamServers(*endps, backend.ServicePort.IntValue())
		if len(upsServers) > 0 {
			ups.UpstreamServers = upsServers
		}
	}

	return ups
}

func pathOrDefault(path string) string {
	if path == "" {
		return "/"
	}
	return path
}

func endpointsToUpstreamServers(endps api.Endpoints, servicePort int) []UpstreamServer {
	var upsServers []UpstreamServer
	for _, subset := range endps.Subsets {
		for _, port := range subset.Ports {
			if port.Port == servicePort {
				for _, address := range subset.Addresses {
					ups := UpstreamServer{Address: address.IP, Port: fmt.Sprintf("%v", servicePort)}
					upsServers = append(upsServers, ups)
				}
				break
			}
		}
	}

	return upsServers
}

func getNameForUpstream(ing *extensions.Ingress, host string, service string, port string) string {
	return fmt.Sprintf("%v-%v-%v-%v-%v", ing.Namespace, ing.Name, host, service, port)
}

func upstreamMapToSlice(upstreams map[string]Upstream) []Upstream {
	result := make([]Upstream, 0, len(upstreams))

	for _, ups := range upstreams {
		result = append(result, ups)
	}

	return result
}

// DeleteIngress deletes NGINX configuration for an Ingress resource
func (cnf *Configurator) DeleteIngress(name string) {
	cnf.lock.Lock()
	defer cnf.lock.Unlock()

	cnf.nginx.DeleteIngress(name)
	if err := cnf.nginx.Reload(); err != nil {
		glog.Errorf("Error when removing ingress %q: %q", name, err)
	}
}

// UpdateConfig updates NGINX Configuration parameters
func (cnf *Configurator) UpdateConfig(config *Config) {
	cnf.lock.Lock()
	defer cnf.lock.Unlock()

	cnf.config = config
	mainCfg := &NginxMainConfig{
		ServerNamesHashBucketSize: config.MainServerNamesHashBucketSize,
		ServerNamesHashMaxSize:    config.MainServerNamesHashMaxSize,
	}

	cnf.nginx.UpdateMainConfigFile(mainCfg)
}
<|endoftext|>


<commit_before>package server

import (
	"testing"

	"github.com/google/go-tpm-tools/proto/attest"
	pb "github.com/google/go-tpm-tools/proto/attest"
)

var (
	defaultGcePolicy = pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 1,
			MinimumTechnology:         pb.GCEConfidentialTechnology_NONE,
		},
	}
	defaultPhysicalPolicy = pb.Policy{
		Platform: &pb.PlatformPolicy{
			AllowedScrtmVersionIds: [][]byte{},
		},
	}
)

func TestNilPolicyAlwaysPasses(t *testing.T) {
	subtests := []struct {
		name  string
		state *attest.MachineState
	}{
		{"NilState", nil},
		{"PlatformState", &attest.MachineState{
			Platform: &attest.PlatformState{
				Firmware:   &attest.PlatformState_GceVersion{GceVersion: 1},
				Technology: attest.GCEConfidentialTechnology_AMD_SEV,
			},
		}},
	}
	for _, subtest := range subtests {
		t.Run(subtest.name, func(t *testing.T) {
			if err := EvaluatePolicy(subtest.state, nil); err != nil {
				t.Errorf("nil policy should always succeed: %v", err)
			}
		})
	}
}

func TestGCEFirmwareVersionSimple(t *testing.T) {
	zero := ConvertGCEFirmwareVersionToSCRTMVersion(0)
	if len(zero) != 0 {
		t.Errorf("expected empty SCRTM version, got %x", zero)
	}
	ver, err := ConvertSCRTMVersionToGCEFirmwareVersion(
		ConvertGCEFirmwareVersionToSCRTMVersion(23),
	)
	if ver != 23 {
		t.Errorf("convert functions aren't inverses, got %d: %v", ver, err)
	}
}

func TestEvaluatePolicy(t *testing.T) {
	tests := []struct {
		name   string
		log    eventLog
		policy *pb.Policy
	}{
		{"Debian10-SHA1", Debian10GCE, &defaultGcePolicy},
		{"RHEL8-CryptoAgile", Rhel8GCE, &defaultGcePolicy},
		{"Ubuntu1804AmdSev-CryptoAgile", UbuntuAmdSevGCE, &defaultGcePolicy},
		{"Ubuntu2104NoDbx-CryptoAgile", Ubuntu2104NoDbxGCE, &defaultGcePolicy},
		{"Ubuntu2104NoSecureBoot-CryptoAgile", Ubuntu2104NoSecureBootGCE, &defaultGcePolicy},
		{"GlinuxNoSecureBoot-CryptoAgile", GlinuxNoSecureBootLaptop, &defaultPhysicalPolicy},
		{"ArchLinuxWorkstation-CryptoAgile", ArchLinuxWorkstation, &defaultPhysicalPolicy},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			machineState, err := ParseMachineState(test.log.RawLog, test.log.Banks[0])
			if err != nil {
				t.Fatalf("failed to get machine state: %v", err)
			}
			if err := EvaluatePolicy(machineState, test.policy); err != nil {
				t.Errorf("failed to apply policy: %v", err)
			}
		})
	}
}

func TestEvaluatePolicySCRTM(t *testing.T) {
	gLinuxPolicy := pb.Policy{
		Platform: &pb.PlatformPolicy{
			AllowedScrtmVersionIds: [][]byte{{0x00}},
		},
	}
	machineState, err := ParseMachineState(GlinuxNoSecureBootLaptop.RawLog, GlinuxNoSecureBootLaptop.Banks[0])
	if err != nil {
		t.Fatalf("failed to get machine state: %v", err)
	}
	if err := EvaluatePolicy(machineState, &gLinuxPolicy); err != nil {
		t.Errorf("failed to apply policy: %v", err)
	}
}

func TestEvaluatePolicyFailure(t *testing.T) {
	badGcePolicyVersion := pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 2,
			MinimumTechnology:         pb.GCEConfidentialTechnology_NONE,
		},
	}
	badGcePolicySEV_ES := pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 0,
			MinimumTechnology:         pb.GCEConfidentialTechnology_AMD_SEV_ES,
		},
	}
	badGcePolicySEV := pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 0,
			MinimumTechnology:         pb.GCEConfidentialTechnology_AMD_SEV_ES,
		},
	}
	badPhysicalPolicy := pb.Policy{
		Platform: &pb.PlatformPolicy{
			AllowedScrtmVersionIds: [][]byte{{0x00}},
		},
	}
	tests := []struct {
		name   string
		log    eventLog
		policy *pb.Policy
	}{
		{"Debian10-SHA1", Debian10GCE, &badGcePolicyVersion},
		{"Debian10-SHA1", Debian10GCE, &badGcePolicySEV},
		{"Ubuntu1804AmdSev-CryptoAgile", UbuntuAmdSevGCE, &badGcePolicySEV_ES},
		{"GlinuxNoSecureBoot-CryptoAgile", GlinuxNoSecureBootLaptop, &badPhysicalPolicy},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			machineState, err := ParseMachineState(test.log.RawLog, test.log.Banks[0])
			if err != nil {
				t.Fatalf("failed to get machine state: %v", err)
			}
			if err := EvaluatePolicy(machineState, test.policy); err == nil {
				t.Errorf("expected policy failure; got success")
			}
		})
	}
}
<commit_msg>Change the physical machine policy test to Arch<commit_after>package server

import (
	"testing"

	"github.com/google/go-tpm-tools/proto/attest"
	pb "github.com/google/go-tpm-tools/proto/attest"
)

var (
	defaultGcePolicy = pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 1,
			MinimumTechnology:         pb.GCEConfidentialTechnology_NONE,
		},
	}
	defaultPhysicalPolicy = pb.Policy{
		Platform: &pb.PlatformPolicy{
			AllowedScrtmVersionIds: [][]byte{},
		},
	}
)

func TestNilPolicyAlwaysPasses(t *testing.T) {
	subtests := []struct {
		name  string
		state *attest.MachineState
	}{
		{"NilState", nil},
		{"PlatformState", &attest.MachineState{
			Platform: &attest.PlatformState{
				Firmware:   &attest.PlatformState_GceVersion{GceVersion: 1},
				Technology: attest.GCEConfidentialTechnology_AMD_SEV,
			},
		}},
	}
	for _, subtest := range subtests {
		t.Run(subtest.name, func(t *testing.T) {
			if err := EvaluatePolicy(subtest.state, nil); err != nil {
				t.Errorf("nil policy should always succeed: %v", err)
			}
		})
	}
}

func TestGCEFirmwareVersionSimple(t *testing.T) {
	zero := ConvertGCEFirmwareVersionToSCRTMVersion(0)
	if len(zero) != 0 {
		t.Errorf("expected empty SCRTM version, got %x", zero)
	}
	ver, err := ConvertSCRTMVersionToGCEFirmwareVersion(
		ConvertGCEFirmwareVersionToSCRTMVersion(23),
	)
	if ver != 23 {
		t.Errorf("convert functions aren't inverses, got %d: %v", ver, err)
	}
}

func TestEvaluatePolicy(t *testing.T) {
	tests := []struct {
		name   string
		log    eventLog
		policy *pb.Policy
	}{
		{"Debian10-SHA1", Debian10GCE, &defaultGcePolicy},
		{"RHEL8-CryptoAgile", Rhel8GCE, &defaultGcePolicy},
		{"Ubuntu1804AmdSev-CryptoAgile", UbuntuAmdSevGCE, &defaultGcePolicy},
		{"Ubuntu2104NoDbx-CryptoAgile", Ubuntu2104NoDbxGCE, &defaultGcePolicy},
		{"Ubuntu2104NoSecureBoot-CryptoAgile", Ubuntu2104NoSecureBootGCE, &defaultGcePolicy},
		{"GlinuxNoSecureBoot-CryptoAgile", GlinuxNoSecureBootLaptop, &defaultPhysicalPolicy},
		{"ArchLinuxWorkstation-CryptoAgile", ArchLinuxWorkstation, &defaultPhysicalPolicy},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			machineState, err := ParseMachineState(test.log.RawLog, test.log.Banks[0])
			if err != nil {
				t.Fatalf("failed to get machine state: %v", err)
			}
			if err := EvaluatePolicy(machineState, test.policy); err != nil {
				t.Errorf("failed to apply policy: %v", err)
			}
		})
	}
}

func TestEvaluatePolicySCRTM(t *testing.T) {
	archLinuxWorkstationSCRTMPolicy := pb.Policy{
		Platform: &pb.PlatformPolicy{
			AllowedScrtmVersionIds: [][]byte{{0x1e, 0xfb, 0x6b, 0x54, 0x0c, 0x1d, 0x55, 0x40, 0xa4, 0xad,
				0x4e, 0xf4, 0xbf, 0x17, 0xb8, 0x3a}},
		},
	}
	machineState, err := ParseMachineState(ArchLinuxWorkstation.RawLog, ArchLinuxWorkstation.Banks[0])
	if err != nil {
		t.Fatalf("failed to get machine state: %v", err)
	}
	if err := EvaluatePolicy(machineState, &archLinuxWorkstationSCRTMPolicy); err != nil {
		t.Errorf("failed to apply policy: %v", err)
	}
}

func TestEvaluatePolicyFailure(t *testing.T) {
	badGcePolicyVersion := pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 2,
			MinimumTechnology:         pb.GCEConfidentialTechnology_NONE,
		},
	}
	badGcePolicySEV_ES := pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 0,
			MinimumTechnology:         pb.GCEConfidentialTechnology_AMD_SEV_ES,
		},
	}
	badGcePolicySEV := pb.Policy{
		Platform: &pb.PlatformPolicy{
			MinimumGceFirmwareVersion: 0,
			MinimumTechnology:         pb.GCEConfidentialTechnology_AMD_SEV_ES,
		},
	}
	badPhysicalPolicy := pb.Policy{
		Platform: &pb.PlatformPolicy{
			AllowedScrtmVersionIds: [][]byte{{0x00}},
		},
	}
	tests := []struct {
		name   string
		log    eventLog
		policy *pb.Policy
	}{
		{"Debian10-SHA1", Debian10GCE, &badGcePolicyVersion},
		{"Debian10-SHA1", Debian10GCE, &badGcePolicySEV},
		{"Ubuntu1804AmdSev-CryptoAgile", UbuntuAmdSevGCE, &badGcePolicySEV_ES},
		{"GlinuxNoSecureBoot-CryptoAgile", GlinuxNoSecureBootLaptop, &badPhysicalPolicy},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			machineState, err := ParseMachineState(test.log.RawLog, test.log.Banks[0])
			if err != nil {
				t.Fatalf("failed to get machine state: %v", err)
			}
			if err := EvaluatePolicy(machineState, test.policy); err == nil {
				t.Errorf("expected policy failure; got success")
			}
		})
	}
}
<|endoftext|>


<commit_before>/*
This test is for PPS pipelines that use S3 inputs/outputs. Most of these
pipelines use the pachyderm/s3testing image, which exists on dockerhub but can
be built by running:
  cd etc/testing/images/s3testing
  make push-to-minikube
*/
package server

import (
	"bytes"
	"strings"
	"testing"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/ppsutil"
	tu "github.com/pachyderm/pachyderm/src/server/pkg/testutil"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestS3PipelineErrors(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration tests in short mode")
	}

	c := tu.GetPachClient(t)
	require.NoError(t, c.DeleteAll())

	repo1, repo2 := tu.UniqueString(t.Name()+"_data"), tu.UniqueString(t.Name()+"_data")
	require.NoError(t, c.CreateRepo(repo1))
	require.NoError(t, c.CreateRepo(repo2))

	pipeline := tu.UniqueString("Pipeline")
	err := c.CreatePipeline(
		pipeline,
		"",
		[]string{"bash"},
		[]string{
			"ls -R /pfs >/pfs/out/files",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Union: []*pps.Input{
				{Pfs: &pps.PFSInput{
					Repo:   repo1,
					Branch: "master",
					S3:     true,
				}},
				{Pfs: &pps.PFSInput{
					Repo:   repo2,
					Branch: "master",
					Glob:   "/*",
				}},
			},
		},
		"",
		false,
	)
	require.YesError(t, err)
	require.Matches(t, "union", err.Error())
	err = c.CreatePipeline(
		pipeline,
		"",
		[]string{"bash"},
		[]string{
			"ls -R /pfs >/pfs/out/files",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Join: []*pps.Input{
				{Pfs: &pps.PFSInput{
					Repo:   repo1,
					Branch: "master",
					S3:     true,
				}},
				{Pfs: &pps.PFSInput{
					Repo:   repo2,
					Branch: "master",
					Glob:   "/*",
				}},
			},
		},
		"",
		false,
	)
	require.YesError(t, err)
	require.Matches(t, "join", err.Error())
}

func TestS3Inputs(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration tests in short mode")
	}

	c := tu.GetPachClient(t)
	require.NoError(t, c.DeleteAll())

	repo := tu.UniqueString(t.Name() + "_data")
	require.NoError(t, c.CreateRepo(repo))

	_, err := c.PutFile(repo, "master", "foo", strings.NewReader("foo"))
	require.NoError(t, err)

	pipeline := tu.UniqueString("Pipeline")
	err = c.CreatePipeline(
		pipeline,
		"pachyderm/ubuntus3clients:v0.0.1",
		[]string{"bash", "-x"},
		[]string{
			"ls -R /pfs >/pfs/out/pfs_files",
			"aws --endpoint=${S3_ENDPOINT} s3 ls >/pfs/out/s3_buckets",
			"aws --endpoint=${S3_ENDPOINT} s3 ls s3://input_repo >/pfs/out/s3_files",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Pfs: &pps.PFSInput{
				Name:   "input_repo",
				Repo:   repo,
				Branch: "master",
				S3:     true,
			},
		},
		"",
		false,
	)

	jis, err := c.FlushJobAll([]*pfs.Commit{client.NewCommit(repo, "master")}, nil)
	require.NoError(t, err)
	require.Equal(t, 1, len(jis))
	jobInfo := jis[0]
	require.Equal(t, "JOB_SUCCESS", jobInfo.State.String())

	// check files in /pfs
	var buf bytes.Buffer
	c.GetFile(pipeline, "master", "pfs_files", 0, 0, &buf)
	require.True(t,
		strings.Contains(buf.String(), "out") && !strings.Contains(buf.String(), "input_repo"),
		"expected \"out\" but not \"input_repo\" in %q", buf.String())

	// check s3 buckets
	buf.Reset()
	c.GetFile(pipeline, "master", "s3_buckets", 0, 0, &buf)
	require.True(t,
		strings.Contains(buf.String(), "input_repo") && !strings.Contains(buf.String(), "out"),
		"expected \"input_repo\" but not \"out\" in %q", buf.String())

	// Check files in input_repo
	buf.Reset()
	c.GetFile(pipeline, "master", "s3_files", 0, 0, &buf)
	require.Matches(t, "foo", buf.String())

	// Check that no service is left over
	k := tu.GetKubeClient(t)
	svcs, err := k.CoreV1().Services(v1.NamespaceDefault).List(metav1.ListOptions{})
	require.NoError(t, err)
	for _, s := range svcs.Items {
		require.NotEqual(t, s.ObjectMeta.Name, ppsutil.SidecarS3GatewayService(jobInfo.Job.ID))
	}
}
<commit_msg>Fix a few more s3g_sidecar.go errors<commit_after>/*
This test is for PPS pipelines that use S3 inputs/outputs. Most of these
pipelines use the pachyderm/s3testing image, which exists on dockerhub but can
be built by running:
  cd etc/testing/images/s3testing
  make push-to-minikube
*/
package server

import (
	"bytes"
	"strings"
	"testing"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/require"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/ppsutil"
	tu "github.com/pachyderm/pachyderm/src/server/pkg/testutil"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestS3PipelineErrors(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration tests in short mode")
	}

	c := tu.GetPachClient(t)
	require.NoError(t, c.DeleteAll())

	repo1, repo2 := tu.UniqueString(t.Name()+"_data"), tu.UniqueString(t.Name()+"_data")
	require.NoError(t, c.CreateRepo(repo1))
	require.NoError(t, c.CreateRepo(repo2))

	pipeline := tu.UniqueString("Pipeline")
	err := c.CreatePipeline(
		pipeline,
		"",
		[]string{"bash"},
		[]string{
			"ls -R /pfs >/pfs/out/files",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Union: []*pps.Input{
				{Pfs: &pps.PFSInput{
					Repo:   repo1,
					Branch: "master",
					S3:     true,
				}},
				{Pfs: &pps.PFSInput{
					Repo:   repo2,
					Branch: "master",
					Glob:   "/*",
				}},
			},
		},
		"",
		false,
	)
	require.YesError(t, err)
	require.Matches(t, "union", err.Error())
	err = c.CreatePipeline(
		pipeline,
		"",
		[]string{"bash"},
		[]string{
			"ls -R /pfs >/pfs/out/files",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Join: []*pps.Input{
				{Pfs: &pps.PFSInput{
					Repo:   repo1,
					Branch: "master",
					S3:     true,
				}},
				{Pfs: &pps.PFSInput{
					Repo:   repo2,
					Branch: "master",
					Glob:   "/*",
				}},
			},
		},
		"",
		false,
	)
	require.YesError(t, err)
	require.Matches(t, "join", err.Error())
}

func TestS3Input(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration tests in short mode")
	}

	c := tu.GetPachClient(t)
	require.NoError(t, c.DeleteAll())

	repo := tu.UniqueString(t.Name() + "_data")
	require.NoError(t, c.CreateRepo(repo))

	_, err := c.PutFile(repo, "master", "foo", strings.NewReader("foo"))
	require.NoError(t, err)

	pipeline := tu.UniqueString("Pipeline")
	err = c.CreatePipeline(
		pipeline,
		"pachyderm/ubuntus3clients:v0.0.1",
		[]string{"bash", "-x"},
		[]string{
			"ls -R /pfs >/pfs/out/pfs_files",
			"aws --endpoint=${S3_ENDPOINT} s3 ls >/pfs/out/s3_buckets",
			"aws --endpoint=${S3_ENDPOINT} s3 ls s3://input_repo >/pfs/out/s3_files",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Pfs: &pps.PFSInput{
				Name:   "input_repo",
				Repo:   repo,
				Branch: "master",
				S3:     true,
				Glob:   "/",
			},
		},
		"",
		false,
	)

	jis, err := c.FlushJobAll([]*pfs.Commit{client.NewCommit(repo, "master")}, nil)
	require.NoError(t, err)
	require.Equal(t, 1, len(jis))
	jobInfo := jis[0]
	require.Equal(t, "JOB_SUCCESS", jobInfo.State.String())

	// check files in /pfs
	var buf bytes.Buffer
	c.GetFile(pipeline, "master", "pfs_files", 0, 0, &buf)
	require.True(t,
		strings.Contains(buf.String(), "out") && !strings.Contains(buf.String(), "input_repo"),
		"expected \"out\" but not \"input_repo\" in %q", buf.String())

	// check s3 buckets
	buf.Reset()
	c.GetFile(pipeline, "master", "s3_buckets", 0, 0, &buf)
	require.True(t,
		strings.Contains(buf.String(), "input_repo") && !strings.Contains(buf.String(), "out"),
		"expected \"input_repo\" but not \"out\" in %q", buf.String())

	// Check files in input_repo
	buf.Reset()
	c.GetFile(pipeline, "master", "s3_files", 0, 0, &buf)
	require.Matches(t, "foo", buf.String())

	// Check that no service is left over
	k := tu.GetKubeClient(t)
	svcs, err := k.CoreV1().Services(v1.NamespaceDefault).List(metav1.ListOptions{})
	require.NoError(t, err)
	for _, s := range svcs.Items {
		require.NotEqual(t, s.ObjectMeta.Name, ppsutil.SidecarS3GatewayService(jobInfo.Job.ID))
	}
}

func TestFullS3(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration tests in short mode")
	}

	c := tu.GetPachClient(t)
	require.NoError(t, c.DeleteAll())

	repo := tu.UniqueString(t.Name() + "_data")
	require.NoError(t, c.CreateRepo(repo))

	_, err := c.PutFile(repo, "master", "foo", strings.NewReader("foo"))
	require.NoError(t, err)

	pipeline := tu.UniqueString("Pipeline")
	err = c.CreatePipeline(
		pipeline,
		"pachyderm/ubuntus3clients:v0.0.1",
		[]string{"bash", "-x"},
		[]string{
			"ls -R /pfs >/pfs/out/pfs_files",
			"aws --endpoint=${S3_ENDPOINT} s3 ls >/pfs/out/s3_buckets",
			"aws --endpoint=${S3_ENDPOINT} s3 ls s3://input_repo >/pfs/out/s3_files",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Pfs: &pps.PFSInput{
				Name:   "input_repo",
				Repo:   repo,
				Branch: "master",
				S3:     true,
				Glob:   "/",
			},
		},
		"",
		false,
	)

	jis, err := c.FlushJobAll([]*pfs.Commit{client.NewCommit(repo, "master")}, nil)
	require.NoError(t, err)
	require.Equal(t, 1, len(jis))
	jobInfo := jis[0]
	require.Equal(t, "JOB_SUCCESS", jobInfo.State.String())

	// check files in /pfs
	var buf bytes.Buffer
	c.GetFile(pipeline, "master", "pfs_files", 0, 0, &buf)
	require.True(t,
		strings.Contains(buf.String(), "out") && !strings.Contains(buf.String(), "input_repo"),
		"expected \"out\" but not \"input_repo\" in %q", buf.String())

	// check s3 buckets
	buf.Reset()
	c.GetFile(pipeline, "master", "s3_buckets", 0, 0, &buf)
	require.True(t,
		strings.Contains(buf.String(), "input_repo") && !strings.Contains(buf.String(), "out"),
		"expected \"input_repo\" but not \"out\" in %q", buf.String())

	// Check files in input_repo
	buf.Reset()
	c.GetFile(pipeline, "master", "s3_files", 0, 0, &buf)
	require.Matches(t, "foo", buf.String())

	// Check that no service is left over
	k := tu.GetKubeClient(t)
	svcs, err := k.CoreV1().Services(v1.NamespaceDefault).List(metav1.ListOptions{})
	require.NoError(t, err)
	for _, s := range svcs.Items {
		require.NotEqual(t, s.ObjectMeta.Name, ppsutil.SidecarS3GatewayService(jobInfo.Job.ID))
	}
}

func TestS3Output(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration tests in short mode")
	}

	c := tu.GetPachClient(t)
	require.NoError(t, c.DeleteAll())

	repo := tu.UniqueString(t.Name() + "_data")
	require.NoError(t, c.CreateRepo(repo))

	_, err := c.PutFile(repo, "master", "foo", strings.NewReader("foo"))
	require.NoError(t, err)

	pipeline := tu.UniqueString("Pipeline")
	err = c.CreatePipeline(
		pipeline,
		"pachyderm/ubuntus3clients:v0.0.1",
		[]string{"bash", "-x"},
		[]string{
			"ls -R /pfs | aws --endpoint=${S3_ENDPOINT} s3 - s3://out/pfs_files",
			"aws --endpoint=${S3_ENDPOINT} s3 ls | s3 - s3://out/s3_buckets",
		},
		&pps.ParallelismSpec{
			Constant: 1,
		},
		&pps.Input{
			Pfs: &pps.PFSInput{
				Name:   "input_repo",
				Repo:   repo,
				Branch: "master",
				S3:     true,
				Glob:   "/",
			},
		},
		"",
		false,
	)

	jis, err := c.FlushJobAll([]*pfs.Commit{client.NewCommit(repo, "master")}, nil)
	require.NoError(t, err)
	require.Equal(t, 1, len(jis))
	jobInfo := jis[0]
	require.Equal(t, "JOB_SUCCESS", jobInfo.State.String())

	// check files in /pfs
	var buf bytes.Buffer
	c.GetFile(pipeline, "master", "pfs_files", 0, 0, &buf)
	require.True(t,
		!strings.Contains(buf.String(), "input_repo") && !strings.Contains(buf.String(), "out"),
		"expected neither \"out\" nor \"input_repo\" in %q", buf.String())

	// check s3 buckets
	buf.Reset()
	c.GetFile(pipeline, "master", "s3_buckets", 0, 0, &buf)
	require.True(t,
		strings.Contains(buf.String(), "out") && strings.Contains(buf.String(), "input_repo"),
		"expected both \"input_repo\" and \"out\" in %q", buf.String())

	// Check that no service is left over
	k := tu.GetKubeClient(t)
	svcs, err := k.CoreV1().Services(v1.NamespaceDefault).List(metav1.ListOptions{})
	require.NoError(t, err)
	for _, s := range svcs.Items {
		require.NotEqual(t, s.ObjectMeta.Name, ppsutil.SidecarS3GatewayService(jobInfo.Job.ID))
	}
}
<|endoftext|>


<commit_before>package debugreader

import (
	"fmt"
	"io"
	"os"
)

type debugReader struct {
	r io.Reader
}

func NewReader(r io.Reader) io.Reader {
	return &debugReader{r: r}
}

func (r *debugReader) Read(buf []byte) (n int, err error) {
	fmt.Fprintf(os.Stderr, "buf in: %v\n", buf)
	n, err = r.r.Read(buf)
	fmt.Fprintf(os.Stderr, "n: %v\n", n)
	fmt.Fprintf(os.Stderr, "err: %v\n", err)
	fmt.Fprintf(os.Stderr, "buf out: %v\n", buf)
	return
}
<commit_msg>Docs.<commit_after>// Package debugreader implements an io.Reader that
// logs information about the Read it receives to os.Stderr.
package debugreader

import (
	"fmt"
	"io"
	"os"
)

type debugReader struct {
	r io.Reader
}

// NewReader constructs a new io.Reader that will log to os.Stderr.
func NewReader(r io.Reader) io.Reader {
	return &debugReader{r: r}
}

func (r *debugReader) Read(buf []byte) (n int, err error) {
	fmt.Fprintf(os.Stderr, "buf in: %v\n", buf)
	n, err = r.r.Read(buf)
	fmt.Fprintf(os.Stderr, "n: %v\n", n)
	fmt.Fprintf(os.Stderr, "err: %v\n", err)
	fmt.Fprintf(os.Stderr, "buf out: %v\n", buf)
	return
}
<|endoftext|>


<commit_before>package jsonstructure

import (
	"encoding/json"
	"reflect"
	"regexp"
	"testing"

	"github.com/shopspring/decimal"
)

func TestMapMerge(t *testing.T) {
	src := map[string]interface{}{
		"foo": "hello",
		"bar": "alice",
	}
	dst := map[string]interface{}{
		"bar": "bob",
		"baz": "world",
	}
	expected := map[string]interface{}{
		"foo": "hello",
		"bar": "alice",
		"baz": "world",
	}
	err := mapMerge(dst, src, nil)
	if err != nil {
		t.Error("Unexpected error", err)
	}
	if !reflect.DeepEqual(dst, expected) {
		t.Error("Merge failure")
	}
}

func TestMapMergeRecursive(t *testing.T) {
	src := map[string]interface{}{
		"foo": map[string]interface{}{
			"bar": "baz",
		},
	}
	dst := map[string]interface{}{
		"foo": 3,
	}
	err := mapMerge(dst, src, nil)
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	dst = map[string]interface{}{}
	err = mapMerge(dst, src, nil)
	if err != nil {
		t.Error("Unexpected error")
	}
	if !reflect.DeepEqual(src, dst) {
		t.Error("Merge failure")
	}
	dst = map[string]interface{}{
		"foo": map[string]interface{}{
			"hello": "world",
		},
	}
	err = mapMerge(dst, src, nil)
	if err != nil {
		t.Error("Unexpected error")
	}
	expected := map[string]interface{}{
		"foo": map[string]interface{}{
			"bar":   "baz",
			"hello": "world",
		},
	}
	if !reflect.DeepEqual(expected, dst) {
		t.Error("Merge failure")
	}
}

func TestIntersection(t *testing.T) {
	m1 := map[string]interface{}{
		"a": true,
		"b": true,
		"c": true,
		"d": true,
	}
	m2 := map[string]interface{}{
		"c": true,
		"d": true,
		"x": true,
	}
	iSect := intersection(m1, m2)
	if len(iSect) != 2 {
		t.Error("Incorrect intersection ", iSect)
	}
	if iSect[0] != "c" && iSect[1] != "c" {
		t.Error("Missing element c")
	}
	if iSect[0] != "d" && iSect[1] != "d" {
		t.Error("Missing element d")
	}
}

func TestUnmarshalStructureSuccess(t *testing.T) {
	text := `{
		"main": {"type": "number"}
	}`
	structure, err := CreateJSONStructure([]byte(text), DefaultOptions())
	if err != nil {
		t.Error("Unmarshal error", err)
	}
	text = `{
		"fragments": {
			"req": {
				"multipleOf": 2
			}
		},
		"types": {
			"bar": {
				"type": "integer",
				"multipleOf": 4
			},
			"foo": {
				"\u0ADD": [ "req", "bar" ],
				"type": "integer"
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	structure, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err != nil {
		t.Error("Unmarshal error", err)
	}
	if structure.Definition.Types["foo"].MultipleOf == nil {
		t.Error("Composition failure")
	}
	if !structure.Definition.Types["foo"].MultipleOf.Equal(decimal.NewFromFloat(4.0)) {
		t.Error("Composition failure")
	}
	if structure.Definition.Types["foo"].Type != "integer" {
		t.Error("Composition failure")
	}
}

func TestUnmarshalStructureFailure(t *testing.T) {
	text := `{}`
	_, err := CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{"fragments": "foo", "types": "bar", "main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{"fragments": "foo", "types": "bar", "main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {"a": true, "b":true},
	 	"types": {"a": true, "b":true},
		"main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
	 	"types": {"a": true, "b":true},
		"main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"number": {"type": "boolean"}
		},
		"types": {
			"integer": {"type": "boolean"}
		},
		"main": {
			"type": "boolean"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"a": {
				"\u0ADD": [ "a" ]
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"a": {
				"\u0ADD": [ "b" ]
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"a": {
				"\u0ADD": [ true ]
			},
			"b": {
				"\u0ADD": 5
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
}

func TestMarshalStructureString(t *testing.T) {
	var result JSONStructureDefinition
	var data []byte
	s1 := EmptyJSONStructure()
	s1.Definition.Main = &TypeDecl{}
	s1.Definition.Main.Type = "string"
	s1.Definition.Main.Pattern = regexp.MustCompile("[0-9]+")
	err := s1.ValidateStructure()
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	data, err = json.MarshalIndent(s1.Definition, "", "  ")
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	err = json.Unmarshal(data, &result)
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	if result.Main.PatternRaw == nil {
		t.Error("Marshal failure")
	}
}

func TestMarshalStructureInteger(t *testing.T) {
	var result JSONStructureDefinition
	var data []byte
	dec, _ := decimal.NewFromString("2")
	s1 := EmptyJSONStructure()
	s1.Definition.Main = &TypeDecl{}
	s1.Definition.Main.Type = "integer"
	s1.Definition.Main.MultipleOf = &dec
	s1.Definition.Main.Minimum = &dec
	s1.Definition.Main.Maximum = &dec
	err := s1.ValidateStructure()
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	data, err = json.MarshalIndent(s1.Definition, "", "  ")
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	err = json.Unmarshal(data, &result)
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	if result.Main.MultipleOfRaw == nil {
		t.Error("Marshal failure")
	}
	if result.Main.MinimumRaw == nil {
		t.Error("Marshal failure")
	}
	if result.Main.MaximumRaw == nil {
		t.Error("Marshal failure")
	}
	s2 := EmptyJSONStructure()
	s2.Definition.Main = &TypeDecl{}
	s2.Definition.Main.Type = "integer"
	s2.Definition.Main.ExclusiveMinimum = &dec
	s2.Definition.Main.ExclusiveMaximum = &dec
	err = s2.ValidateStructure()
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	data, err = json.MarshalIndent(s2.Definition, "", "  ")
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	err = json.Unmarshal(data, &result)
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	if result.Main.ExclusiveMinimumRaw == nil {
		t.Error("Marshal failure")
	}
	if result.Main.ExclusiveMaximumRaw == nil {
		t.Error("Marshal failure")
	}
}
<commit_msg>Hardening of unit test.<commit_after>package jsonstructure

import (
	"encoding/json"
	"reflect"
	"regexp"
	"testing"

	"github.com/shopspring/decimal"
)

func TestMapMerge(t *testing.T) {
	src := map[string]interface{}{
		"foo": "hello",
		"bar": "alice",
	}
	dst := map[string]interface{}{
		"bar": "bob",
		"baz": "world",
	}
	expected := map[string]interface{}{
		"foo": "hello",
		"bar": "alice",
		"baz": "world",
	}
	err := mapMerge(dst, src, nil)
	if err != nil {
		t.Error("Unexpected error", err)
	}
	if !reflect.DeepEqual(dst, expected) {
		t.Error("Merge failure")
	}
}

func TestMapMergeRecursive(t *testing.T) {
	src := map[string]interface{}{
		"foo": map[string]interface{}{
			"bar": "baz",
		},
	}
	dst := map[string]interface{}{
		"foo": 3,
	}
	err := mapMerge(dst, src, nil)
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	dst = map[string]interface{}{}
	err = mapMerge(dst, src, nil)
	if err != nil {
		t.Error("Unexpected error")
	}
	if !reflect.DeepEqual(src, dst) {
		t.Error("Merge failure")
	}
	dst = map[string]interface{}{
		"foo": map[string]interface{}{
			"hello": "world",
		},
	}
	err = mapMerge(dst, src, nil)
	if err != nil {
		t.Error("Unexpected error")
	}
	expected := map[string]interface{}{
		"foo": map[string]interface{}{
			"bar":   "baz",
			"hello": "world",
		},
	}
	if !reflect.DeepEqual(expected, dst) {
		t.Error("Merge failure")
	}
}

func TestIntersection(t *testing.T) {
	m1 := map[string]interface{}{
		"a": true,
		"b": true,
		"c": true,
		"d": true,
	}
	m2 := map[string]interface{}{
		"c": true,
		"d": true,
		"x": true,
	}
	iSect := intersection(m1, m2)
	if len(iSect) != 2 {
		t.Error("Incorrect intersection ", iSect)
	}
	if iSect[0] != "c" && iSect[1] != "c" {
		t.Error("Missing element c")
	}
	if iSect[0] != "d" && iSect[1] != "d" {
		t.Error("Missing element d")
	}
}

func TestUnmarshalStructureSuccess(t *testing.T) {
	text := `{
		"main": {"type": "number"}
	}`
	structure, err := CreateJSONStructure([]byte(text), DefaultOptions())
	if err != nil {
		t.Error("Unmarshal error", err)
	}
	text = `{
		"fragments": {
			"req": {
				"multipleOf": 2
			}
		},
		"types": {
			"bar": {
				"type": "integer",
				"multipleOf": 4
			},
			"foo": {
				"\u0ADD": [ "req", "bar" ],
				"type": "number"
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	structure, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err != nil {
		t.Error("Unmarshal error", err)
	}
	if structure.Definition.Types["foo"].MultipleOf == nil {
		t.Error("Composition failure")
	}
	if !structure.Definition.Types["foo"].MultipleOf.Equal(decimal.NewFromFloat(4.0)) {
		t.Error("Composition failure")
	}
	if structure.Definition.Types["foo"].Type != "number" {
		t.Error("Composition failure")
	}
}

func TestUnmarshalStructureFailure(t *testing.T) {
	text := `{}`
	_, err := CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{"fragments": "foo", "types": "bar", "main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{"fragments": "foo", "types": "bar", "main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {"a": true, "b":true},
	 	"types": {"a": true, "b":true},
		"main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
	 	"types": {"a": true, "b":true},
		"main": {}}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"number": {"type": "boolean"}
		},
		"types": {
			"integer": {"type": "boolean"}
		},
		"main": {
			"type": "boolean"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"a": {
				"\u0ADD": [ "a" ]
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"a": {
				"\u0ADD": [ "b" ]
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
	text = `{
		"fragments": {
			"a": {
				"\u0ADD": [ true ]
			},
			"b": {
				"\u0ADD": 5
			}
		},
		"main": {
			"type": "foo"
		}
	}`
	_, err = CreateJSONStructure([]byte(text), DefaultOptions())
	if err == nil {
		t.Error("Expected error")
	}
	t.Log(err)
}

func TestMarshalStructureString(t *testing.T) {
	var result JSONStructureDefinition
	var data []byte
	s1 := EmptyJSONStructure()
	s1.Definition.Main = &TypeDecl{}
	s1.Definition.Main.Type = "string"
	s1.Definition.Main.Pattern = regexp.MustCompile("[0-9]+")
	err := s1.ValidateStructure()
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	data, err = json.MarshalIndent(s1.Definition, "", "  ")
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	err = json.Unmarshal(data, &result)
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	if result.Main.PatternRaw == nil {
		t.Error("Marshal failure")
	}
}

func TestMarshalStructureInteger(t *testing.T) {
	var result JSONStructureDefinition
	var data []byte
	dec, _ := decimal.NewFromString("2")
	s1 := EmptyJSONStructure()
	s1.Definition.Main = &TypeDecl{}
	s1.Definition.Main.Type = "integer"
	s1.Definition.Main.MultipleOf = &dec
	s1.Definition.Main.Minimum = &dec
	s1.Definition.Main.Maximum = &dec
	err := s1.ValidateStructure()
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	data, err = json.MarshalIndent(s1.Definition, "", "  ")
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	err = json.Unmarshal(data, &result)
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	if result.Main.MultipleOfRaw == nil {
		t.Error("Marshal failure")
	}
	if result.Main.MinimumRaw == nil {
		t.Error("Marshal failure")
	}
	if result.Main.MaximumRaw == nil {
		t.Error("Marshal failure")
	}
	s2 := EmptyJSONStructure()
	s2.Definition.Main = &TypeDecl{}
	s2.Definition.Main.Type = "integer"
	s2.Definition.Main.ExclusiveMinimum = &dec
	s2.Definition.Main.ExclusiveMaximum = &dec
	err = s2.ValidateStructure()
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	data, err = json.MarshalIndent(s2.Definition, "", "  ")
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	err = json.Unmarshal(data, &result)
	if err != nil {
		t.Error("Unexpected error ", err)
	}
	if result.Main.ExclusiveMinimumRaw == nil {
		t.Error("Marshal failure")
	}
	if result.Main.ExclusiveMaximumRaw == nil {
		t.Error("Marshal failure")
	}
}
<|endoftext|>


<commit_before>package origin

import (
	"io/ioutil"
	"time"

	"github.com/golang/glog"

	kapierror "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	apirequest "k8s.io/apiserver/pkg/endpoints/request"
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/retry"

	"github.com/openshift/origin/pkg/oc/admin/policy"

	authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization"
	clusterpolicyregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy"
	clusterpolicystorage "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy/etcd"
	"github.com/openshift/origin/pkg/cmd/server/admin"
	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
	"github.com/openshift/origin/pkg/security/legacyclient"
)

// ensureOpenShiftSharedResourcesNamespace is called as part of global policy initialization to ensure shared namespace exists
func (c *MasterConfig) ensureOpenShiftSharedResourcesNamespace() {
	if _, err := c.KubeClientsetInternal().Core().Namespaces().Get(c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace, metav1.GetOptions{}); kapierror.IsNotFound(err) {
		namespace, createErr := c.KubeClientsetInternal().Core().Namespaces().Create(&kapi.Namespace{ObjectMeta: metav1.ObjectMeta{Name: c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace}})
		if createErr != nil {
			glog.Errorf("Error creating namespace: %v due to %v\n", c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace, createErr)
			return
		}

		c.ensureNamespaceServiceAccountRoleBindings(namespace)
	}
}

// ensureOpenShiftInfraNamespace is called as part of global policy initialization to ensure infra namespace exists
func (c *MasterConfig) ensureOpenShiftInfraNamespace() {
	ns := c.Options.PolicyConfig.OpenShiftInfrastructureNamespace

	// Ensure namespace exists
	namespace, err := c.KubeClientsetInternal().Core().Namespaces().Create(&kapi.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}})
	if kapierror.IsAlreadyExists(err) {
		// Get the persisted namespace
		namespace, err = c.KubeClientsetInternal().Core().Namespaces().Get(ns, metav1.GetOptions{})
		if err != nil {
			glog.Errorf("Error getting namespace %s: %v", ns, err)
			return
		}
	} else if err != nil {
		glog.Errorf("Error creating namespace %s: %v", ns, err)
		return
	}

	for _, role := range bootstrappolicy.ControllerRoles() {
		reconcileRole := &policy.ReconcileClusterRolesOptions{
			RolesToReconcile: []string{role.Name},
			Confirmed:        true,
			Union:            true,
			Out:              ioutil.Discard,
			RoleClient:       c.PrivilegedLoopbackOpenShiftClient.ClusterRoles(),
		}
		if err := reconcileRole.RunReconcileClusterRoles(nil, nil); err != nil {
			glog.Errorf("Could not reconcile %v: %v\n", role.Name, err)
		}
	}
	for _, roleBinding := range bootstrappolicy.ControllerRoleBindings() {
		reconcileRoleBinding := &policy.ReconcileClusterRoleBindingsOptions{
			RolesToReconcile:  []string{roleBinding.RoleRef.Name},
			Confirmed:         true,
			Union:             true,
			Out:               ioutil.Discard,
			RoleBindingClient: c.PrivilegedLoopbackOpenShiftClient.ClusterRoleBindings(),
		}
		if err := reconcileRoleBinding.RunReconcileClusterRoleBindings(nil, nil); err != nil {
			glog.Errorf("Could not reconcile %v: %v\n", roleBinding.Name, err)
		}
	}

	c.ensureNamespaceServiceAccountRoleBindings(namespace)
}

// ensureDefaultNamespaceServiceAccountRoles initializes roles for service accounts in the default namespace
func (c *MasterConfig) ensureDefaultNamespaceServiceAccountRoles() {
	// Wait for the default namespace
	var namespace *kapi.Namespace
	for i := 0; i < 30; i++ {
		ns, err := c.KubeClientsetInternal().Core().Namespaces().Get(metav1.NamespaceDefault, metav1.GetOptions{})
		if err == nil {
			namespace = ns
			break
		}
		if kapierror.IsNotFound(err) {
			time.Sleep(time.Second)
			continue
		}
		glog.Errorf("Error adding service account roles to %q namespace: %v", metav1.NamespaceDefault, err)
		return
	}
	if namespace == nil {
		glog.Errorf("Namespace %q not found, could not initialize the %q namespace", metav1.NamespaceDefault, metav1.NamespaceDefault)
		return
	}

	c.ensureNamespaceServiceAccountRoleBindings(namespace)
}

// ensureNamespaceServiceAccountRoleBindings initializes roles for service accounts in the namespace
func (c *MasterConfig) ensureNamespaceServiceAccountRoleBindings(namespace *kapi.Namespace) {
	const ServiceAccountRolesInitializedAnnotation = "openshift.io/sa.initialized-roles"

	// Short-circuit if we're already initialized
	if namespace.Annotations[ServiceAccountRolesInitializedAnnotation] == "true" {
		return
	}

	hasErrors := false
	for _, binding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(namespace.Name) {
		addRole := &policy.RoleModificationOptions{
			RoleName:            binding.RoleRef.Name,
			RoleNamespace:       binding.RoleRef.Namespace,
			RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace.Name, c.ServiceAccountRoleBindingClient()),
			Subjects:            binding.Subjects,
		}
		if err := retry.RetryOnConflict(retry.DefaultRetry, func() error { return addRole.AddRole() }); err != nil {
			glog.Errorf("Could not add service accounts to the %v role in the %q namespace: %v\n", binding.RoleRef.Name, namespace.Name, err)
			hasErrors = true
		}
	}

	// If we had errors, don't register initialization so we can try again
	if hasErrors {
		return
	}

	if namespace.Annotations == nil {
		namespace.Annotations = map[string]string{}
	}
	namespace.Annotations[ServiceAccountRolesInitializedAnnotation] = "true"
	// Log any error other than a conflict (the update will be retried and recorded again on next startup in that case)
	if _, err := c.KubeClientsetInternal().Core().Namespaces().Update(namespace); err != nil && !kapierror.IsConflict(err) {
		glog.Errorf("Error recording adding service account roles to %q namespace: %v", namespace.Name, err)
	}
}

func (c *MasterConfig) ensureDefaultSecurityContextConstraints() {
	ns := c.Options.PolicyConfig.OpenShiftInfrastructureNamespace
	bootstrapSCCGroups, bootstrapSCCUsers := bootstrappolicy.GetBoostrapSCCAccess(ns)

	for _, scc := range bootstrappolicy.GetBootstrapSecurityContextConstraints(bootstrapSCCGroups, bootstrapSCCUsers) {
		_, err := legacyclient.NewFromClient(c.KubeClientsetInternal().Core().RESTClient()).Create(&scc)
		if kapierror.IsAlreadyExists(err) {
			continue
		}
		if err != nil {
			glog.Errorf("Unable to create default security context constraint %s.  Got error: %v", scc.Name, err)
			continue
		}
		glog.Infof("Created default security context constraint %s", scc.Name)
	}
}

// ensureComponentAuthorizationRules initializes the cluster policies
func (c *MasterConfig) ensureComponentAuthorizationRules() {
	clusterPolicyStorage, err := clusterpolicystorage.NewREST(c.RESTOptionsGetter)
	if err != nil {
		glog.Errorf("Error creating policy storage: %v", err)
		return
	}
	clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage)
	ctx := apirequest.WithNamespace(apirequest.NewContext(), "")

	if _, err := clusterPolicyRegistry.GetClusterPolicy(ctx, authorizationapi.PolicyName, &metav1.GetOptions{}); kapierror.IsNotFound(err) {
		glog.Infof("No cluster policy found.  Creating bootstrap policy based on: %v", c.Options.PolicyConfig.BootstrapPolicyFile)

		if err := admin.OverwriteBootstrapPolicy(c.RESTOptionsGetter, c.Options.PolicyConfig.BootstrapPolicyFile, admin.CreateBootstrapPolicyFileFullCommand, true, ioutil.Discard); err != nil {
			glog.Errorf("Error creating bootstrap policy: %v", err)
		}

	} else {
		glog.V(2).Infof("Ignoring bootstrap policy file because cluster policy found")
	}

	// Wait until the policy cache has caught up before continuing
	review := &authorizationapi.SubjectAccessReview{Action: authorizationapi.Action{Verb: "get", Group: authorizationapi.GroupName, Resource: "clusterpolicies"}}
	err = wait.PollImmediate(100*time.Millisecond, 30*time.Second, func() (done bool, err error) {
		result, err := c.PolicyClient().SubjectAccessReviews().Create(review)
		if err == nil && result.Allowed {
			return true, nil
		}
		if kapierror.IsForbidden(err) || (err == nil && !result.Allowed) {
			glog.V(2).Infof("waiting for policy cache to initialize")
			return false, nil
		}
		return false, err
	})
	if err != nil {
		glog.Errorf("error waiting for policy cache to initialize: %v", err)
	}

	// Reconcile roles that must exist for the cluster to function
	// Be very judicious about what is placed in this list, since it will be enforced on every server start
	reconcileRoles := &policy.ReconcileClusterRolesOptions{
		RolesToReconcile: []string{bootstrappolicy.DiscoveryRoleName},
		Confirmed:        true,
		Union:            true,
		Out:              ioutil.Discard,
		RoleClient:       c.PrivilegedLoopbackOpenShiftClient.ClusterRoles(),
	}
	if err := reconcileRoles.RunReconcileClusterRoles(nil, nil); err != nil {
		glog.Errorf("Could not auto reconcile roles: %v\n", err)
	}

	// Reconcile rolebindings that must exist for the cluster to function
	// Be very judicious about what is placed in this list, since it will be enforced on every server start
	reconcileRoleBindings := &policy.ReconcileClusterRoleBindingsOptions{
		RolesToReconcile:  []string{bootstrappolicy.DiscoveryRoleName},
		Confirmed:         true,
		Union:             true,
		Out:               ioutil.Discard,
		RoleBindingClient: c.PrivilegedLoopbackOpenShiftClient.ClusterRoleBindings(),
	}
	if err := reconcileRoleBindings.RunReconcileClusterRoleBindings(nil, nil); err != nil {
		glog.Errorf("Could not auto reconcile role bindings: %v\n", err)
	}
}
<commit_msg>add upstream namespaced rbac resoruces<commit_after>package origin

import (
	"fmt"
	"io/ioutil"
	"time"

	"github.com/golang/glog"

	kapierror "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	apirequest "k8s.io/apiserver/pkg/endpoints/request"
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/rbac"
	"k8s.io/kubernetes/pkg/client/retry"
	kbootstrappolicy "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"

	"github.com/openshift/origin/pkg/oc/admin/policy"

	authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization"
	clusterpolicyregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy"
	clusterpolicystorage "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy/etcd"
	"github.com/openshift/origin/pkg/cmd/server/admin"
	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
	"github.com/openshift/origin/pkg/security/legacyclient"
)

// ensureOpenShiftSharedResourcesNamespace is called as part of global policy initialization to ensure shared namespace exists
func (c *MasterConfig) ensureOpenShiftSharedResourcesNamespace() {
	if _, err := c.KubeClientsetInternal().Core().Namespaces().Get(c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace, metav1.GetOptions{}); kapierror.IsNotFound(err) {
		namespace, createErr := c.KubeClientsetInternal().Core().Namespaces().Create(&kapi.Namespace{ObjectMeta: metav1.ObjectMeta{Name: c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace}})
		if createErr != nil {
			glog.Errorf("Error creating namespace: %v due to %v\n", c.Options.PolicyConfig.OpenShiftSharedResourcesNamespace, createErr)
			return
		}

		c.ensureNamespaceServiceAccountRoleBindings(namespace)
	}
}

// ensureOpenShiftInfraNamespace is called as part of global policy initialization to ensure infra namespace exists
func (c *MasterConfig) ensureOpenShiftInfraNamespace() {
	ns := c.Options.PolicyConfig.OpenShiftInfrastructureNamespace

	// Ensure namespace exists
	namespace, err := c.KubeClientsetInternal().Core().Namespaces().Create(&kapi.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}})
	if kapierror.IsAlreadyExists(err) {
		// Get the persisted namespace
		namespace, err = c.KubeClientsetInternal().Core().Namespaces().Get(ns, metav1.GetOptions{})
		if err != nil {
			glog.Errorf("Error getting namespace %s: %v", ns, err)
			return
		}
	} else if err != nil {
		glog.Errorf("Error creating namespace %s: %v", ns, err)
		return
	}

	for _, role := range bootstrappolicy.ControllerRoles() {
		reconcileRole := &policy.ReconcileClusterRolesOptions{
			RolesToReconcile: []string{role.Name},
			Confirmed:        true,
			Union:            true,
			Out:              ioutil.Discard,
			RoleClient:       c.PrivilegedLoopbackOpenShiftClient.ClusterRoles(),
		}
		if err := reconcileRole.RunReconcileClusterRoles(nil, nil); err != nil {
			glog.Errorf("Could not reconcile %v: %v\n", role.Name, err)
		}
	}
	for _, roleBinding := range bootstrappolicy.ControllerRoleBindings() {
		reconcileRoleBinding := &policy.ReconcileClusterRoleBindingsOptions{
			RolesToReconcile:  []string{roleBinding.RoleRef.Name},
			Confirmed:         true,
			Union:             true,
			Out:               ioutil.Discard,
			RoleBindingClient: c.PrivilegedLoopbackOpenShiftClient.ClusterRoleBindings(),
		}
		if err := reconcileRoleBinding.RunReconcileClusterRoleBindings(nil, nil); err != nil {
			glog.Errorf("Could not reconcile %v: %v\n", roleBinding.Name, err)
		}
	}

	c.ensureNamespaceServiceAccountRoleBindings(namespace)
}

// ensureDefaultNamespaceServiceAccountRoles initializes roles for service accounts in the default namespace
func (c *MasterConfig) ensureDefaultNamespaceServiceAccountRoles() {
	// Wait for the default namespace
	var namespace *kapi.Namespace
	for i := 0; i < 30; i++ {
		ns, err := c.KubeClientsetInternal().Core().Namespaces().Get(metav1.NamespaceDefault, metav1.GetOptions{})
		if err == nil {
			namespace = ns
			break
		}
		if kapierror.IsNotFound(err) {
			time.Sleep(time.Second)
			continue
		}
		glog.Errorf("Error adding service account roles to %q namespace: %v", metav1.NamespaceDefault, err)
		return
	}
	if namespace == nil {
		glog.Errorf("Namespace %q not found, could not initialize the %q namespace", metav1.NamespaceDefault, metav1.NamespaceDefault)
		return
	}

	c.ensureNamespaceServiceAccountRoleBindings(namespace)
}

// ensureNamespaceServiceAccountRoleBindings initializes roles for service accounts in the namespace
func (c *MasterConfig) ensureNamespaceServiceAccountRoleBindings(namespace *kapi.Namespace) {
	const ServiceAccountRolesInitializedAnnotation = "openshift.io/sa.initialized-roles"

	// Short-circuit if we're already initialized
	if namespace.Annotations[ServiceAccountRolesInitializedAnnotation] == "true" {
		return
	}

	hasErrors := false
	for _, binding := range bootstrappolicy.GetBootstrapServiceAccountProjectRoleBindings(namespace.Name) {
		addRole := &policy.RoleModificationOptions{
			RoleName:            binding.RoleRef.Name,
			RoleNamespace:       binding.RoleRef.Namespace,
			RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(namespace.Name, c.ServiceAccountRoleBindingClient()),
			Subjects:            binding.Subjects,
		}
		if err := retry.RetryOnConflict(retry.DefaultRetry, func() error { return addRole.AddRole() }); err != nil {
			glog.Errorf("Could not add service accounts to the %v role in the %q namespace: %v\n", binding.RoleRef.Name, namespace.Name, err)
			hasErrors = true
		}
	}

	// If we had errors, don't register initialization so we can try again
	if hasErrors {
		return
	}

	if namespace.Annotations == nil {
		namespace.Annotations = map[string]string{}
	}
	namespace.Annotations[ServiceAccountRolesInitializedAnnotation] = "true"
	// Log any error other than a conflict (the update will be retried and recorded again on next startup in that case)
	if _, err := c.KubeClientsetInternal().Core().Namespaces().Update(namespace); err != nil && !kapierror.IsConflict(err) {
		glog.Errorf("Error recording adding service account roles to %q namespace: %v", namespace.Name, err)
	}
}

func (c *MasterConfig) ensureDefaultSecurityContextConstraints() {
	ns := c.Options.PolicyConfig.OpenShiftInfrastructureNamespace
	bootstrapSCCGroups, bootstrapSCCUsers := bootstrappolicy.GetBoostrapSCCAccess(ns)

	for _, scc := range bootstrappolicy.GetBootstrapSecurityContextConstraints(bootstrapSCCGroups, bootstrapSCCUsers) {
		_, err := legacyclient.NewFromClient(c.KubeClientsetInternal().Core().RESTClient()).Create(&scc)
		if kapierror.IsAlreadyExists(err) {
			continue
		}
		if err != nil {
			glog.Errorf("Unable to create default security context constraint %s.  Got error: %v", scc.Name, err)
			continue
		}
		glog.Infof("Created default security context constraint %s", scc.Name)
	}
}

// ensureComponentAuthorizationRules initializes the cluster policies
func (c *MasterConfig) ensureComponentAuthorizationRules() {
	clusterPolicyStorage, err := clusterpolicystorage.NewREST(c.RESTOptionsGetter)
	if err != nil {
		glog.Errorf("Error creating policy storage: %v", err)
		return
	}
	clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage)
	ctx := apirequest.WithNamespace(apirequest.NewContext(), "")

	if _, err := clusterPolicyRegistry.GetClusterPolicy(ctx, authorizationapi.PolicyName, &metav1.GetOptions{}); kapierror.IsNotFound(err) {
		glog.Infof("No cluster policy found.  Creating bootstrap policy based on: %v", c.Options.PolicyConfig.BootstrapPolicyFile)

		if err := admin.OverwriteBootstrapPolicy(c.RESTOptionsGetter, c.Options.PolicyConfig.BootstrapPolicyFile, admin.CreateBootstrapPolicyFileFullCommand, true, ioutil.Discard); err != nil {
			glog.Errorf("Error creating bootstrap policy: %v", err)
		}

		// these are namespaced, so we can't reconcile them.  Just try to put them in until we work against rbac
		// This only had to hold us until the transition is complete
		// TODO remove this block and use a post-starthook
		// ensure bootstrap namespaced roles are created or reconciled
		for namespace, roles := range kbootstrappolicy.NamespaceRoles() {
			for _, rbacRole := range roles {
				role := &authorizationapi.Role{}
				if err := authorizationapi.Convert_rbac_Role_To_authorization_Role(&rbacRole, role, nil); err != nil {
					utilruntime.HandleError(fmt.Errorf("unable to convert role.%s/%s in %v: %v", rbac.GroupName, rbacRole.Name, namespace, err))
					continue
				}
				if _, err := c.PrivilegedLoopbackOpenShiftClient.Roles(namespace).Create(role); err != nil {
					// don't fail on failures, try to create as many as you can
					utilruntime.HandleError(fmt.Errorf("unable to reconcile role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err))
				}
			}
		}

		// ensure bootstrap namespaced rolebindings are created or reconciled
		for namespace, roleBindings := range kbootstrappolicy.NamespaceRoleBindings() {
			for _, rbacRoleBinding := range roleBindings {
				roleBinding := &authorizationapi.RoleBinding{}
				if err := authorizationapi.Convert_rbac_RoleBinding_To_authorization_RoleBinding(&rbacRoleBinding, roleBinding, nil); err != nil {
					utilruntime.HandleError(fmt.Errorf("unable to convert rolebinding.%s/%s in %v: %v", rbac.GroupName, rbacRoleBinding.Name, namespace, err))
					continue
				}
				if _, err := c.PrivilegedLoopbackOpenShiftClient.RoleBindings(namespace).Create(roleBinding); err != nil {
					// don't fail on failures, try to create as many as you can
					utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, namespace, err))
				}
			}
		}

	} else {
		glog.V(2).Infof("Ignoring bootstrap policy file because cluster policy found")
	}

	// Wait until the policy cache has caught up before continuing
	review := &authorizationapi.SubjectAccessReview{Action: authorizationapi.Action{Verb: "get", Group: authorizationapi.GroupName, Resource: "clusterpolicies"}}
	err = wait.PollImmediate(100*time.Millisecond, 30*time.Second, func() (done bool, err error) {
		result, err := c.PolicyClient().SubjectAccessReviews().Create(review)
		if err == nil && result.Allowed {
			return true, nil
		}
		if kapierror.IsForbidden(err) || (err == nil && !result.Allowed) {
			glog.V(2).Infof("waiting for policy cache to initialize")
			return false, nil
		}
		return false, err
	})
	if err != nil {
		glog.Errorf("error waiting for policy cache to initialize: %v", err)
	}

	// Reconcile roles that must exist for the cluster to function
	// Be very judicious about what is placed in this list, since it will be enforced on every server start
	reconcileRoles := &policy.ReconcileClusterRolesOptions{
		RolesToReconcile: []string{bootstrappolicy.DiscoveryRoleName},
		Confirmed:        true,
		Union:            true,
		Out:              ioutil.Discard,
		RoleClient:       c.PrivilegedLoopbackOpenShiftClient.ClusterRoles(),
	}
	if err := reconcileRoles.RunReconcileClusterRoles(nil, nil); err != nil {
		glog.Errorf("Could not auto reconcile roles: %v\n", err)
	}

	// Reconcile rolebindings that must exist for the cluster to function
	// Be very judicious about what is placed in this list, since it will be enforced on every server start
	reconcileRoleBindings := &policy.ReconcileClusterRoleBindingsOptions{
		RolesToReconcile:  []string{bootstrappolicy.DiscoveryRoleName},
		Confirmed:         true,
		Union:             true,
		Out:               ioutil.Discard,
		RoleBindingClient: c.PrivilegedLoopbackOpenShiftClient.ClusterRoleBindings(),
	}
	if err := reconcileRoleBindings.RunReconcileClusterRoleBindings(nil, nil); err != nil {
		glog.Errorf("Could not auto reconcile role bindings: %v\n", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package chartutil

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ghodss/yaml"

	"k8s.io/helm/pkg/proto/hapi/chart"
)

var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")

// SaveDir saves a chart as files in a directory.
func SaveDir(c *chart.Chart, dest string) error {
	// Create the chart directory
	outdir := filepath.Join(dest, c.Metadata.Name)
	if err := os.Mkdir(outdir, 0755); err != nil {
		return err
	}

	// Save the chart file.
	if err := SaveChartfile(filepath.Join(outdir, ChartfileName), c.Metadata); err != nil {
		return err
	}

	// Save values.yaml
	if c.Values != nil && len(c.Values.Raw) > 0 {
		vf := filepath.Join(outdir, ValuesfileName)
		if err := ioutil.WriteFile(vf, []byte(c.Values.Raw), 0755); err != nil {
			return err
		}
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(outdir, d), 0755); err != nil {
			return err
		}
	}

	// Save templates
	for _, f := range c.Templates {
		n := filepath.Join(outdir, f.Name)
		if err := ioutil.WriteFile(n, f.Data, 0755); err != nil {
			return err
		}
	}

	// Save files
	for _, f := range c.Files {
		n := filepath.Join(outdir, f.TypeUrl)

		d := filepath.Dir(n)
		if err := os.MkdirAll(d, 0755); err != nil {
			return err
		}

		if err := ioutil.WriteFile(n, f.Value, 0755); err != nil {
			return err
		}
	}

	// Save dependencies
	base := filepath.Join(outdir, ChartsDir)
	for _, dep := range c.Dependencies {
		// Here, we write each dependency as a tar file.
		if _, err := Save(dep, base); err != nil {
			return err
		}
	}
	return nil
}

// Save creates an archived chart to the given directory.
//
// This takes an existing chart and a destination directory.
//
// If the directory is /foo, and the chart is named bar, with version 1.0.0, this
// will generate /foo/bar-1.0.0.tgz.
//
// This returns the absolute path to the chart archive file.
func Save(c *chart.Chart, outDir string) (string, error) {
	// Create archive
	if fi, err := os.Stat(outDir); err != nil {
		return "", err
	} else if !fi.IsDir() {
		return "", fmt.Errorf("location %s is not a directory", outDir)
	}

	if c.Metadata == nil {
		return "", errors.New("no Chart.yaml data")
	}

	cfile := c.Metadata
	if cfile.Name == "" {
		return "", errors.New("no chart name specified (Chart.yaml)")
	} else if cfile.Version == "" {
		return "", errors.New("no chart version specified (Chart.yaml)")
	}

	filename := fmt.Sprintf("%s-%s.tgz", cfile.Name, cfile.Version)
	filename = filepath.Join(outDir, filename)
	if stat, err := os.Stat(filepath.Dir(filename)); os.IsNotExist(err) {
		if err := os.MkdirAll(filepath.Dir(filename), 0755); !os.IsExist(err) {
			return "", err
		}
	} else if !stat.IsDir() {
		return "", fmt.Errorf("is not a directory: %s", filepath.Dir(filename))
	}

	f, err := os.Create(filename)
	if err != nil {
		return "", err
	}

	// Wrap in gzip writer
	zipper := gzip.NewWriter(f)
	zipper.Header.Extra = headerBytes
	zipper.Header.Comment = "Helm"

	// Wrap in tar writer
	twriter := tar.NewWriter(zipper)
	rollback := false
	defer func() {
		twriter.Close()
		zipper.Close()
		f.Close()
		if rollback {
			os.Remove(filename)
		}
	}()

	if err := writeTarContents(twriter, c, ""); err != nil {
		rollback = true
	}
	return filename, err
}

func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
	base := filepath.Join(prefix, c.Metadata.Name)

	// Save Chart.yaml
	cdata, err := yaml.Marshal(c.Metadata)
	if err != nil {
		return err
	}
	if err := writeToTar(out, base+"/Chart.yaml", cdata); err != nil {
		return err
	}

	// Save values.yaml
	if c.Values != nil && len(c.Values.Raw) > 0 {
		if err := writeToTar(out, base+"/values.yaml", []byte(c.Values.Raw)); err != nil {
			return err
		}
	}

	// Save templates
	for _, f := range c.Templates {
		n := filepath.Join(base, f.Name)
		if err := writeToTar(out, n, f.Data); err != nil {
			return err
		}
	}

	// Save files
	for _, f := range c.Files {
		n := filepath.Join(base, f.TypeUrl)
		if err := writeToTar(out, n, f.Value); err != nil {
			return err
		}
	}

	// Save dependencies
	for _, dep := range c.Dependencies {
		if err := writeTarContents(out, dep, base+"/charts"); err != nil {
			return err
		}
	}
	return nil
}

// writeToTar writes a single file to a tar archive.
func writeToTar(out *tar.Writer, name string, body []byte) error {
	// TODO: Do we need to create dummy parent directory names if none exist?
	h := &tar.Header{
		Name: name,
		Mode: 0755,
		Size: int64(len(body)),
	}
	if err := out.WriteHeader(h); err != nil {
		return err
	}
	if _, err := out.Write(body); err != nil {
		return err
	}
	return nil
}
<commit_msg>#3763 replace backslash with forward slash<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package chartutil

import (
	"archive/tar"
	"compress/gzip"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/ghodss/yaml"

	"k8s.io/helm/pkg/proto/hapi/chart"
)

var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=")

// SaveDir saves a chart as files in a directory.
func SaveDir(c *chart.Chart, dest string) error {
	// Create the chart directory
	outdir := filepath.Join(dest, c.Metadata.Name)
	if err := os.Mkdir(outdir, 0755); err != nil {
		return err
	}

	// Save the chart file.
	if err := SaveChartfile(filepath.Join(outdir, ChartfileName), c.Metadata); err != nil {
		return err
	}

	// Save values.yaml
	if c.Values != nil && len(c.Values.Raw) > 0 {
		vf := filepath.Join(outdir, ValuesfileName)
		if err := ioutil.WriteFile(vf, []byte(c.Values.Raw), 0755); err != nil {
			return err
		}
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(outdir, d), 0755); err != nil {
			return err
		}
	}

	// Save templates
	for _, f := range c.Templates {
		n := filepath.Join(outdir, f.Name)
		if err := ioutil.WriteFile(n, f.Data, 0755); err != nil {
			return err
		}
	}

	// Save files
	for _, f := range c.Files {
		n := filepath.Join(outdir, f.TypeUrl)

		d := filepath.Dir(n)
		if err := os.MkdirAll(d, 0755); err != nil {
			return err
		}

		if err := ioutil.WriteFile(n, f.Value, 0755); err != nil {
			return err
		}
	}

	// Save dependencies
	base := filepath.Join(outdir, ChartsDir)
	for _, dep := range c.Dependencies {
		// Here, we write each dependency as a tar file.
		if _, err := Save(dep, base); err != nil {
			return err
		}
	}
	return nil
}

// Save creates an archived chart to the given directory.
//
// This takes an existing chart and a destination directory.
//
// If the directory is /foo, and the chart is named bar, with version 1.0.0, this
// will generate /foo/bar-1.0.0.tgz.
//
// This returns the absolute path to the chart archive file.
func Save(c *chart.Chart, outDir string) (string, error) {
	// Create archive
	if fi, err := os.Stat(outDir); err != nil {
		return "", err
	} else if !fi.IsDir() {
		return "", fmt.Errorf("location %s is not a directory", outDir)
	}

	if c.Metadata == nil {
		return "", errors.New("no Chart.yaml data")
	}

	cfile := c.Metadata
	if cfile.Name == "" {
		return "", errors.New("no chart name specified (Chart.yaml)")
	} else if cfile.Version == "" {
		return "", errors.New("no chart version specified (Chart.yaml)")
	}

	filename := fmt.Sprintf("%s-%s.tgz", cfile.Name, cfile.Version)
	filename = filepath.Join(outDir, filename)
	if stat, err := os.Stat(filepath.Dir(filename)); os.IsNotExist(err) {
		if err := os.MkdirAll(filepath.Dir(filename), 0755); !os.IsExist(err) {
			return "", err
		}
	} else if !stat.IsDir() {
		return "", fmt.Errorf("is not a directory: %s", filepath.Dir(filename))
	}

	f, err := os.Create(filename)
	if err != nil {
		return "", err
	}

	// Wrap in gzip writer
	zipper := gzip.NewWriter(f)
	zipper.Header.Extra = headerBytes
	zipper.Header.Comment = "Helm"

	// Wrap in tar writer
	twriter := tar.NewWriter(zipper)
	rollback := false
	defer func() {
		twriter.Close()
		zipper.Close()
		f.Close()
		if rollback {
			os.Remove(filename)
		}
	}()

	if err := writeTarContents(twriter, c, ""); err != nil {
		rollback = true
	}
	return filename, err
}

func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
	base := filepath.Join(prefix, c.Metadata.Name)

	// Save Chart.yaml
	cdata, err := yaml.Marshal(c.Metadata)
	if err != nil {
		return err
	}
	if err := writeToTar(out, base+"/Chart.yaml", cdata); err != nil {
		return err
	}

	// Save values.yaml
	if c.Values != nil && len(c.Values.Raw) > 0 {
		if err := writeToTar(out, base+"/values.yaml", []byte(c.Values.Raw)); err != nil {
			return err
		}
	}

	// Save templates
	for _, f := range c.Templates {
		n := filepath.Join(base, f.Name)
		if err := writeToTar(out, n, f.Data); err != nil {
			return err
		}
	}

	// Save files
	for _, f := range c.Files {
		n := filepath.Join(base, f.TypeUrl)
		if err := writeToTar(out, n, f.Value); err != nil {
			return err
		}
	}

	// Save dependencies
	for _, dep := range c.Dependencies {
		if err := writeTarContents(out, dep, base+"/charts"); err != nil {
			return err
		}
	}
	return nil
}

// writeToTar writes a single file to a tar archive.
func writeToTar(out *tar.Writer, name string, body []byte) error {
	// TODO: Do we need to create dummy parent directory names if none exist?
	name = strings.Replace(name, "\\", "/", -1)
	h := &tar.Header{
		Name: name,
		Mode: 0755,
		Size: int64(len(body)),
	}
	if err := out.WriteHeader(h); err != nil {
		return err
	}
	if _, err := out.Write(body); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package conf

import (
	"github.com/Sirupsen/logrus"
	"github.com/intelsdi-x/swan/pkg/utils/fs"
	. "github.com/smartystreets/goconvey/convey"
	"io/ioutil"
	"os"
	"path"
	"testing"
)

const (
	testAppName       = "testAppName"
	testIPDefaultName = "127.0.0.1"
)

func TestConf(t *testing.T) {
	testReadmePath := path.Join(fs.GetSwanPath(), "pkg", "conf", "test_file.md")
	Convey("While using Conf pkg", t, func() {
		logLevelFlag.clear()
		defer logLevelFlag.clear()

		SetAppName(testAppName)
		SetHelpPath(testReadmePath)

		Convey("Name and help should match to specified one", func() {
			So(AppName(), ShouldEqual, testAppName)

			readmeData, err := ioutil.ReadFile(testReadmePath)
			if err != nil {
				panic(err)
			}
			So(app.Help, ShouldEqual, string(readmeData)[:])
		})

		Convey("Log level can be fetched", func() {
			So(LogLevel(), ShouldEqual, logrus.ErrorLevel)
		})

		Convey("Log level can be fetched from env", func() {
			// Default one.
			So(LogLevel(), ShouldEqual, logrus.ErrorLevel)

			os.Setenv(logLevelFlag.envName(), "debug")

			err := ParseEnv()
			So(err, ShouldBeNil)

			// Should be from environment.
			So(LogLevel(), ShouldEqual, logrus.DebugLevel)
		})
	})
}
<commit_msg>Default log level to "warn" (#294)<commit_after>package conf

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

	"github.com/Sirupsen/logrus"
	"github.com/intelsdi-x/swan/pkg/utils/fs"
	. "github.com/smartystreets/goconvey/convey"
)

const (
	testAppName       = "testAppName"
	testIPDefaultName = "127.0.0.1"
)

func TestConf(t *testing.T) {
	testReadmePath := path.Join(fs.GetSwanPath(), "pkg", "conf", "test_file.md")
	Convey("While using Conf pkg", t, func() {
		logLevelFlag.clear()
		defer logLevelFlag.clear()

		SetAppName(testAppName)
		SetHelpPath(testReadmePath)

		Convey("Name and help should match to specified one", func() {
			So(AppName(), ShouldEqual, testAppName)

			readmeData, err := ioutil.ReadFile(testReadmePath)
			if err != nil {
				panic(err)
			}
			So(app.Help, ShouldEqual, string(readmeData)[:])
		})

		Convey("Log level can be fetched", func() {
			So(LogLevel(), ShouldEqual, logrus.ErrorLevel)
		})

		Convey("Log level can be fetched from env", func() {
			// Default one.
			So(LogLevel(), ShouldEqual, logrus.ErrorLevel)

			os.Setenv(logLevelFlag.envName(), "debug")

			err := ParseEnv()
			So(err, ShouldBeNil)

			// Should be from environment.
			So(LogLevel(), ShouldEqual, logrus.DebugLevel)
		})
	})
}
<|endoftext|>