<commit_before>// Package datafiller implements function for randomly filling passed
// datastructures by mock sample data.
package datafiller

import (
	"math/rand"
	"reflect"
	"strings"
	"time"

	"github.com/Pallinder/go-randomdata"
)

func init() {
	packagesInit()
}

const (
	taggedStructKey = "datafiller"
)

// Function Fill takes a pointer to variable of any type and fills the variable
// by with sample data. It panics if the passed value is not a pointer.
func Fill(i interface{}) {
	f := NewFiller()
	f.Seed = time.Now().Unix()
	f.Fill(i)
}

type Filler struct {
	Seed     int64
	ArrayMin int
	ArrayMax int
}

type FillerArg interface {
	AddArg(*Filler)
}

type Seed int64

func (sed Seed) AddArg(f *Filler) {
	f.Seed = int64(sed)
}

type ArrayMin int

func (amn ArrayMin) AddArg(f *Filler) {
	f.ArrayMin = int(amn)
}

type ArrayMax int

func (amx ArrayMax) AddArg(f *Filler) {
	f.ArrayMax = int(amx)
}

func NewFiller(args ...FillerArg) *Filler {
	f := &Filler{
		Seed:     -1,
		ArrayMin: 1,
		ArrayMax: 3,
	}
	for _, a := range args {
		a.AddArg(f)
	}
	return f
}

func (f *Filler) Fill(i interface{}) {
	valPtr := reflect.ValueOf(i)

	if valPtr.Kind() != reflect.Ptr && valPtr.Kind() != reflect.UnsafePointer {
		panic("Passed argument is not a pointer.")
	}

	val := reflect.Indirect(valPtr)
	f.recursiveSet(val)

}

func taggedFieldSet(val reflect.Value, structTag string) {
	stringDataMap := make(map[string]func() string)

	stringDataMap["address"] = randomdata.Address
	stringDataMap["city"] = randomdata.City
	stringDataMap["email"] = randomdata.Email
	stringDataMap["lastname"] = randomdata.LastName
	stringDataMap["paragraph"] = randomdata.Paragraph
	stringDataMap["street"] = randomdata.Street
	stringDataMap["firstname"] = func() string { return randomdata.FirstName(randomdata.RandomGender) }
	stringDataMap["name"] = func() string { return randomdata.FullName(randomdata.RandomGender) }
	stringDataMap["country"] = func() string { return randomdata.Country(0) }
	stringDataMap["postalcode"] = func() string { return randomdata.PostalCode("US") }
	stringDataMap["state"] = func() string { return randomdata.State(1) }

	tags := strings.Split(structTag, ",")
	// TODO(tvi): Design struct tags ordering.
	if val.Kind() == reflect.String {
		gen, ok := stringDataMap[tags[0]]
		if ok {
			val.SetString(gen())
		}
	}
}

func (self *Filler) recursiveSet(val reflect.Value) {
	if val.CanSet() {
		var fullPath string
		fullPath = val.Type().PkgPath() + "." + val.Type().Name()
		pkgVal, ok := packages[fullPath]
		if ok {
			val.Set(pkgVal)
			return
		}

		if val.Kind() == reflect.Int ||
			val.Kind() == reflect.Int8 ||
			val.Kind() == reflect.Int16 ||
			val.Kind() == reflect.Int32 ||
			val.Kind() == reflect.Int64 {
			val.SetInt(rand.Int63n(100))
			return
		} else if val.Kind() == reflect.Uint ||
			val.Kind() == reflect.Uint8 ||
			val.Kind() == reflect.Uint16 ||
			val.Kind() == reflect.Uint32 ||
			val.Kind() == reflect.Uint64 {
			val.SetUint(uint64(rand.Int63n(100)))
			return
		} else if val.Kind() == reflect.Float32 ||
			val.Kind() == reflect.Float64 {
			val.SetFloat(float64(rand.Float32()))
			return
		} else if val.Kind() == reflect.Complex64 ||
			val.Kind() == reflect.Complex128 {
			cpx := complex128(complex(rand.Float32(), rand.Float32()))
			val.SetComplex(cpx)
			return
		} else if val.Kind() == reflect.Bool {
			val.SetBool(true)
			return
		} else if val.Kind() == reflect.String {
			val.SetString("test")
			return
		} else if val.Kind() == reflect.Struct {
			lngth := val.NumField()
			strType := val.Type()

			for i := 0; i < lngth; i++ {
				if strType.Field(i).Tag.Get(taggedStructKey) == "" {
					self.recursiveSet(val.Field(i))
				} else if strType.Field(i).Tag.Get(taggedStructKey) == "-" {
				} else {
					advStrTag := strType.Field(i).Tag.Get(taggedStructKey)
					taggedFieldSet(val.Field(i), advStrTag)
				}
			}
			return
		} else if val.Kind() == reflect.Ptr {
			self.recursiveSet(reflect.Indirect(val))
			return
		} else if val.Kind() == reflect.Slice {
			// TODO(tvi): Fix slice length.
			typ := val.Type()
			elem := typ.Elem()
			nw := reflect.Zero(elem)
			m := reflect.MakeSlice(typ, 0, 1)
			m = reflect.Append(m, nw)
			m = reflect.Append(m, nw)
			val.Set(m)
			self.recursiveSet(val.Index(0))
			self.recursiveSet(val.Index(1))
			return
		}
	}
}
<commit_msg>New Seed initializer.<commit_after>// Package datafiller implements function for randomly filling passed
// datastructures by mock sample data.
package datafiller

import (
	"math/rand"
	"reflect"
	"strings"
	"time"

	"github.com/Pallinder/go-randomdata"
)

func init() {
	packagesInit()
}

const (
	taggedStructKey = "datafiller"
)

// Function Fill takes a pointer to variable of any type and fills the variable
// by with sample data. It panics if the passed value is not a pointer.
func Fill(i interface{}) {
	f := NewFiller()
	f.Seed = time.Now().Unix()
	f.Fill(i)
}

type Filler struct {
	Seed     int64
	randSeed *rand.Rand
	ArrayMin int
	ArrayMax int
}

type FillerArg interface {
	AddArg(*Filler)
}

type Seed int64

func (sed Seed) AddArg(f *Filler) {
	f.Seed = int64(sed)
}

type ArrayMin int

func (amn ArrayMin) AddArg(f *Filler) {
	f.ArrayMin = int(amn)
}

type ArrayMax int

func (amx ArrayMax) AddArg(f *Filler) {
	f.ArrayMax = int(amx)
}

func NewFiller(args ...FillerArg) *Filler {
	f := &Filler{
		Seed:     -1,
		ArrayMin: 1,
		ArrayMax: 3,
	}
	for _, a := range args {
		a.AddArg(f)
	}
	return f
}

func (f *Filler) Fill(i interface{}) {
	valPtr := reflect.ValueOf(i)

	if valPtr.Kind() != reflect.Ptr && valPtr.Kind() != reflect.UnsafePointer {
		panic("Passed argument is not a pointer.")
	}

	val := reflect.Indirect(valPtr)

	f.randSeed = rand.New(rand.NewSource(f.Seed))
	f.recursiveSet(val)

}

func taggedFieldSet(val reflect.Value, structTag string) {
	stringDataMap := make(map[string]func() string)

	stringDataMap["address"] = randomdata.Address
	stringDataMap["city"] = randomdata.City
	stringDataMap["email"] = randomdata.Email
	stringDataMap["lastname"] = randomdata.LastName
	stringDataMap["paragraph"] = randomdata.Paragraph
	stringDataMap["street"] = randomdata.Street
	stringDataMap["firstname"] = func() string { return randomdata.FirstName(randomdata.RandomGender) }
	stringDataMap["name"] = func() string { return randomdata.FullName(randomdata.RandomGender) }
	stringDataMap["country"] = func() string { return randomdata.Country(0) }
	stringDataMap["postalcode"] = func() string { return randomdata.PostalCode("US") }
	stringDataMap["state"] = func() string { return randomdata.State(1) }

	tags := strings.Split(structTag, ",")
	// TODO(tvi): Design struct tags ordering.
	if val.Kind() == reflect.String {
		gen, ok := stringDataMap[tags[0]]
		if ok {
			val.SetString(gen())
		}
	}
}

func (self *Filler) recursiveSet(val reflect.Value) {
	if val.CanSet() {
		var fullPath string
		fullPath = val.Type().PkgPath() + "." + val.Type().Name()
		pkgVal, ok := packages[fullPath]
		if ok {
			val.Set(pkgVal)
			return
		}

		if val.Kind() == reflect.Int ||
			val.Kind() == reflect.Int8 ||
			val.Kind() == reflect.Int16 ||
			val.Kind() == reflect.Int32 ||
			val.Kind() == reflect.Int64 {
			val.SetInt(self.randSeed.Int63n(100))
			return
		} else if val.Kind() == reflect.Uint ||
			val.Kind() == reflect.Uint8 ||
			val.Kind() == reflect.Uint16 ||
			val.Kind() == reflect.Uint32 ||
			val.Kind() == reflect.Uint64 {
			val.SetUint(uint64(self.randSeed.Int63n(100)))
			return
		} else if val.Kind() == reflect.Float32 ||
			val.Kind() == reflect.Float64 {
			val.SetFloat(float64(self.randSeed.Float32()))
			return
		} else if val.Kind() == reflect.Complex64 ||
			val.Kind() == reflect.Complex128 {
			cpx := complex128(complex(self.randSeed.Float32(), self.randSeed.Float32()))
			val.SetComplex(cpx)
			return
		} else if val.Kind() == reflect.Bool {
			val.SetBool(true)
			return
		} else if val.Kind() == reflect.String {
			val.SetString("test")
			return
		} else if val.Kind() == reflect.Struct {
			lngth := val.NumField()
			strType := val.Type()

			for i := 0; i < lngth; i++ {
				if strType.Field(i).Tag.Get(taggedStructKey) == "" {
					self.recursiveSet(val.Field(i))
				} else if strType.Field(i).Tag.Get(taggedStructKey) == "-" {
				} else {
					advStrTag := strType.Field(i).Tag.Get(taggedStructKey)
					taggedFieldSet(val.Field(i), advStrTag)
				}
			}
			return
		} else if val.Kind() == reflect.Ptr {
			self.recursiveSet(reflect.Indirect(val))
			return
		} else if val.Kind() == reflect.Slice {
			// TODO(tvi): Fix slice length.
			typ := val.Type()
			elem := typ.Elem()
			nw := reflect.Zero(elem)
			m := reflect.MakeSlice(typ, 0, 1)
			m = reflect.Append(m, nw)
			m = reflect.Append(m, nw)
			val.Set(m)
			self.recursiveSet(val.Index(0))
			self.recursiveSet(val.Index(1))
			return
		}
	}
}
<|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.
*/

// Binary implements a Certificate Management service client.
package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"flag"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/google/gnxi/gnoi/cert"
	credUtils "github.com/google/gnxi/utils/credentials"
	"github.com/google/gnxi/utils/entity"
	"github.com/kylelemons/godebug/pretty"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	log "github.com/golang/glog"
)

var (
	certID     = flag.String("cert_id", "", "Certificate Management certificate ID.")
	certIDs    = flag.String("cert_ids", "", "Comma separated list of Certificate Management certificate IDs for revoke operation")
	op         = flag.String("op", "get", "Certificate Management operation, one of: provision, install, rotate, get, revoke, check")
	targetCN   = credUtils.TargetName
	targetAddr = flag.String("target_addr", "localhost:9339", "The target address in the format of host:port")
	timeOut    = flag.Duration("time_out", 5*time.Second, "Timeout for the operation, 5 seconds by default")
	minKeySize = flag.Uint("min_key_size", 128, "Minimum key size")
	country    = flag.String("country", "US", "Country in CSR parameters")
	state      = flag.String("state", "CA", "State in CSR parameters")
	org        = flag.String("organization", "", "Organization in CSR parameters")
	orgUnit    = flag.String("organizational_unit", "", "Organizational unit in CSR parameters")
	ipAddress  = flag.String("ip_address", "127.0.0.1", "IP address in CSR parameters")

	caEnt     *entity.Entity
	ctx       context.Context
	cancel    func()
	dial      = grpc.Dial
	loadCerts = credUtils.LoadCertificates
)

func main() {
	flag.Parse()

	if *targetCN == "" {
		log.Exit("Must set a Common Name ID with -target_name.")
	}

	ctx, cancel = context.WithTimeout(context.Background(), *timeOut)
	defer cancel()

	switch *op {
	case "provision":
		caEnt = credUtils.GetCAEntity()
		certIDCheck()
		provision()
	case "install":
		caEnt = credUtils.GetCAEntity()
		certIDCheck()
		install()
	case "rotate":
		caEnt = credUtils.GetCAEntity()
		certIDCheck()
		rotate()
	case "revoke":
		revoke()
	case "check":
		check()
	case "get":
		get()
	default:
		log.Exitf("Unknown operation: %q", *op)
	}
}

func certIDCheck() {
	if *certID == "" {
		log.Exit("Must set a certificate ID with -cert_id.")
	}
}

// gnoiEncrypted creates an encrypted TLS connection to the target.
func gnoiEncrypted(c tls.Certificate) (*grpc.ClientConn, *cert.Client) {
	opts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS(
		&tls.Config{
			InsecureSkipVerify: true,
			Certificates:       []tls.Certificate{c},
			RootCAs:            nil,
		}))}

	conn, err := dial(*targetAddr, opts...)
	if err != nil {
		log.Exitf("Failed dial to %q: %v", *targetAddr, err)
	}

	client := cert.NewClient(conn)
	return conn, client
}

// gnoiAuthenticated creates an authenticated TLS connection to the target.
func gnoiAuthenticated(targetName string) (*grpc.ClientConn, *cert.Client) {
	signed, certPool := loadCerts()

	opts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS(
		&tls.Config{
			ServerName:   targetName,
			Certificates: signed,
			RootCAs:      certPool,
		}))}

	conn, err := dial(*targetAddr, opts...)
	if err != nil {
		log.Exitf("Failed dial to %q: %v", *targetAddr, err)
	}

	client := cert.NewClient(conn)
	return conn, client
}

// signer is called to create a Certificate from a CSR.
func signer(csr *x509.CertificateRequest) (*x509.Certificate, error) {
	e, err := entity.FromSigningRequest(csr)
	if err != nil {
		return nil, fmt.Errorf("failed generating a cert from a CSR: %v", err)
	}
	if err := e.SignWith(caEnt); err != nil {
		return nil, fmt.Errorf("failed to sign the certificate: %v", err)
	}
	return e.Certificate.Leaf, nil
}

// provision provisions a target in bootstrapping mode.
func provision() {
	// Using the CA x509 cert as default Certificate, but can be any.
	conn, client := gnoiEncrypted(*caEnt.Certificate)
	defer conn.Close()
	pkiName := pkix.Name{CommonName: *targetCN, Organization: []string{*org}, OrganizationalUnit: []string{*orgUnit}, Country: []string{*country}, Province: []string{*state}}

	if err := client.Install(ctx, *certID, uint32(*minKeySize), pkiName, *ipAddress, signer, []*x509.Certificate{caEnt.Certificate.Leaf}); err != nil {
		log.Exit("Failed Install:", err)
	}
	log.Info("Install success")
}

// install installs a certificate in authenticated mode.
func install() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()
	pkiName := pkix.Name{CommonName: *targetCN, Organization: []string{*org}, OrganizationalUnit: []string{*orgUnit}, Country: []string{*country}, Province: []string{*state}}

	if err := client.Install(ctx, *certID, uint32(*minKeySize), pkiName, *ipAddress, signer, []*x509.Certificate{caEnt.Certificate.Leaf}); err != nil {
		log.Exit("Failed Install:", err)
	}
	log.Info("Install success")
}

// rotate rotates a certificate in authenticated mode.
func rotate() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()
	pkiName := pkix.Name{CommonName: *targetCN, Organization: []string{*org}, OrganizationalUnit: []string{*orgUnit}, Country: []string{*country}, Province: []string{*state}}

	if err := client.Rotate(ctx, *certID, uint32(*minKeySize), pkiName, *ipAddress, signer, []*x509.Certificate{caEnt.Certificate.Leaf}, func() error { return nil }); err != nil {
		log.Exit("Failed Rotate:", err)
	}
	log.Info("Rotate success")
}

// revoke revokes a certificate in authenticated mode.
func revoke() {
	var revokeCertIDs = []string{*certID}

	if *certIDs != "" {
		revokeCertIDs = strings.FieldsFunc(*certIDs, func(r rune) bool { return r == ',' })
		if len(revokeCertIDs) == 0 {
			log.Exit("Must specify comma separated certificate IDs when using -cert_ids")
		}
	} else if *certID == "" {
		log.Exit("Must set a certificate ID with -cert_id or set multiple IDs with -cert_ids")
	}
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()

	revoked, err := client.RevokeCertificates(ctx, revokeCertIDs)
	if err != nil {
		log.Exit("Failed RevokeCertificates:", err)
	}
	log.Info("RevokeCertificates:\n", pretty.Sprint(revoked))
}

// revoke checks if a target can generate certificates - authenticated mode.
func check() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()

	resp, err := client.CanGenerateCSR(ctx)
	if err != nil {
		log.Exit("Failed CanGenerateCSR:", err)
	}
	log.Info("CanGenerateCSR:\n", pretty.Sprint(resp))
}

// get fetches the installed certificates on a target - authenticated mode.
func get() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()

	resp, err := client.GetCertificates(ctx)
	if err != nil {
		log.Exit("Failed GetCertificates:", err)
	}

	pretty.DefaultFormatter[reflect.TypeOf(&x509.Certificate{})] = func(c *x509.Certificate) string {
		return pretty.Sprint(c.Subject.CommonName)
	}
	log.Info("GetCertificates:\n", pretty.Sprint(resp))
}
<commit_msg>Set default Organization in cert provision (#246)<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.
*/

// Binary implements a Certificate Management service client.
package main

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"flag"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/google/gnxi/gnoi/cert"
	credUtils "github.com/google/gnxi/utils/credentials"
	"github.com/google/gnxi/utils/entity"
	"github.com/kylelemons/godebug/pretty"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	log "github.com/golang/glog"
)

var (
	certID     = flag.String("cert_id", "", "Certificate Management certificate ID.")
	certIDs    = flag.String("cert_ids", "", "Comma separated list of Certificate Management certificate IDs for revoke operation")
	op         = flag.String("op", "get", "Certificate Management operation, one of: provision, install, rotate, get, revoke, check")
	targetCN   = credUtils.TargetName
	targetAddr = flag.String("target_addr", "localhost:9339", "The target address in the format of host:port")
	timeOut    = flag.Duration("time_out", 5*time.Second, "Timeout for the operation, 5 seconds by default")
	minKeySize = flag.Uint("min_key_size", 1024, "Minimum key size")
	country    = flag.String("country", "CH", "Country in CSR parameters")
	state      = flag.String("state", "ZRH", "State in CSR parameters")
	org        = flag.String("organization", "OpenConfig", "Organization in CSR parameters")
	orgUnit    = flag.String("organizational_unit", "gNxI", "Organizational unit in CSR parameters")
	ipAddress  = flag.String("ip_address", "127.0.0.1", "IP address in CSR parameters")

	caEnt     *entity.Entity
	ctx       context.Context
	cancel    func()
	dial      = grpc.Dial
	loadCerts = credUtils.LoadCertificates
)

func main() {
	flag.Parse()

	if *targetCN == "" {
		log.Exit("Must set a Common Name ID with -target_name.")
	}

	ctx, cancel = context.WithTimeout(context.Background(), *timeOut)
	defer cancel()

	switch *op {
	case "provision":
		caEnt = credUtils.GetCAEntity()
		certIDCheck()
		provision()
	case "install":
		caEnt = credUtils.GetCAEntity()
		certIDCheck()
		install()
	case "rotate":
		caEnt = credUtils.GetCAEntity()
		certIDCheck()
		rotate()
	case "revoke":
		revoke()
	case "check":
		check()
	case "get":
		get()
	default:
		log.Exitf("Unknown operation: %q", *op)
	}
}

func certIDCheck() {
	if *certID == "" {
		log.Exit("Must set a certificate ID with -cert_id.")
	}
}

// gnoiEncrypted creates an encrypted TLS connection to the target.
func gnoiEncrypted(c tls.Certificate) (*grpc.ClientConn, *cert.Client) {
	opts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS(
		&tls.Config{
			InsecureSkipVerify: true,
			Certificates:       []tls.Certificate{c},
			RootCAs:            nil,
		}))}

	conn, err := dial(*targetAddr, opts...)
	if err != nil {
		log.Exitf("Failed dial to %q: %v", *targetAddr, err)
	}

	client := cert.NewClient(conn)
	return conn, client
}

// gnoiAuthenticated creates an authenticated TLS connection to the target.
func gnoiAuthenticated(targetName string) (*grpc.ClientConn, *cert.Client) {
	signed, certPool := loadCerts()

	opts := []grpc.DialOption{grpc.WithTransportCredentials(credentials.NewTLS(
		&tls.Config{
			ServerName:   targetName,
			Certificates: signed,
			RootCAs:      certPool,
		}))}

	conn, err := dial(*targetAddr, opts...)
	if err != nil {
		log.Exitf("Failed dial to %q: %v", *targetAddr, err)
	}

	client := cert.NewClient(conn)
	return conn, client
}

// signer is called to create a Certificate from a CSR.
func signer(csr *x509.CertificateRequest) (*x509.Certificate, error) {
	e, err := entity.FromSigningRequest(csr)
	if err != nil {
		return nil, fmt.Errorf("failed generating a cert from a CSR: %v", err)
	}
	if err := e.SignWith(caEnt); err != nil {
		return nil, fmt.Errorf("failed to sign the certificate: %v", err)
	}
	return e.Certificate.Leaf, nil
}

// provision provisions a target in bootstrapping mode.
func provision() {
	// Using the CA x509 cert as default Certificate, but can be any.
	conn, client := gnoiEncrypted(*caEnt.Certificate)
	defer conn.Close()
	pkiName := pkix.Name{CommonName: *targetCN, Organization: []string{*org}, OrganizationalUnit: []string{*orgUnit}, Country: []string{*country}, Province: []string{*state}}

	if err := client.Install(ctx, *certID, uint32(*minKeySize), pkiName, *ipAddress, signer, []*x509.Certificate{caEnt.Certificate.Leaf}); err != nil {
		log.Exit("Failed Install:", err)
	}
	log.Info("Install success")
}

// install installs a certificate in authenticated mode.
func install() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()
	pkiName := pkix.Name{CommonName: *targetCN, Organization: []string{*org}, OrganizationalUnit: []string{*orgUnit}, Country: []string{*country}, Province: []string{*state}}

	if err := client.Install(ctx, *certID, uint32(*minKeySize), pkiName, *ipAddress, signer, []*x509.Certificate{caEnt.Certificate.Leaf}); err != nil {
		log.Exit("Failed Install:", err)
	}
	log.Info("Install success")
}

// rotate rotates a certificate in authenticated mode.
func rotate() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()
	pkiName := pkix.Name{CommonName: *targetCN, Organization: []string{*org}, OrganizationalUnit: []string{*orgUnit}, Country: []string{*country}, Province: []string{*state}}

	if err := client.Rotate(ctx, *certID, uint32(*minKeySize), pkiName, *ipAddress, signer, []*x509.Certificate{caEnt.Certificate.Leaf}, func() error { return nil }); err != nil {
		log.Exit("Failed Rotate:", err)
	}
	log.Info("Rotate success")
}

// revoke revokes a certificate in authenticated mode.
func revoke() {
	var revokeCertIDs = []string{*certID}

	if *certIDs != "" {
		revokeCertIDs = strings.FieldsFunc(*certIDs, func(r rune) bool { return r == ',' })
		if len(revokeCertIDs) == 0 {
			log.Exit("Must specify comma separated certificate IDs when using -cert_ids")
		}
	} else if *certID == "" {
		log.Exit("Must set a certificate ID with -cert_id or set multiple IDs with -cert_ids")
	}
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()

	revoked, err := client.RevokeCertificates(ctx, revokeCertIDs)
	if err != nil {
		log.Exit("Failed RevokeCertificates:", err)
	}
	log.Info("RevokeCertificates:\n", pretty.Sprint(revoked))
}

// revoke checks if a target can generate certificates - authenticated mode.
func check() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()

	resp, err := client.CanGenerateCSR(ctx)
	if err != nil {
		log.Exit("Failed CanGenerateCSR:", err)
	}
	log.Info("CanGenerateCSR:\n", pretty.Sprint(resp))
}

// get fetches the installed certificates on a target - authenticated mode.
func get() {
	conn, client := gnoiAuthenticated(*targetCN)
	defer conn.Close()

	resp, err := client.GetCertificates(ctx)
	if err != nil {
		log.Exit("Failed GetCertificates:", err)
	}

	pretty.DefaultFormatter[reflect.TypeOf(&x509.Certificate{})] = func(c *x509.Certificate) string {
		return pretty.Sprint(c.Subject.CommonName)
	}
	log.Info("GetCertificates:\n", pretty.Sprint(resp))
}
<|endoftext|>


<commit_before>package cloudfoundry

import (
	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-product-bundle/products/cloudfoundry/enaml-gen/acceptance-tests"
)

func NewAcceptanceTestsPartition(c *cli.Context, internet bool) InstanceGrouper {
	return &acceptanceTests{
		AZs:                      c.StringSlice("az"),
		StemcellName:             c.String("stemcell-name"),
		NetworkName:              c.String("network"),
		AppsDomain:               c.StringSlice("app-domain"),
		SystemDomain:             c.String("system-domain"),
		AdminPassword:            c.String("admin-password"),
		SkipCertVerify:           c.BoolT("skip-cert-verify"),
		IncludeInternetDependent: internet,
	}
}

func (a *acceptanceTests) ToInstanceGroup() *enaml.InstanceGroup {
	return &enaml.InstanceGroup{
		Name:      "acceptance-tests",
		Instances: 1,
		VMType:    "errand",
		Lifecycle: "errand",
		AZs:       a.AZs,
		Stemcell:  a.StemcellName,
		Networks: []enaml.Network{
			{Name: a.NetworkName},
		},
		Update: enaml.Update{
			MaxInFlight: 1,
		},
		Jobs: []enaml.InstanceJob{
			{
				Name:       "acceptance-tests",
				Release:    CFReleaseName,
				Properties: a.newAcceptanceTestsProperties(a.IncludeInternetDependent),
			},
		},
	}
}

func (a *acceptanceTests) newAcceptanceTestsProperties(internet bool) *acceptance_tests.AcceptanceTestsJob {
	var ad string
	if len(a.AppsDomain) > 0 {
		ad = a.AppsDomain[0]
	}
	return &acceptance_tests.AcceptanceTestsJob{
		AcceptanceTests: &acceptance_tests.AcceptanceTests{
			Api:                      prefixSystemDomain(a.SystemDomain, "api"),
			AppsDomain:               ad,
			AdminUser:                "admin",
			AdminPassword:            a.AdminPassword,
			IncludeLogging:           true,
			IncludeInternetDependent: internet,
			IncludeOperator:          true,
			IncludeServices:          true,
			IncludeSecurityGroups:    true,
			SkipSslValidation:        a.SkipCertVerify,
			SkipRegex:                "lucid64",
			JavaBuildpackName:        "java_buildpack_offline",
		},
	}
}

func (a *acceptanceTests) HasValidValues() bool {
	return len(a.AZs) > 0 &&
		a.StemcellName != "" &&
		a.NetworkName != "" &&
		len(a.AppsDomain) > 0 &&
		a.SystemDomain != "" &&
		a.AdminPassword != ""
}
<commit_msg>[#125968975] adding more verbose debug output for validations of acceptancetest<commit_after>package cloudfoundry

import (
	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-product-bundle/products/cloudfoundry/enaml-gen/acceptance-tests"
	"github.com/xchapter7x/lo"
)

func NewAcceptanceTestsPartition(c *cli.Context, internet bool) InstanceGrouper {
	return &acceptanceTests{
		AZs:                      c.StringSlice("az"),
		StemcellName:             c.String("stemcell-name"),
		NetworkName:              c.String("network"),
		AppsDomain:               c.StringSlice("app-domain"),
		SystemDomain:             c.String("system-domain"),
		AdminPassword:            c.String("admin-password"),
		SkipCertVerify:           c.BoolT("skip-cert-verify"),
		IncludeInternetDependent: internet,
	}
}

func (a *acceptanceTests) ToInstanceGroup() *enaml.InstanceGroup {
	return &enaml.InstanceGroup{
		Name:      "acceptance-tests",
		Instances: 1,
		VMType:    "errand",
		Lifecycle: "errand",
		AZs:       a.AZs,
		Stemcell:  a.StemcellName,
		Networks: []enaml.Network{
			{Name: a.NetworkName},
		},
		Update: enaml.Update{
			MaxInFlight: 1,
		},
		Jobs: []enaml.InstanceJob{
			{
				Name:       "acceptance-tests",
				Release:    CFReleaseName,
				Properties: a.newAcceptanceTestsProperties(a.IncludeInternetDependent),
			},
		},
	}
}

func (a *acceptanceTests) newAcceptanceTestsProperties(internet bool) *acceptance_tests.AcceptanceTestsJob {
	var ad string
	if len(a.AppsDomain) > 0 {
		ad = a.AppsDomain[0]
	}
	return &acceptance_tests.AcceptanceTestsJob{
		AcceptanceTests: &acceptance_tests.AcceptanceTests{
			Api:                      prefixSystemDomain(a.SystemDomain, "api"),
			AppsDomain:               ad,
			AdminUser:                "admin",
			AdminPassword:            a.AdminPassword,
			IncludeLogging:           true,
			IncludeInternetDependent: internet,
			IncludeOperator:          true,
			IncludeServices:          true,
			IncludeSecurityGroups:    true,
			SkipSslValidation:        a.SkipCertVerify,
			SkipRegex:                "lucid64",
			JavaBuildpackName:        "java_buildpack_offline",
		},
	}
}

func (a *acceptanceTests) HasValidValues() bool {
	lo.G.Debugf("checking '%s' for valid flags", "acceptanceTests")

	if len(a.AZs) <= 0 {
		lo.G.Debugf("could not find the correct number of AZs configured '%v' : '%v'", len(a.AZs), a.AZs)
	}

	if a.StemcellName == "" {
		lo.G.Debugf("could not find a valid stemcellname '%v'", a.StemcellName)
	}

	if a.NetworkName == "" {
		lo.G.Debugf("could not find a valid networkname '%v'", a.NetworkName)
	}

	if len(a.AppsDomain) <= 0 {
		lo.G.Debugf("could not find the correct number of app domains configured '%v' : '%v'", len(a.AppsDomain), a.AppsDomain)
	}

	if a.SystemDomain == "" {
		lo.G.Debugf("could not find a valid system domain '%v'", a.SystemDomain)
	}

	if a.AdminPassword == "" {
		lo.G.Debugf("could not find a valid admin password '%v'", a.AdminPassword)
	}

	return len(a.AZs) > 0 &&
		a.StemcellName != "" &&
		a.NetworkName != "" &&
		len(a.AppsDomain) > 0 &&
		a.SystemDomain != "" &&
		a.AdminPassword != ""
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
//
// +build !windows

package libfuse

import (
	"os"
	"sync"
	"time"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"github.com/keybase/client/go/kbfs/data"
	"github.com/keybase/client/go/kbfs/libfs"
	"github.com/keybase/client/go/kbfs/libkbfs"
	"github.com/keybase/client/go/kbfs/tlf"
	"github.com/keybase/client/go/kbfs/tlfhandle"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	"golang.org/x/net/context"
)

// TLF represents the root directory of a TLF. It wraps a lazy-loaded
// Dir.
type TLF struct {
	folder *Folder
	inode  uint64

	dirLock sync.RWMutex
	dir     *Dir

	// We never set quarantine on TLF roots, so don't bother with getting a dir
	// and calling the method on it. Instead, just use this dumb handler to
	// always return fuse.ENOTSUP.
	NoXattrHandler
}

func newTLF(ctx context.Context, fl *FolderList, h *tlfhandle.Handle,
	name tlf.PreferredName) *TLF {
	folder := newFolder(ctx, fl, h, name)
	tlf := &TLF{
		folder: folder,
		inode:  fl.fs.assignInode(),
	}
	return tlf
}

var _ DirInterface = (*TLF)(nil)

func (tlf *TLF) getStoredDir() *Dir {
	tlf.dirLock.RLock()
	defer tlf.dirLock.RUnlock()
	return tlf.dir
}

func (tlf *TLF) clearStoredDir() {
	tlf.dirLock.Lock()
	defer tlf.dirLock.Unlock()
	tlf.dir = nil
}

func (tlf *TLF) log() logger.Logger {
	return tlf.folder.fs.log
}

func (tlf *TLF) vlog() *libkb.VDebugLog {
	return tlf.folder.fs.vlog
}

func (tlf *TLF) loadDirHelper(
	ctx context.Context, mode libkbfs.ErrorModeType, branch data.BranchName,
	filterErr bool) (dir *Dir, exitEarly bool, err error) {
	dir = tlf.getStoredDir()
	if dir != nil {
		return dir, false, nil
	}

	tlf.dirLock.Lock()
	defer tlf.dirLock.Unlock()
	// Need to check for nilness again to avoid racing with other
	// calls to loadDir().
	if tlf.dir != nil {
		return tlf.dir, false, nil
	}

	tlf.log().CDebugf(ctx, "Loading root directory for folder %s "+
		"(type: %s, filter error: %t)", tlf.folder.name(),
		tlf.folder.list.tlfType, filterErr)
	defer func() {
		if filterErr {
			exitEarly, err = libfs.FilterTLFEarlyExitError(ctx, err, tlf.log(), tlf.folder.name())
		}
		err = tlf.folder.processError(ctx, mode, err)
	}()

	handle, err := tlf.folder.resolve(ctx)
	if err != nil {
		return nil, false, err
	}

	if branch == data.MasterBranch {
		conflictBranch, isLocalConflictBranch :=
			data.MakeConflictBranchName(handle)
		if isLocalConflictBranch {
			branch = conflictBranch
		}
	}

	var rootNode libkbfs.Node
	if filterErr {
		rootNode, _, err = tlf.folder.fs.config.KBFSOps().GetRootNode(
			ctx, handle, branch)
		if err != nil {
			return nil, false, err
		}
		// If not fake an empty directory.
		if rootNode == nil {
			return nil, false, libfs.TlfDoesNotExist{}
		}
	} else {
		rootNode, _, err = tlf.folder.fs.config.KBFSOps().GetOrCreateRootNode(
			ctx, handle, branch)
		if err != nil {
			return nil, false, err
		}
	}

	err = tlf.folder.setFolderBranch(rootNode.GetFolderBranch())
	if err != nil {
		return nil, false, err
	}

	tlf.folder.nodes[rootNode.GetID()] = tlf
	tlf.dir = newDirWithInode(tlf.folder, rootNode, tlf.inode)

	return tlf.dir, false, nil
}

func (tlf *TLF) loadDir(ctx context.Context) (*Dir, error) {
	dir, _, err := tlf.loadDirHelper(
		ctx, libkbfs.WriteMode, data.MasterBranch, false)
	return dir, err
}

// loadDirAllowNonexistent loads a TLF if it's not already loaded.  If
// the TLF doesn't yet exist, it still returns a nil error and
// indicates that the calling function should pretend it's an empty
// folder.
func (tlf *TLF) loadDirAllowNonexistent(ctx context.Context) (
	*Dir, bool, error) {
	return tlf.loadDirHelper(ctx, libkbfs.ReadMode, data.MasterBranch, true)
}

func (tlf *TLF) loadArchivedDir(
	ctx context.Context, branch data.BranchName) (*Dir, bool, error) {
	// Always filter errors for archive TLF directories, so that we
	// don't try to initialize them.
	return tlf.loadDirHelper(ctx, libkbfs.ReadMode, branch, true)
}

// Access implements the fs.NodeAccesser interface for *TLF.
func (tlf *TLF) Access(ctx context.Context, r *fuse.AccessRequest) error {
	return tlf.folder.access(ctx, r)
}

// Attr implements the fs.Node interface for TLF.
func (tlf *TLF) Attr(ctx context.Context, a *fuse.Attr) error {
	dir := tlf.getStoredDir()
	a.Inode = tlf.inode
	if dir == nil {
		tlf.vlog().CLogf(
			ctx, libkb.VLog1, "Faking Attr for TLF %s", tlf.folder.name())
		// Have a low non-zero value for Valid to avoid being
		// swamped with requests, while still not showing
		// stale data for too long if we end up loading the
		// dir.
		a.Valid = 1 * time.Second
		a.Mode = os.ModeDir | 0500
		a.Uid = uint32(os.Getuid())
		return nil
	}

	return dir.Attr(ctx, a)
}

// tlfLoadAvoidingLookupNames specifies a set of directory entry names
// that should NOT cause a TLF to be fully loaded and identified on a
// lookup.  If the directory is not yet loaded and one of these names
// are looked-up, then ENOENT will be returned automatically.  This is
// to avoid unnecessary loading and tracker popups when listing the
// folder list directories.  For example, when macOS finder opens
// `/keybase/private`, it looks up `.localized` in every TLF
// subdirectory to see if it should translate the TLF folder name or
// not, which can cause a tracker popup storm (see KBFS-2649).
var tlfLoadAvoidingLookupNames = map[string]bool{
	".localized": true,
}

// Lookup implements the fs.NodeRequestLookuper interface for TLF.
func (tlf *TLF) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {
	if tlfLoadAvoidingLookupNames[req.Name] {
		dir := tlf.getStoredDir()
		if dir == nil {
			tlf.vlog().CLogf(
				ctx, libkb.VLog1, "Avoiding TLF loading for name %s", req.Name)
			return nil, fuse.ENOENT
		}
		return dir.Lookup(ctx, req, resp)
	}

	dir, exitEarly, err := tlf.loadDirAllowNonexistent(ctx)
	if err != nil {
		return nil, err
	}
	if exitEarly {
		if node := handleTLFSpecialFile(
			req.Name, tlf.folder, &resp.EntryValid); node != nil {
			return node, nil
		}
		return nil, fuse.ENOENT
	}

	branch, isArchivedBranch := libfs.BranchNameFromArchiveRefDir(req.Name)
	if isArchivedBranch {
		archivedTLF := newTLF(ctx,
			tlf.folder.list, tlf.folder.h, tlf.folder.hPreferredName)
		_, _, err := archivedTLF.loadArchivedDir(ctx, branch)
		if err != nil {
			return nil, err
		}
		return archivedTLF, nil
	}

	linkTarget, isArchivedTimeLink, err := libfs.LinkTargetFromTimeString(
		ctx, tlf.folder.fs.config, tlf.folder.h, req.Name)
	if err != nil {
		return nil, err
	}
	if isArchivedTimeLink {
		return &Alias{
			realPath: linkTarget,
			inode:    0,
		}, nil
	}

	_, isRelTimeLink, err := libfs.FileDataFromRelativeTimeString(
		ctx, tlf.folder.fs.config, tlf.folder.h, req.Name)
	if err != nil {
		return nil, err
	}
	if isRelTimeLink {
		return NewArchiveRelTimeFile(
			tlf.folder.fs, tlf.folder.h, req.Name, &resp.EntryValid), nil
	}

	return dir.Lookup(ctx, req, resp)
}

// Create implements the fs.NodeCreater interface for TLF.
func (tlf *TLF) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return nil, nil, err
	}
	return dir.Create(ctx, req, resp)
}

// Mkdir implements the fs.NodeMkdirer interface for TLF.
func (tlf *TLF) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (_ fs.Node, err error) {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return nil, err
	}
	return dir.Mkdir(ctx, req)
}

// Symlink implements the fs.NodeSymlinker interface for TLF.
func (tlf *TLF) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (
	fs.Node, error) {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return nil, err
	}
	return dir.Symlink(ctx, req)
}

var _ fs.NodeLinker = (*TLF)(nil)

// Link implements the fs.NodeLinker interface for TLF.
func (tlf *TLF) Link(
	_ context.Context, _ *fuse.LinkRequest, _ fs.Node) (fs.Node, error) {
	return nil, fuse.ENOTSUP
}

// Rename implements the fs.NodeRenamer interface for TLF.
func (tlf *TLF) Rename(ctx context.Context, req *fuse.RenameRequest,
	newDir fs.Node) error {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return err
	}
	return dir.Rename(ctx, req, newDir)
}

// Remove implements the fs.NodeRemover interface for TLF.
func (tlf *TLF) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return err
	}
	return dir.Remove(ctx, req)
}

// ReadDirAll implements the fs.NodeReadDirAller interface for TLF.
func (tlf *TLF) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	dir, exitEarly, err := tlf.loadDirAllowNonexistent(ctx)
	if err != nil || exitEarly {
		return nil, err
	}
	return dir.ReadDirAll(ctx)
}

// Forget kernel reference to this node.
func (tlf *TLF) Forget() {
	dir := tlf.getStoredDir()
	if dir != nil {
		dir.Forget()
	} else {
		tlf.folder.list.forgetFolder(string(tlf.folder.name()))
	}
}

// Setattr implements the fs.NodeSetattrer interface for TLF.
func (tlf *TLF) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return err
	}
	return dir.Setattr(ctx, req, resp)
}

// Fsync implements the fs.NodeFsyncer interface for TLF.
func (tlf *TLF) Fsync(ctx context.Context, req *fuse.FsyncRequest) (err error) {
	dir := tlf.getStoredDir()
	if dir == nil {
		// The directory hasn't been loaded yet, so there's nothing to do.
		return nil
	}

	return dir.Fsync(ctx, req)
}

var _ fs.Handle = (*TLF)(nil)

var _ fs.NodeOpener = (*TLF)(nil)

// Open implements the fs.NodeOpener interface for TLF.
func (tlf *TLF) Open(ctx context.Context, req *fuse.OpenRequest,
	resp *fuse.OpenResponse) (fs.Handle, error) {
	// Explicitly load the directory when a TLF is opened, because
	// some OSX programs like ls have a bug that doesn't report errors
	// on a ReadDirAll.
	_, _, err := tlf.loadDirAllowNonexistent(ctx)
	if err != nil {
		return nil, err
	}
	return tlf, nil
}

func (tlf *TLF) openFileCount() int64 {
	return tlf.folder.openFileCount()
}
<commit_msg>tlf: avoid loading TLFs on a "Contents" lookup<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
//
// +build !windows

package libfuse

import (
	"os"
	"sync"
	"time"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"github.com/keybase/client/go/kbfs/data"
	"github.com/keybase/client/go/kbfs/libfs"
	"github.com/keybase/client/go/kbfs/libkbfs"
	"github.com/keybase/client/go/kbfs/tlf"
	"github.com/keybase/client/go/kbfs/tlfhandle"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	"golang.org/x/net/context"
)

// TLF represents the root directory of a TLF. It wraps a lazy-loaded
// Dir.
type TLF struct {
	folder *Folder
	inode  uint64

	dirLock sync.RWMutex
	dir     *Dir

	// We never set quarantine on TLF roots, so don't bother with getting a dir
	// and calling the method on it. Instead, just use this dumb handler to
	// always return fuse.ENOTSUP.
	NoXattrHandler
}

func newTLF(ctx context.Context, fl *FolderList, h *tlfhandle.Handle,
	name tlf.PreferredName) *TLF {
	folder := newFolder(ctx, fl, h, name)
	tlf := &TLF{
		folder: folder,
		inode:  fl.fs.assignInode(),
	}
	return tlf
}

var _ DirInterface = (*TLF)(nil)

func (tlf *TLF) getStoredDir() *Dir {
	tlf.dirLock.RLock()
	defer tlf.dirLock.RUnlock()
	return tlf.dir
}

func (tlf *TLF) clearStoredDir() {
	tlf.dirLock.Lock()
	defer tlf.dirLock.Unlock()
	tlf.dir = nil
}

func (tlf *TLF) log() logger.Logger {
	return tlf.folder.fs.log
}

func (tlf *TLF) vlog() *libkb.VDebugLog {
	return tlf.folder.fs.vlog
}

func (tlf *TLF) loadDirHelper(
	ctx context.Context, mode libkbfs.ErrorModeType, branch data.BranchName,
	filterErr bool) (dir *Dir, exitEarly bool, err error) {
	dir = tlf.getStoredDir()
	if dir != nil {
		return dir, false, nil
	}

	tlf.dirLock.Lock()
	defer tlf.dirLock.Unlock()
	// Need to check for nilness again to avoid racing with other
	// calls to loadDir().
	if tlf.dir != nil {
		return tlf.dir, false, nil
	}

	tlf.log().CDebugf(ctx, "Loading root directory for folder %s "+
		"(type: %s, filter error: %t)", tlf.folder.name(),
		tlf.folder.list.tlfType, filterErr)
	defer func() {
		if filterErr {
			exitEarly, err = libfs.FilterTLFEarlyExitError(ctx, err, tlf.log(), tlf.folder.name())
		}
		err = tlf.folder.processError(ctx, mode, err)
	}()

	handle, err := tlf.folder.resolve(ctx)
	if err != nil {
		return nil, false, err
	}

	if branch == data.MasterBranch {
		conflictBranch, isLocalConflictBranch :=
			data.MakeConflictBranchName(handle)
		if isLocalConflictBranch {
			branch = conflictBranch
		}
	}

	var rootNode libkbfs.Node
	if filterErr {
		rootNode, _, err = tlf.folder.fs.config.KBFSOps().GetRootNode(
			ctx, handle, branch)
		if err != nil {
			return nil, false, err
		}
		// If not fake an empty directory.
		if rootNode == nil {
			return nil, false, libfs.TlfDoesNotExist{}
		}
	} else {
		rootNode, _, err = tlf.folder.fs.config.KBFSOps().GetOrCreateRootNode(
			ctx, handle, branch)
		if err != nil {
			return nil, false, err
		}
	}

	err = tlf.folder.setFolderBranch(rootNode.GetFolderBranch())
	if err != nil {
		return nil, false, err
	}

	tlf.folder.nodes[rootNode.GetID()] = tlf
	tlf.dir = newDirWithInode(tlf.folder, rootNode, tlf.inode)

	return tlf.dir, false, nil
}

func (tlf *TLF) loadDir(ctx context.Context) (*Dir, error) {
	dir, _, err := tlf.loadDirHelper(
		ctx, libkbfs.WriteMode, data.MasterBranch, false)
	return dir, err
}

// loadDirAllowNonexistent loads a TLF if it's not already loaded.  If
// the TLF doesn't yet exist, it still returns a nil error and
// indicates that the calling function should pretend it's an empty
// folder.
func (tlf *TLF) loadDirAllowNonexistent(ctx context.Context) (
	*Dir, bool, error) {
	return tlf.loadDirHelper(ctx, libkbfs.ReadMode, data.MasterBranch, true)
}

func (tlf *TLF) loadArchivedDir(
	ctx context.Context, branch data.BranchName) (*Dir, bool, error) {
	// Always filter errors for archive TLF directories, so that we
	// don't try to initialize them.
	return tlf.loadDirHelper(ctx, libkbfs.ReadMode, branch, true)
}

// Access implements the fs.NodeAccesser interface for *TLF.
func (tlf *TLF) Access(ctx context.Context, r *fuse.AccessRequest) error {
	return tlf.folder.access(ctx, r)
}

// Attr implements the fs.Node interface for TLF.
func (tlf *TLF) Attr(ctx context.Context, a *fuse.Attr) error {
	dir := tlf.getStoredDir()
	a.Inode = tlf.inode
	if dir == nil {
		tlf.vlog().CLogf(
			ctx, libkb.VLog1, "Faking Attr for TLF %s", tlf.folder.name())
		// Have a low non-zero value for Valid to avoid being
		// swamped with requests, while still not showing
		// stale data for too long if we end up loading the
		// dir.
		a.Valid = 1 * time.Second
		a.Mode = os.ModeDir | 0500
		a.Uid = uint32(os.Getuid())
		return nil
	}

	return dir.Attr(ctx, a)
}

// tlfLoadAvoidingLookupNames specifies a set of directory entry names
// that should NOT cause a TLF to be fully loaded and identified on a
// lookup.  If the directory is not yet loaded and one of these names
// are looked-up, then ENOENT will be returned automatically.  This is
// to avoid unnecessary loading and tracker popups when listing the
// folder list directories.  For example, when macOS finder opens
// `/keybase/private`, it looks up `.localized` in every TLF
// subdirectory to see if it should translate the TLF folder name or
// not, which can cause a tracker popup storm (see KBFS-2649).
var tlfLoadAvoidingLookupNames = map[string]bool{
	".localized": true,
	"Contents":   true,
}

// Lookup implements the fs.NodeRequestLookuper interface for TLF.
func (tlf *TLF) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (fs.Node, error) {
	if tlfLoadAvoidingLookupNames[req.Name] {
		dir := tlf.getStoredDir()
		if dir == nil {
			tlf.vlog().CLogf(
				ctx, libkb.VLog1, "Avoiding TLF loading for name %s", req.Name)
			return nil, fuse.ENOENT
		}
		return dir.Lookup(ctx, req, resp)
	}

	dir, exitEarly, err := tlf.loadDirAllowNonexistent(ctx)
	if err != nil {
		return nil, err
	}
	if exitEarly {
		if node := handleTLFSpecialFile(
			req.Name, tlf.folder, &resp.EntryValid); node != nil {
			return node, nil
		}
		return nil, fuse.ENOENT
	}

	branch, isArchivedBranch := libfs.BranchNameFromArchiveRefDir(req.Name)
	if isArchivedBranch {
		archivedTLF := newTLF(ctx,
			tlf.folder.list, tlf.folder.h, tlf.folder.hPreferredName)
		_, _, err := archivedTLF.loadArchivedDir(ctx, branch)
		if err != nil {
			return nil, err
		}
		return archivedTLF, nil
	}

	linkTarget, isArchivedTimeLink, err := libfs.LinkTargetFromTimeString(
		ctx, tlf.folder.fs.config, tlf.folder.h, req.Name)
	if err != nil {
		return nil, err
	}
	if isArchivedTimeLink {
		return &Alias{
			realPath: linkTarget,
			inode:    0,
		}, nil
	}

	_, isRelTimeLink, err := libfs.FileDataFromRelativeTimeString(
		ctx, tlf.folder.fs.config, tlf.folder.h, req.Name)
	if err != nil {
		return nil, err
	}
	if isRelTimeLink {
		return NewArchiveRelTimeFile(
			tlf.folder.fs, tlf.folder.h, req.Name, &resp.EntryValid), nil
	}

	return dir.Lookup(ctx, req, resp)
}

// Create implements the fs.NodeCreater interface for TLF.
func (tlf *TLF) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return nil, nil, err
	}
	return dir.Create(ctx, req, resp)
}

// Mkdir implements the fs.NodeMkdirer interface for TLF.
func (tlf *TLF) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (_ fs.Node, err error) {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return nil, err
	}
	return dir.Mkdir(ctx, req)
}

// Symlink implements the fs.NodeSymlinker interface for TLF.
func (tlf *TLF) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (
	fs.Node, error) {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return nil, err
	}
	return dir.Symlink(ctx, req)
}

var _ fs.NodeLinker = (*TLF)(nil)

// Link implements the fs.NodeLinker interface for TLF.
func (tlf *TLF) Link(
	_ context.Context, _ *fuse.LinkRequest, _ fs.Node) (fs.Node, error) {
	return nil, fuse.ENOTSUP
}

// Rename implements the fs.NodeRenamer interface for TLF.
func (tlf *TLF) Rename(ctx context.Context, req *fuse.RenameRequest,
	newDir fs.Node) error {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return err
	}
	return dir.Rename(ctx, req, newDir)
}

// Remove implements the fs.NodeRemover interface for TLF.
func (tlf *TLF) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return err
	}
	return dir.Remove(ctx, req)
}

// ReadDirAll implements the fs.NodeReadDirAller interface for TLF.
func (tlf *TLF) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	dir, exitEarly, err := tlf.loadDirAllowNonexistent(ctx)
	if err != nil || exitEarly {
		return nil, err
	}
	return dir.ReadDirAll(ctx)
}

// Forget kernel reference to this node.
func (tlf *TLF) Forget() {
	dir := tlf.getStoredDir()
	if dir != nil {
		dir.Forget()
	} else {
		tlf.folder.list.forgetFolder(string(tlf.folder.name()))
	}
}

// Setattr implements the fs.NodeSetattrer interface for TLF.
func (tlf *TLF) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
	dir, err := tlf.loadDir(ctx)
	if err != nil {
		return err
	}
	return dir.Setattr(ctx, req, resp)
}

// Fsync implements the fs.NodeFsyncer interface for TLF.
func (tlf *TLF) Fsync(ctx context.Context, req *fuse.FsyncRequest) (err error) {
	dir := tlf.getStoredDir()
	if dir == nil {
		// The directory hasn't been loaded yet, so there's nothing to do.
		return nil
	}

	return dir.Fsync(ctx, req)
}

var _ fs.Handle = (*TLF)(nil)

var _ fs.NodeOpener = (*TLF)(nil)

// Open implements the fs.NodeOpener interface for TLF.
func (tlf *TLF) Open(ctx context.Context, req *fuse.OpenRequest,
	resp *fuse.OpenResponse) (fs.Handle, error) {
	// Explicitly load the directory when a TLF is opened, because
	// some OSX programs like ls have a bug that doesn't report errors
	// on a ReadDirAll.
	_, _, err := tlf.loadDirAllowNonexistent(ctx)
	if err != nil {
		return nil, err
	}
	return tlf, nil
}

func (tlf *TLF) openFileCount() int64 {
	return tlf.folder.openFileCount()
}
<|endoftext|>


<commit_before>// Package vtctld contains all the code to expose a vtctld server
// based on the provided topo.Server.
package vtctld

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"

	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/acl"
	"github.com/youtube/vitess/go/vt/key"
	"github.com/youtube/vitess/go/vt/topo"
	"github.com/youtube/vitess/go/vt/wrangler"
	"golang.org/x/net/context"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

var (
	webDir = flag.String("web_dir", "", "directory from which to serve vtctld web interface resources")
	// webDir2 is a temporary additional dir for a new, in-development UI.
	webDir2             = flag.String("web_dir2", "", "directory from which to serve vtctld2 web interface resources")
	enableRealtimeStats = flag.Bool("enable_realtime_stats", false, "Required for the Realtime Stats view. If set, vtctld will maintain a streaming RPC to each tablet (in all cells) to gather the realtime health stats.")
)

const (
	appPrefix = "/app/"
	// appPrefix2 is a temporary additional path for a new, in-development UI.
	appPrefix2 = "/app2/"
)

// InitVtctld initializes all the vtctld functionnality.
func InitVtctld(ts topo.Server) {
	actionRepo := NewActionRepository(ts)

	// keyspace actions
	actionRepo.RegisterKeyspaceAction("ValidateKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidateKeyspace(ctx, keyspace, false)
		})

	actionRepo.RegisterKeyspaceAction("ValidateSchemaKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidateSchemaKeyspace(ctx, keyspace, nil, false)
		})

	actionRepo.RegisterKeyspaceAction("ValidateVersionKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidateVersionKeyspace(ctx, keyspace)
		})

	actionRepo.RegisterKeyspaceAction("ValidatePermissionsKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidatePermissionsKeyspace(ctx, keyspace)
		})

	actionRepo.RegisterKeyspaceAction("CreateKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			shardingColumnName := r.FormValue("shardingColumnName")
			shardingColumnType := r.FormValue("shardingColumnType")
			kit, err := key.ParseKeyspaceIDType(shardingColumnType)
			if err != nil {
				return "", err
			}
			ki := &topodatapb.Keyspace{
				ShardingColumnName: shardingColumnName,
				ShardingColumnType: kit,
			}
			return "", wr.TopoServer().CreateKeyspace(ctx, keyspace, ki)
		})

	actionRepo.RegisterKeyspaceAction("EditKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			shardingColumnName := r.FormValue("shardingColumnName")
			shardingColumnType := r.FormValue("shardingColumnType")
			forceString := r.FormValue("force")
			force := false
			if forceString == "true" {
				force = true
			}

			kit := topodatapb.KeyspaceIdType_UNSET
			var err error
			kit, err = key.ParseKeyspaceIDType(shardingColumnType)
			if err != nil {
				return "", err
			}

			keyspaceIDTypeSet := (kit != topodatapb.KeyspaceIdType_UNSET)
			columnNameSet := (shardingColumnName != "")
			if (keyspaceIDTypeSet && !columnNameSet) || (!keyspaceIDTypeSet && columnNameSet) {
				return "", fmt.Errorf("Both <column name> and <column type> must be set, or both must be unset.")
			}
			return "", wr.SetKeyspaceShardingInfo(ctx, keyspace, shardingColumnName, kit, force)
		})

	actionRepo.RegisterKeyspaceAction("DeleteKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			recursiveString := r.FormValue("recursive")
			recursive := false
			if recursiveString == "true" {
				recursive = true
			}
			return "", wr.DeleteKeyspace(ctx, keyspace, recursive)
		})

	// shard actions
	actionRepo.RegisterShardAction("ValidateShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidateShard(ctx, keyspace, shard, false)
		})

	actionRepo.RegisterShardAction("ValidateSchemaShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidateSchemaShard(ctx, keyspace, shard, nil, false)
		})

	actionRepo.RegisterShardAction("ValidateVersionShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidateVersionShard(ctx, keyspace, shard)
		})

	actionRepo.RegisterShardAction("ValidatePermissionsShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidatePermissionsShard(ctx, keyspace, shard)
		})

	// tablet actions
	actionRepo.RegisterTabletAction("Ping", "",
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias)
			if err != nil {
				return "", err
			}
			return "", wr.TabletManagerClient().Ping(ctx, ti.Tablet)
		})

	actionRepo.RegisterTabletAction("RefreshState", acl.ADMIN,
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias)
			if err != nil {
				return "", err
			}
			return "", wr.TabletManagerClient().RefreshState(ctx, ti.Tablet)
		})

	actionRepo.RegisterTabletAction("DeleteTablet", acl.ADMIN,
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			return "", wr.DeleteTablet(ctx, tabletAlias, false)
		})

	actionRepo.RegisterTabletAction("ReloadSchema", acl.ADMIN,
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			return "", wr.ReloadSchema(ctx, tabletAlias)
		})

	// Anything unrecognized gets redirected to the main app page.
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, appPrefix, http.StatusFound)
	})

	// Serve the static files for the vtctld web app.
	http.HandleFunc(appPrefix, func(w http.ResponseWriter, r *http.Request) {
		// Strip the prefix.
		parts := strings.SplitN(r.URL.Path, "/", 3)
		if len(parts) != 3 {
			http.NotFound(w, r)
			return
		}
		rest := parts[2]
		if rest == "" {
			rest = "index.html"
		}
		http.ServeFile(w, r, path.Join(*webDir, rest))
	})

	// Serve the static files for the vtctld2 web app.
	// This is a temporary additional URL for serving the new,
	// in-development UI side-by-side with the current one.
	http.HandleFunc(appPrefix2, func(w http.ResponseWriter, r *http.Request) {
		// Strip the prefix.
		parts := strings.SplitN(r.URL.Path, "/", 3)
		if len(parts) != 3 {
			http.NotFound(w, r)
			return
		}
		rest := parts[2]
		if rest == "" {
			rest = "index.html"
		}
		filePath := path.Join(*webDir2, rest)
		// If the requested file doesn't exist, serve index.html.
		if _, err := os.Stat(filePath); err != nil {
			filePath = path.Join(*webDir2, "index.html")
		}
		http.ServeFile(w, r, filePath)
	})

	var realtimeStats *realtimeStats
	if *enableRealtimeStats {
		var err error
		realtimeStats, err = newRealtimeStats(ts)
		if err != nil {
			log.Errorf("Failed to instantiate RealtimeStats at startup: %v", err)
		}
	}

	// Serve the REST API for the vtctld web app.
	initAPI(context.Background(), ts, actionRepo, realtimeStats)

	// Init redirects for explorers
	initExplorer(ts)
}
<commit_msg>Fixed go double import<commit_after>// Package vtctld contains all the code to expose a vtctld server
// based on the provided topo.Server.
package vtctld

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"path"
	"strings"

	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/acl"
	"github.com/youtube/vitess/go/vt/key"
	"github.com/youtube/vitess/go/vt/topo"
	"github.com/youtube/vitess/go/vt/wrangler"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

var (
	webDir = flag.String("web_dir", "", "directory from which to serve vtctld web interface resources")
	// webDir2 is a temporary additional dir for a new, in-development UI.
	webDir2             = flag.String("web_dir2", "", "directory from which to serve vtctld2 web interface resources")
	enableRealtimeStats = flag.Bool("enable_realtime_stats", false, "Required for the Realtime Stats view. If set, vtctld will maintain a streaming RPC to each tablet (in all cells) to gather the realtime health stats.")
)

const (
	appPrefix = "/app/"
	// appPrefix2 is a temporary additional path for a new, in-development UI.
	appPrefix2 = "/app2/"
)

// InitVtctld initializes all the vtctld functionnality.
func InitVtctld(ts topo.Server) {
	actionRepo := NewActionRepository(ts)

	// keyspace actions
	actionRepo.RegisterKeyspaceAction("ValidateKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidateKeyspace(ctx, keyspace, false)
		})

	actionRepo.RegisterKeyspaceAction("ValidateSchemaKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidateSchemaKeyspace(ctx, keyspace, nil, false)
		})

	actionRepo.RegisterKeyspaceAction("ValidateVersionKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidateVersionKeyspace(ctx, keyspace)
		})

	actionRepo.RegisterKeyspaceAction("ValidatePermissionsKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			return "", wr.ValidatePermissionsKeyspace(ctx, keyspace)
		})

	actionRepo.RegisterKeyspaceAction("CreateKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			shardingColumnName := r.FormValue("shardingColumnName")
			shardingColumnType := r.FormValue("shardingColumnType")
			kit, err := key.ParseKeyspaceIDType(shardingColumnType)
			if err != nil {
				return "", err
			}
			ki := &topodatapb.Keyspace{
				ShardingColumnName: shardingColumnName,
				ShardingColumnType: kit,
			}
			return "", wr.TopoServer().CreateKeyspace(ctx, keyspace, ki)
		})

	actionRepo.RegisterKeyspaceAction("EditKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			shardingColumnName := r.FormValue("shardingColumnName")
			shardingColumnType := r.FormValue("shardingColumnType")
			forceString := r.FormValue("force")
			force := false
			if forceString == "true" {
				force = true
			}

			kit := topodatapb.KeyspaceIdType_UNSET
			var err error
			kit, err = key.ParseKeyspaceIDType(shardingColumnType)
			if err != nil {
				return "", err
			}

			keyspaceIDTypeSet := (kit != topodatapb.KeyspaceIdType_UNSET)
			columnNameSet := (shardingColumnName != "")
			if (keyspaceIDTypeSet && !columnNameSet) || (!keyspaceIDTypeSet && columnNameSet) {
				return "", fmt.Errorf("Both <column name> and <column type> must be set, or both must be unset.")
			}
			return "", wr.SetKeyspaceShardingInfo(ctx, keyspace, shardingColumnName, kit, force)
		})

	actionRepo.RegisterKeyspaceAction("DeleteKeyspace",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace string, r *http.Request) (string, error) {
			recursiveString := r.FormValue("recursive")
			recursive := false
			if recursiveString == "true" {
				recursive = true
			}
			return "", wr.DeleteKeyspace(ctx, keyspace, recursive)
		})

	// shard actions
	actionRepo.RegisterShardAction("ValidateShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidateShard(ctx, keyspace, shard, false)
		})

	actionRepo.RegisterShardAction("ValidateSchemaShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidateSchemaShard(ctx, keyspace, shard, nil, false)
		})

	actionRepo.RegisterShardAction("ValidateVersionShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidateVersionShard(ctx, keyspace, shard)
		})

	actionRepo.RegisterShardAction("ValidatePermissionsShard",
		func(ctx context.Context, wr *wrangler.Wrangler, keyspace, shard string, r *http.Request) (string, error) {
			return "", wr.ValidatePermissionsShard(ctx, keyspace, shard)
		})

	// tablet actions
	actionRepo.RegisterTabletAction("Ping", "",
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias)
			if err != nil {
				return "", err
			}
			return "", wr.TabletManagerClient().Ping(ctx, ti.Tablet)
		})

	actionRepo.RegisterTabletAction("RefreshState", acl.ADMIN,
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			ti, err := wr.TopoServer().GetTablet(ctx, tabletAlias)
			if err != nil {
				return "", err
			}
			return "", wr.TabletManagerClient().RefreshState(ctx, ti.Tablet)
		})

	actionRepo.RegisterTabletAction("DeleteTablet", acl.ADMIN,
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			return "", wr.DeleteTablet(ctx, tabletAlias, false)
		})

	actionRepo.RegisterTabletAction("ReloadSchema", acl.ADMIN,
		func(ctx context.Context, wr *wrangler.Wrangler, tabletAlias *topodatapb.TabletAlias, r *http.Request) (string, error) {
			return "", wr.ReloadSchema(ctx, tabletAlias)
		})

	// Anything unrecognized gets redirected to the main app page.
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, appPrefix, http.StatusFound)
	})

	// Serve the static files for the vtctld web app.
	http.HandleFunc(appPrefix, func(w http.ResponseWriter, r *http.Request) {
		// Strip the prefix.
		parts := strings.SplitN(r.URL.Path, "/", 3)
		if len(parts) != 3 {
			http.NotFound(w, r)
			return
		}
		rest := parts[2]
		if rest == "" {
			rest = "index.html"
		}
		http.ServeFile(w, r, path.Join(*webDir, rest))
	})

	// Serve the static files for the vtctld2 web app.
	// This is a temporary additional URL for serving the new,
	// in-development UI side-by-side with the current one.
	http.HandleFunc(appPrefix2, func(w http.ResponseWriter, r *http.Request) {
		// Strip the prefix.
		parts := strings.SplitN(r.URL.Path, "/", 3)
		if len(parts) != 3 {
			http.NotFound(w, r)
			return
		}
		rest := parts[2]
		if rest == "" {
			rest = "index.html"
		}
		filePath := path.Join(*webDir2, rest)
		// If the requested file doesn't exist, serve index.html.
		if _, err := os.Stat(filePath); err != nil {
			filePath = path.Join(*webDir2, "index.html")
		}
		http.ServeFile(w, r, filePath)
	})

	var realtimeStats *realtimeStats
	if *enableRealtimeStats {
		var err error
		realtimeStats, err = newRealtimeStats(ts)
		if err != nil {
			log.Errorf("Failed to instantiate RealtimeStats at startup: %v", err)
		}
	}

	// Serve the REST API for the vtctld web app.
	initAPI(context.Background(), ts, actionRepo, realtimeStats)

	// Init redirects for explorers
	initExplorer(ts)
}
<|endoftext|>


<commit_before>package otp

import "sync"

const (
	TypeTOTP int16 = 1
	TypeHOTP       = 2
)

func ValidType(t int16) bool {
	return (t == TypeTOTP || t == TypeHOTP)
}

type Authenticator struct {
	mux     *sync.RWMutex
	Type    int16
	OTPAuth map[string]OTP
}

func NewAuthenticator(_type int16) (*Authenticator, error) {
	if !ValidType(_type) {
		return nil, ErrType
	}
	return &Authenticator{
		mux:     new(sync.RWMutex),
		Type:    _type,
		OTPAuth: make(map[string]OTP),
	}, nil
}

func (a *Authenticator) AddSecret(id, secret string) (OTP, error) {
	if len(id) == 0 {
		return nil, ErrID
	}
	a.mux.Lock()
	defer a.mux.Unlock()
	if v, ok := a.OTPAuth[id]; ok {
		return v, ErrExist
	}
	switch a.Type {
	case TypeTOTP:
		a.OTPAuth[id] = NewTOTP(3).SetSecret(secret)
	case TypeHOTP:
		a.OTPAuth[id] = NewHOTP(5).SetSecret(secret)
	default:
		return nil, ErrType
	}
	return a.OTPAuth[id], nil
}

func (a *Authenticator) GetSecret(id string) string {
	if v, ok := a.OTPAuth[id]; ok {
		return v.GetSecret()
	}
	return ""
}

func (a *Authenticator) ValidSecret(id string) bool {
	if v, ok := a.OTPAuth[id]; ok {
		return v.ValidSecret()
	}
	return false
}

func (a *Authenticator) URL(id, user, issuer string) string {
	if v, ok := a.OTPAuth[id]; ok {
		return v.URL(user, issuer)
	}
	return ""
}

func (a *Authenticator) Verify(id, password string) (bool, error) {
	if v, ok := a.OTPAuth[id]; ok {
		return v.Verify(password)
	}
	return false, ErrNotExist
}
<commit_msg>fix: otp auth type<commit_after>package otp

import "sync"

const (
	TypeTOTP string = "totp"
	TypeHOTP        = "hotp"
)

func ValidType(t string) bool {
	return (t == TypeTOTP || t == TypeHOTP)
}

type Authenticator struct {
	mux     *sync.RWMutex
	Type    string
	OTPAuth map[string]OTP
}

func NewAuthenticator(_type string) (*Authenticator, error) {
	if !ValidType(_type) {
		return nil, ErrType
	}
	return &Authenticator{
		mux:     new(sync.RWMutex),
		Type:    _type,
		OTPAuth: make(map[string]OTP),
	}, nil
}

func (a *Authenticator) AddSecret(id, secret string) (OTP, error) {
	if len(id) == 0 {
		return nil, ErrID
	}
	a.mux.Lock()
	defer a.mux.Unlock()
	if v, ok := a.OTPAuth[id]; ok {
		return v, ErrExist
	}
	switch a.Type {
	case TypeTOTP:
		a.OTPAuth[id] = NewTOTP(3).SetSecret(secret)
	case TypeHOTP:
		a.OTPAuth[id] = NewHOTP(5).SetSecret(secret)
	default:
		return nil, ErrType
	}
	return a.OTPAuth[id], nil
}

func (a *Authenticator) GetSecret(id string) string {
	if v, ok := a.OTPAuth[id]; ok {
		return v.GetSecret()
	}
	return ""
}

func (a *Authenticator) ValidSecret(id string) bool {
	if v, ok := a.OTPAuth[id]; ok {
		return v.ValidSecret()
	}
	return false
}

func (a *Authenticator) URL(id, user, issuer string) string {
	if v, ok := a.OTPAuth[id]; ok {
		return v.URL(user, issuer)
	}
	return ""
}

func (a *Authenticator) Verify(id, password string) (bool, error) {
	if v, ok := a.OTPAuth[id]; ok {
		return v.Verify(password)
	}
	return false, ErrNotExist
}
<|endoftext|>


<commit_before>// Package azure implements a DNS provider for solving the DNS-01
// challenge using azure DNS.
// Azure doesn't like trailing dots on domain names, most of the acme code does.
package azure

import (
	"fmt"
	"os"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/dns"

	"strings"

	"github.com/Azure/go-autorest/autorest"
	"github.com/Azure/go-autorest/autorest/adal"
	"github.com/Azure/go-autorest/autorest/azure"
	"github.com/Azure/go-autorest/autorest/to"
	"github.com/xenolf/lego/acme"
)

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	clientId       string
	clientSecret   string
	subscriptionId string
	tenantId       string
	resourceGroup  string
}

// NewDNSProvider returns a DNSProvider instance configured for azure.
// Credentials must be passed in the environment variables: AZURE_CLIENT_ID,
// AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID
func NewDNSProvider() (*DNSProvider, error) {
	clientId := os.Getenv("AZURE_CLIENT_ID")
	clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
	subscriptionId := os.Getenv("AZURE_SUBSCRIPTION_ID")
	tenantId := os.Getenv("AZURE_TENANT_ID")
	resourceGroup := os.Getenv("AZURE_RESOURCE_GROUP")
	return NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for azure.
func NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup string) (*DNSProvider, error) {
	if clientId == "" || clientSecret == "" || subscriptionId == "" || tenantId == "" || resourceGroup == "" {
		return nil, fmt.Errorf("Azure configuration missing")
	}

	return &DNSProvider{
		clientId:       clientId,
		clientSecret:   clientSecret,
		subscriptionId: subscriptionId,
		tenantId:       tenantId,
		resourceGroup:  resourceGroup,
	}, nil
}

// Timeout returns the timeout and interval to use when checking for DNS
// propagation. Adjusting here to cope with spikes in propagation times.
func (c *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return 120 * time.Second, 2 * time.Second
}

// Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	rsc.Authorizer = autorest.NewBearerAuthorizer(spt)

	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rec := dns.RecordSet{
		Name: &relative,
		RecordSetProperties: &dns.RecordSetProperties{
			TTL:        to.Int64Ptr(60),
			TxtRecords: &[]dns.TxtRecord{dns.TxtRecord{Value: &[]string{value}}},
		},
	}
	_, err = rsc.CreateOrUpdate(c.resourceGroup, zone, relative, dns.TXT, rec, "", "")

	if err != nil {
		return err
	}

	return nil
}

// Returns the relative record to the domain
func toRelativeRecord(domain, zone string) string {
	return acme.UnFqdn(strings.TrimSuffix(domain, zone))
}

// CleanUp removes the TXT record matching the specified parameters
func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _, _ := acme.DNS01Record(domain, keyAuth)

	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	rsc.Authorizer = autorest.NewBearerAuthorizer(spt)
	_, err = rsc.Delete(c.resourceGroup, zone, relative, dns.TXT, "")
	if err != nil {
		return err
	}

	return nil
}

// Checks that azure has a zone for this domain name.
func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
	authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
	if err != nil {
		return "", err
	}

	// Now we want to to Azure and get the zone.
	dc := dns.NewZonesClient(c.subscriptionId)

	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	rsc.Authorizer = autorest.NewBearerAuthorizer(spt)

	zone, err := dc.Get(c.resourceGroup, acme.UnFqdn(authZone))

	if err != nil {
		return "", err
	}

	// zone.Name shouldn't have a trailing dot(.)
	return to.String(zone.Name), nil
}

// NewServicePrincipalTokenFromCredentials creates a new ServicePrincipalToken using values of the
// passed credentials map.
func (c *DNSProvider) newServicePrincipalTokenFromCredentials(scope string) (*adal.ServicePrincipalToken, error) {
	oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, c.tenantId)
	if err != nil {
		panic(err)
	}
	return adal.NewServicePrincipalToken(*oauthConfig, c.clientId, c.clientSecret, scope)
}
<commit_msg>added authorization to dns zones client (#428)<commit_after>// Package azure implements a DNS provider for solving the DNS-01
// challenge using azure DNS.
// Azure doesn't like trailing dots on domain names, most of the acme code does.
package azure

import (
	"fmt"
	"os"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/dns"

	"strings"

	"github.com/Azure/go-autorest/autorest"
	"github.com/Azure/go-autorest/autorest/adal"
	"github.com/Azure/go-autorest/autorest/azure"
	"github.com/Azure/go-autorest/autorest/to"
	"github.com/xenolf/lego/acme"
)

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	clientId       string
	clientSecret   string
	subscriptionId string
	tenantId       string
	resourceGroup  string
}

// NewDNSProvider returns a DNSProvider instance configured for azure.
// Credentials must be passed in the environment variables: AZURE_CLIENT_ID,
// AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID
func NewDNSProvider() (*DNSProvider, error) {
	clientId := os.Getenv("AZURE_CLIENT_ID")
	clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
	subscriptionId := os.Getenv("AZURE_SUBSCRIPTION_ID")
	tenantId := os.Getenv("AZURE_TENANT_ID")
	resourceGroup := os.Getenv("AZURE_RESOURCE_GROUP")
	return NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for azure.
func NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId, resourceGroup string) (*DNSProvider, error) {
	if clientId == "" || clientSecret == "" || subscriptionId == "" || tenantId == "" || resourceGroup == "" {
		return nil, fmt.Errorf("Azure configuration missing")
	}

	return &DNSProvider{
		clientId:       clientId,
		clientSecret:   clientSecret,
		subscriptionId: subscriptionId,
		tenantId:       tenantId,
		resourceGroup:  resourceGroup,
	}, nil
}

// Timeout returns the timeout and interval to use when checking for DNS
// propagation. Adjusting here to cope with spikes in propagation times.
func (c *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return 120 * time.Second, 2 * time.Second
}

// Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	rsc.Authorizer = autorest.NewBearerAuthorizer(spt)

	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rec := dns.RecordSet{
		Name: &relative,
		RecordSetProperties: &dns.RecordSetProperties{
			TTL:        to.Int64Ptr(60),
			TxtRecords: &[]dns.TxtRecord{dns.TxtRecord{Value: &[]string{value}}},
		},
	}
	_, err = rsc.CreateOrUpdate(c.resourceGroup, zone, relative, dns.TXT, rec, "", "")

	if err != nil {
		return err
	}

	return nil
}

// Returns the relative record to the domain
func toRelativeRecord(domain, zone string) string {
	return acme.UnFqdn(strings.TrimSuffix(domain, zone))
}

// CleanUp removes the TXT record matching the specified parameters
func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _, _ := acme.DNS01Record(domain, keyAuth)

	zone, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	relative := toRelativeRecord(fqdn, acme.ToFqdn(zone))
	rsc := dns.NewRecordSetsClient(c.subscriptionId)
	spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
	rsc.Authorizer = autorest.NewBearerAuthorizer(spt)
	_, err = rsc.Delete(c.resourceGroup, zone, relative, dns.TXT, "")
	if err != nil {
		return err
	}

	return nil
}

// Checks that azure has a zone for this domain name.
func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
	authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers)
	if err != nil {
		return "", err
	}

	// Now we want to to Azure and get the zone.
	spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)

	dc := dns.NewZonesClient(c.subscriptionId)
	dc.Authorizer = autorest.NewBearerAuthorizer(spt)

	zone, err := dc.Get(c.resourceGroup, acme.UnFqdn(authZone))

	if err != nil {
		return "", err
	}

	// zone.Name shouldn't have a trailing dot(.)
	return to.String(zone.Name), nil
}

// NewServicePrincipalTokenFromCredentials creates a new ServicePrincipalToken using values of the
// passed credentials map.
func (c *DNSProvider) newServicePrincipalTokenFromCredentials(scope string) (*adal.ServicePrincipalToken, error) {
	oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, c.tenantId)
	if err != nil {
		panic(err)
	}
	return adal.NewServicePrincipalToken(*oauthConfig, c.clientId, c.clientSecret, scope)
}
<|endoftext|>


<commit_before>package kontainerdrivermetadata

import (
	"fmt"
	"strings"

	mVersion "github.com/mcuadros/go-version"
	"github.com/rancher/rancher/pkg/settings"
	v3 "github.com/rancher/types/apis/management.cattle.io/v3"

	"github.com/sirupsen/logrus"

	"github.com/rancher/rancher/pkg/namespace"
	"github.com/rancher/rke/util"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func GetRKESystemImages(k8sVersion string, sysImageLister v3.RKEK8sSystemImageLister, sysImages v3.RKEK8sSystemImageInterface) (v3.RKESystemImages, error) {
	name := k8sVersion
	sysImage, err := sysImageLister.Get(namespace.GlobalNamespace, name)
	if err != nil {
		if !errors.IsNotFound(err) {
			return v3.RKESystemImages{}, err
		}
		sysImage, err = sysImages.GetNamespaced(namespace.GlobalNamespace, name, metav1.GetOptions{})
		if err != nil {
			return v3.RKESystemImages{}, err
		}
	}
	return sysImage.SystemImages, err
}

func GetRKEAddonTemplate(addonName string, addonLister v3.RKEAddonLister, addons v3.RKEAddonInterface) (string, error) {
	addon, err := addonLister.Get(namespace.GlobalNamespace, addonName)
	if err != nil {
		if !errors.IsNotFound(err) {
			return "", err
		}
		addon, err = addons.GetNamespaced(namespace.GlobalNamespace, addonName, metav1.GetOptions{})
		if err != nil {
			return "", err
		}
	}
	if addon.Labels[sendRKELabel] == "false" {
		return "", nil
	}
	return addon.Template, err
}

func getRKEServiceOption(name string, svcOptionLister v3.RKEK8sServiceOptionLister, svcOptions v3.RKEK8sServiceOptionInterface) (*v3.KubernetesServicesOptions, error) {
	var k8sSvcOption *v3.KubernetesServicesOptions
	svcOption, err := svcOptionLister.Get(namespace.GlobalNamespace, name)
	if err != nil {
		if !errors.IsNotFound(err) {
			return k8sSvcOption, err
		}
		svcOption, err = svcOptions.GetNamespaced(namespace.GlobalNamespace, name, metav1.GetOptions{})
		if err != nil {
			if !errors.IsNotFound(err) {
				return k8sSvcOption, err
			}
		}
	}
	if svcOption.Labels[sendRKELabel] == "false" {
		logrus.Infof("svcOption False %s", name)
		return k8sSvcOption, nil
	}
	return &svcOption.ServiceOptions, nil
}

func GetRKEK8sServiceOptions(k8sVersion string, svcOptionLister v3.RKEK8sServiceOptionLister,
	svcOptions v3.RKEK8sServiceOptionInterface, sysImageLister v3.RKEK8sSystemImageLister,
	sysImages v3.RKEK8sSystemImageInterface, osType OSType) (*v3.KubernetesServicesOptions, error) {

	var k8sSvcOption *v3.KubernetesServicesOptions
	sysImage, err := sysImageLister.Get(namespace.GlobalNamespace, k8sVersion)
	if err != nil {
		if !errors.IsNotFound(err) {
			logrus.Errorf("getSvcOptions: error finding system image for %s %v", k8sVersion, err)
			return k8sSvcOption, err
		}
		sysImage, err = sysImages.GetNamespaced(namespace.GlobalNamespace, k8sVersion, metav1.GetOptions{})
		if err != nil {
			logrus.Errorf("getSvcOptions: error finding system image for %s %v", k8sVersion, err)
			return k8sSvcOption, err
		}
	}
	key := svcOptionLinuxKey
	if osType == Windows {
		key = svcOptionWindowsKey
	}
	val, ok := sysImage.Labels[key]
	if !ok {
		return k8sSvcOption, fmt.Errorf("getSvcOptions: no service-option key present for %s", k8sVersion)
	}
	return getRKEServiceOption(val, svcOptionLister, svcOptions)
}

func GetK8sVersionInfo(
	rancherVersion string,
	rkeSysImages map[string]v3.RKESystemImages,
	linuxSvcOptions map[string]v3.KubernetesServicesOptions,
	windowsSvcOptions map[string]v3.KubernetesServicesOptions,
	rancherVersions map[string]v3.K8sVersionInfo,
) (linuxInfo, windowsInfo *VersionInfo) {

	linuxInfo = newVersionInfo()
	windowsInfo = newVersionInfo()

	maxVersionForMajorK8sVersion := map[string]string{}
	for k8sVersion := range rkeSysImages {
		if rancherVersionInfo, ok := rancherVersions[k8sVersion]; ok && toIgnoreForAllK8s(rancherVersionInfo, rancherVersion) {
			continue
		}
		majorVersion := util.GetTagMajorVersion(k8sVersion)
		if majorVersionInfo, ok := rancherVersions[majorVersion]; ok && toIgnoreForK8sCurrent(majorVersionInfo, rancherVersion) {
			continue
		}
		if curr, ok := maxVersionForMajorK8sVersion[majorVersion]; !ok || mVersion.Compare(k8sVersion, curr, ">") {
			maxVersionForMajorK8sVersion[majorVersion] = k8sVersion
		}
	}
	for majorVersion, k8sVersion := range maxVersionForMajorK8sVersion {
		sysImgs, exist := rkeSysImages[k8sVersion]
		if !exist {
			continue
		}
		// windows has been supported since v1.14,
		// the following logic would not find `< v1.14` service options
		if svcOptions, exist := windowsSvcOptions[majorVersion]; exist {
			// only keep the related images for windows
			windowsSysImgs := v3.RKESystemImages{
				NginxProxy:                sysImgs.NginxProxy,
				CertDownloader:            sysImgs.CertDownloader,
				KubernetesServicesSidecar: sysImgs.KubernetesServicesSidecar,
				Kubernetes:                sysImgs.Kubernetes,
				WindowsPodInfraContainer:  sysImgs.WindowsPodInfraContainer,
			}

			windowsInfo.RKESystemImages[k8sVersion] = windowsSysImgs
			windowsInfo.KubernetesServicesOptions[k8sVersion] = svcOptions
		}
		if svcOptions, exist := linuxSvcOptions[majorVersion]; exist {
			// clean the unrelated images for linux
			sysImgs.WindowsPodInfraContainer = ""

			linuxInfo.RKESystemImages[k8sVersion] = sysImgs
			linuxInfo.KubernetesServicesOptions[k8sVersion] = svcOptions
		}
	}

	return linuxInfo, windowsInfo
}

type VersionInfo struct {
	RKESystemImages           map[string]v3.RKESystemImages
	KubernetesServicesOptions map[string]v3.KubernetesServicesOptions
}

func newVersionInfo() *VersionInfo {
	return &VersionInfo{
		RKESystemImages:           map[string]v3.RKESystemImages{},
		KubernetesServicesOptions: map[string]v3.KubernetesServicesOptions{},
	}
}

func GetRancherVersion() string {
	rancherVersion := settings.ServerVersion.Get()
	if strings.HasPrefix(rancherVersion, "dev") || strings.HasPrefix(rancherVersion, "master") {
		return RancherVersionDev
	}
	if strings.HasPrefix(rancherVersion, "v") {
		return rancherVersion[1:]
	}
	return rancherVersion
}
<commit_msg>change log level for getRKEServiceOption<commit_after>package kontainerdrivermetadata

import (
	"fmt"
	"strings"

	mVersion "github.com/mcuadros/go-version"
	"github.com/rancher/rancher/pkg/settings"
	v3 "github.com/rancher/types/apis/management.cattle.io/v3"

	"github.com/sirupsen/logrus"

	"github.com/rancher/rancher/pkg/namespace"
	"github.com/rancher/rke/util"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func GetRKESystemImages(k8sVersion string, sysImageLister v3.RKEK8sSystemImageLister, sysImages v3.RKEK8sSystemImageInterface) (v3.RKESystemImages, error) {
	name := k8sVersion
	sysImage, err := sysImageLister.Get(namespace.GlobalNamespace, name)
	if err != nil {
		if !errors.IsNotFound(err) {
			return v3.RKESystemImages{}, err
		}
		sysImage, err = sysImages.GetNamespaced(namespace.GlobalNamespace, name, metav1.GetOptions{})
		if err != nil {
			return v3.RKESystemImages{}, err
		}
	}
	return sysImage.SystemImages, err
}

func GetRKEAddonTemplate(addonName string, addonLister v3.RKEAddonLister, addons v3.RKEAddonInterface) (string, error) {
	addon, err := addonLister.Get(namespace.GlobalNamespace, addonName)
	if err != nil {
		if !errors.IsNotFound(err) {
			return "", err
		}
		addon, err = addons.GetNamespaced(namespace.GlobalNamespace, addonName, metav1.GetOptions{})
		if err != nil {
			return "", err
		}
	}
	if addon.Labels[sendRKELabel] == "false" {
		return "", nil
	}
	return addon.Template, err
}

func getRKEServiceOption(name string, svcOptionLister v3.RKEK8sServiceOptionLister, svcOptions v3.RKEK8sServiceOptionInterface) (*v3.KubernetesServicesOptions, error) {
	var k8sSvcOption *v3.KubernetesServicesOptions
	svcOption, err := svcOptionLister.Get(namespace.GlobalNamespace, name)
	if err != nil {
		if !errors.IsNotFound(err) {
			return k8sSvcOption, err
		}
		svcOption, err = svcOptions.GetNamespaced(namespace.GlobalNamespace, name, metav1.GetOptions{})
		if err != nil {
			if !errors.IsNotFound(err) {
				return k8sSvcOption, err
			}
		}
	}
	if svcOption.Labels[sendRKELabel] == "false" {
		return k8sSvcOption, nil
	}
	logrus.Debugf("getRKEServiceOption: sending svcOption %s", name)
	return &svcOption.ServiceOptions, nil
}

func GetRKEK8sServiceOptions(k8sVersion string, svcOptionLister v3.RKEK8sServiceOptionLister,
	svcOptions v3.RKEK8sServiceOptionInterface, sysImageLister v3.RKEK8sSystemImageLister,
	sysImages v3.RKEK8sSystemImageInterface, osType OSType) (*v3.KubernetesServicesOptions, error) {

	var k8sSvcOption *v3.KubernetesServicesOptions
	sysImage, err := sysImageLister.Get(namespace.GlobalNamespace, k8sVersion)
	if err != nil {
		if !errors.IsNotFound(err) {
			logrus.Errorf("getSvcOptions: error finding system image for %s %v", k8sVersion, err)
			return k8sSvcOption, err
		}
		sysImage, err = sysImages.GetNamespaced(namespace.GlobalNamespace, k8sVersion, metav1.GetOptions{})
		if err != nil {
			logrus.Errorf("getSvcOptions: error finding system image for %s %v", k8sVersion, err)
			return k8sSvcOption, err
		}
	}
	key := svcOptionLinuxKey
	if osType == Windows {
		key = svcOptionWindowsKey
	}
	val, ok := sysImage.Labels[key]
	if !ok {
		return k8sSvcOption, fmt.Errorf("getSvcOptions: no service-option key present for %s", k8sVersion)
	}
	return getRKEServiceOption(val, svcOptionLister, svcOptions)
}

func GetK8sVersionInfo(
	rancherVersion string,
	rkeSysImages map[string]v3.RKESystemImages,
	linuxSvcOptions map[string]v3.KubernetesServicesOptions,
	windowsSvcOptions map[string]v3.KubernetesServicesOptions,
	rancherVersions map[string]v3.K8sVersionInfo,
) (linuxInfo, windowsInfo *VersionInfo) {

	linuxInfo = newVersionInfo()
	windowsInfo = newVersionInfo()

	maxVersionForMajorK8sVersion := map[string]string{}
	for k8sVersion := range rkeSysImages {
		if rancherVersionInfo, ok := rancherVersions[k8sVersion]; ok && toIgnoreForAllK8s(rancherVersionInfo, rancherVersion) {
			continue
		}
		majorVersion := util.GetTagMajorVersion(k8sVersion)
		if majorVersionInfo, ok := rancherVersions[majorVersion]; ok && toIgnoreForK8sCurrent(majorVersionInfo, rancherVersion) {
			continue
		}
		if curr, ok := maxVersionForMajorK8sVersion[majorVersion]; !ok || mVersion.Compare(k8sVersion, curr, ">") {
			maxVersionForMajorK8sVersion[majorVersion] = k8sVersion
		}
	}
	for majorVersion, k8sVersion := range maxVersionForMajorK8sVersion {
		sysImgs, exist := rkeSysImages[k8sVersion]
		if !exist {
			continue
		}
		// windows has been supported since v1.14,
		// the following logic would not find `< v1.14` service options
		if svcOptions, exist := windowsSvcOptions[majorVersion]; exist {
			// only keep the related images for windows
			windowsSysImgs := v3.RKESystemImages{
				NginxProxy:                sysImgs.NginxProxy,
				CertDownloader:            sysImgs.CertDownloader,
				KubernetesServicesSidecar: sysImgs.KubernetesServicesSidecar,
				Kubernetes:                sysImgs.Kubernetes,
				WindowsPodInfraContainer:  sysImgs.WindowsPodInfraContainer,
			}

			windowsInfo.RKESystemImages[k8sVersion] = windowsSysImgs
			windowsInfo.KubernetesServicesOptions[k8sVersion] = svcOptions
		}
		if svcOptions, exist := linuxSvcOptions[majorVersion]; exist {
			// clean the unrelated images for linux
			sysImgs.WindowsPodInfraContainer = ""

			linuxInfo.RKESystemImages[k8sVersion] = sysImgs
			linuxInfo.KubernetesServicesOptions[k8sVersion] = svcOptions
		}
	}

	return linuxInfo, windowsInfo
}

type VersionInfo struct {
	RKESystemImages           map[string]v3.RKESystemImages
	KubernetesServicesOptions map[string]v3.KubernetesServicesOptions
}

func newVersionInfo() *VersionInfo {
	return &VersionInfo{
		RKESystemImages:           map[string]v3.RKESystemImages{},
		KubernetesServicesOptions: map[string]v3.KubernetesServicesOptions{},
	}
}

func GetRancherVersion() string {
	rancherVersion := settings.ServerVersion.Get()
	if strings.HasPrefix(rancherVersion, "dev") || strings.HasPrefix(rancherVersion, "master") {
		return RancherVersionDev
	}
	if strings.HasPrefix(rancherVersion, "v") {
		return rancherVersion[1:]
	}
	return rancherVersion
}
<|endoftext|>