<commit_before>/*
Copyright IBM Corp. 2017 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 main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"text/template"

	"gopkg.in/yaml.v2"

	"gopkg.in/alecthomas/kingpin.v2"

	"bytes"
	"io/ioutil"

	"github.com/hyperledger/fabric/common/tools/cryptogen/ca"
	"github.com/hyperledger/fabric/common/tools/cryptogen/msp"
)

const (
	userBaseName            = "User"
	adminBaseName           = "Admin"
	defaultHostnameTemplate = "{{.Prefix}}{{.Index}}"
	defaultCNTemplate       = "{{.Hostname}}.{{.Domain}}"
)

type HostnameData struct {
	Prefix string
	Index  int
	Domain string
}

type CommonNameData struct {
	Hostname string
	Domain   string
}

type NodeTemplate struct {
	Count    int    `yaml:"Count"`
	Start    int    `yaml:"Start"`
	Hostname string `yaml:"Hostname"`
}

type NodeSpec struct {
	Hostname     string   `yaml:"Hostname"`
	AltHostnames []string `yaml:"AltHostnames"`
	CommonName   string   `yaml:"CommonName"`
}

type UsersSpec struct {
	Count int `yaml:"Count"`
}

type OrgSpec struct {
	Name     string       `yaml:"Name"`
	Domain   string       `yaml:"Domain"`
	Template NodeTemplate `yaml:"Template"`
	Specs    []NodeSpec   `yaml:"Specs"`
	Users    UsersSpec    `yaml:"Users"`
}

type Config struct {
	OrdererOrgs []OrgSpec `yaml:"OrdererOrgs"`
	PeerOrgs    []OrgSpec `yaml:"PeerOrgs"`
}

var defaultConfig = `
# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
  # ---------------------------------------------------------------------------
  # Orderer
  # ---------------------------------------------------------------------------
  - Name: Orderer
    Domain: example.com

    # ---------------------------------------------------------------------------
    # "Specs" - See PeerOrgs below for complete description
    # ---------------------------------------------------------------------------
    Specs:
      - Hostname: orderer

# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1
  # ---------------------------------------------------------------------------
  - Name: Org1
    Domain: org1.example.com

    # ---------------------------------------------------------------------------
    # "Specs"
    # ---------------------------------------------------------------------------
    # Uncomment this section to enable the explicit definition of hosts in your
    # configuration.  Most users will want to use Template, below
    #
    # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
    #   - Hostname:   (Required) The desired hostname, sans the domain.
    #   - CommonName: (Optional) Specifies the template or explicit override for
    #                 the CN.  By default, this is the template:
    #
    #                              "{{.Hostname}}.{{.Domain}}"
    #
    #                 which obtains its values from the Spec.Hostname and
    #                 Org.Domain, respectively.
    # ---------------------------------------------------------------------------
    # Specs:
    #   - Hostname: foo # implicitly "foo.org1.example.com"
    #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
    #   - Hostname: bar
    #   - Hostname: baz

    # ---------------------------------------------------------------------------
    # "Template"
    # ---------------------------------------------------------------------------
    # Allows for the definition of 1 or more hosts that are created sequentially
    # from a template. By default, this looks like "peer%d" from 0 to Count-1.
    # You may override the number of nodes (Count), the starting index (Start)
    # or the template used to construct the name (Hostname).
    #
    # Note: Template and Specs are not mutually exclusive.  You may define both
    # sections and the aggregate nodes will be created for you.  Take care with
    # name collisions
    # ---------------------------------------------------------------------------
    Template:
      Count: 1
      # Start: 5
      # Hostname: {{.Prefix}}{{.Index}} # default

    # ---------------------------------------------------------------------------
    # "Users"
    # ---------------------------------------------------------------------------
    # Count: The number of user accounts _in addition_ to Admin
    # ---------------------------------------------------------------------------
    Users:
      Count: 1

  # ---------------------------------------------------------------------------
  # Org2: See "Org1" for full specification
  # ---------------------------------------------------------------------------
  - Name: Org2
    Domain: org2.example.com
    Template:
      Count: 1
    Users:
      Count: 1
`

//command line flags
var (
	app = kingpin.New("cryptogen", "Utility for generating Hyperledger Fabric key material")

	gen        = app.Command("generate", "Generate key material")
	outputDir  = gen.Flag("output", "The output directory in which to place artifacts").Default("crypto-config").String()
	configFile = gen.Flag("config", "The configuration template to use").File()

	showtemplate = app.Command("showtemplate", "Show the default configuration template")
)

func main() {
	kingpin.Version("0.0.1")
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {

	// "generate" command
	case gen.FullCommand():
		generate()

	// "showtemplate" command
	case showtemplate.FullCommand():
		fmt.Print(defaultConfig)
		os.Exit(0)
	}

}

func getConfig() (*Config, error) {
	var configData string

	if *configFile != nil {
		data, err := ioutil.ReadAll(*configFile)
		if err != nil {
			return nil, fmt.Errorf("Error reading configuration: %s", err)
		}

		configData = string(data)
	} else {
		configData = defaultConfig
	}

	config := &Config{}
	err := yaml.Unmarshal([]byte(configData), &config)
	if err != nil {
		return nil, fmt.Errorf("Error Unmarshaling YAML: %s", err)
	}

	return config, nil
}

func generate() {

	config, err := getConfig()
	if err != nil {
		fmt.Printf("Error reading config: %s", err)
		os.Exit(-1)
	}

	for _, orgSpec := range config.PeerOrgs {
		err = generateNodeSpec(&orgSpec, "peer")
		if err != nil {
			fmt.Printf("Error processing peer configuration: %s", err)
			os.Exit(-1)
		}
		generatePeerOrg(*outputDir, orgSpec)
	}

	for _, orgSpec := range config.OrdererOrgs {
		generateNodeSpec(&orgSpec, "orderer")
		if err != nil {
			fmt.Printf("Error processing orderer configuration: %s", err)
			os.Exit(-1)
		}
		generateOrdererOrg(*outputDir, orgSpec)
	}
}

func parseTemplate(input, defaultInput string, data interface{}) (string, error) {

	// Use the default if the input is an empty string
	if len(input) == 0 {
		input = defaultInput
	}

	t, err := template.New("parse").Parse(input)
	if err != nil {
		return "", fmt.Errorf("Error parsing template: %s", err)
	}

	output := new(bytes.Buffer)
	err = t.Execute(output, data)
	if err != nil {
		return "", fmt.Errorf("Error executing template: %s", err)
	}

	return output.String(), nil
}

func generateNodeSpec(orgSpec *OrgSpec, prefix string) error {
	// First process all of our templated nodes
	for i := 0; i < orgSpec.Template.Count; i++ {
		data := HostnameData{
			Prefix: prefix,
			Index:  i + orgSpec.Template.Start,
			Domain: orgSpec.Domain,
		}

		hostname, err := parseTemplate(orgSpec.Template.Hostname, defaultHostnameTemplate, data)
		if err != nil {
			return err
		}

		spec := NodeSpec{Hostname: hostname}
		orgSpec.Specs = append(orgSpec.Specs, spec)
	}

	// And finally touch up all specs to add the domain
	for idx, spec := range orgSpec.Specs {
		data := CommonNameData{
			Hostname: spec.Hostname,
			Domain:   orgSpec.Domain,
		}

		finalCN, err := parseTemplate(spec.CommonName, defaultCNTemplate, data)
		if err != nil {
			return err
		}

		orgSpec.Specs[idx].CommonName = finalCN
	}

	return nil
}

func generatePeerOrg(baseDir string, orgSpec OrgSpec) {

	orgName := orgSpec.Domain

	fmt.Println(orgName)
	// generate CA
	orgDir := filepath.Join(baseDir, "peerOrganizations", orgName)
	caDir := filepath.Join(orgDir, "ca")
	mspDir := filepath.Join(orgDir, "msp")
	peersDir := filepath.Join(orgDir, "peers")
	usersDir := filepath.Join(orgDir, "users")
	adminCertsDir := filepath.Join(mspDir, "admincerts")
	rootCA, err := ca.NewCA(caDir, orgName)
	if err != nil {
		fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}
	err = msp.GenerateVerifyingMSP(mspDir, rootCA)
	if err != nil {
		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}

	peerNames := []string{}
	for _, spec := range orgSpec.Specs {
		peerNames = append(peerNames, spec.CommonName)
	}
	generateNodes(peersDir, peerNames, rootCA)

	// TODO: add ability to specify usernames
	usernames := []string{}
	for j := 1; j <= orgSpec.Users.Count; j++ {
		usernames = append(usernames, fmt.Sprintf("%s%d@%s",
			userBaseName, j, orgName))
	}
	// add an admin user
	adminUserName := fmt.Sprintf("%s@%s",
		adminBaseName, orgName)

	usernames = append(usernames, adminUserName)
	generateNodes(usersDir, usernames, rootCA)

	// copy the admin cert to the org's MSP admincerts
	err = copyAdminCert(usersDir, adminCertsDir, adminUserName)
	if err != nil {
		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
			orgName, err)
		os.Exit(1)
	}
}

func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error {
	// delete the contents of admincerts
	err := os.RemoveAll(adminCertsDir)
	if err != nil {
		return err
	}
	// recreate the admincerts directory
	err = os.MkdirAll(adminCertsDir, 0755)
	if err != nil {
		return err
	}
	err = copyFile(filepath.Join(usersDir, adminUserName, "signcerts",
		adminUserName+"-cert.pem"), filepath.Join(adminCertsDir,
		adminUserName+"-cert.pem"))
	if err != nil {
		return err
	}
	return nil

}

func generateNodes(baseDir string, nodeNames []string, rootCA *ca.CA) {

	for _, nodeName := range nodeNames {
		nodeDir := filepath.Join(baseDir, nodeName)
		err := msp.GenerateLocalMSP(nodeDir, nodeName, rootCA)
		if err != nil {
			fmt.Printf("Error generating local MSP for %s:\n%v\n", nodeName, err)
			os.Exit(1)
		}
	}

}

func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {

	orgName := orgSpec.Domain

	// generate CA
	orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)
	caDir := filepath.Join(orgDir, "ca")
	mspDir := filepath.Join(orgDir, "msp")
	orderersDir := filepath.Join(orgDir, "orderers")
	usersDir := filepath.Join(orgDir, "users")
	adminCertsDir := filepath.Join(mspDir, "admincerts")
	rootCA, err := ca.NewCA(caDir, orgName)
	if err != nil {
		fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}
	err = msp.GenerateVerifyingMSP(mspDir, rootCA)
	if err != nil {
		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}

	// TODO: add ability to specify orderer names
	// for name just use default base name
	ordererNames := []string{}
	for _, spec := range orgSpec.Specs {
		ordererNames = append(ordererNames, spec.CommonName)
	}
	generateNodes(orderersDir, ordererNames, rootCA)

	adminUserName := fmt.Sprintf("%s@%s",
		adminBaseName, orgName)

	// generate an admin for the orderer org
	usernames := []string{}
	// add an admin user
	usernames = append(usernames, adminUserName)
	generateNodes(usersDir, usernames, rootCA)

	// copy the admin cert to the org's MSP admincerts
	err = copyAdminCert(usersDir, adminCertsDir, adminUserName)
	if err != nil {
		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
			orgName, err)
		os.Exit(1)
	}

}

func copyFile(src, dst string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = io.Copy(out, in)
	cerr := out.Close()
	if err != nil {
		return err
	}
	return cerr
}
<commit_msg>[FAB-3306] cryptogen - copy admin certs to node MSPs<commit_after>/*
Copyright IBM Corp. 2017 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 main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"text/template"

	"gopkg.in/yaml.v2"

	"gopkg.in/alecthomas/kingpin.v2"

	"bytes"
	"io/ioutil"

	"github.com/hyperledger/fabric/common/tools/cryptogen/ca"
	"github.com/hyperledger/fabric/common/tools/cryptogen/msp"
)

const (
	userBaseName            = "User"
	adminBaseName           = "Admin"
	defaultHostnameTemplate = "{{.Prefix}}{{.Index}}"
	defaultCNTemplate       = "{{.Hostname}}.{{.Domain}}"
)

type HostnameData struct {
	Prefix string
	Index  int
	Domain string
}

type CommonNameData struct {
	Hostname string
	Domain   string
}

type NodeTemplate struct {
	Count    int    `yaml:"Count"`
	Start    int    `yaml:"Start"`
	Hostname string `yaml:"Hostname"`
}

type NodeSpec struct {
	Hostname     string   `yaml:"Hostname"`
	AltHostnames []string `yaml:"AltHostnames"`
	CommonName   string   `yaml:"CommonName"`
}

type UsersSpec struct {
	Count int `yaml:"Count"`
}

type OrgSpec struct {
	Name     string       `yaml:"Name"`
	Domain   string       `yaml:"Domain"`
	Template NodeTemplate `yaml:"Template"`
	Specs    []NodeSpec   `yaml:"Specs"`
	Users    UsersSpec    `yaml:"Users"`
}

type Config struct {
	OrdererOrgs []OrgSpec `yaml:"OrdererOrgs"`
	PeerOrgs    []OrgSpec `yaml:"PeerOrgs"`
}

var defaultConfig = `
# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
  # ---------------------------------------------------------------------------
  # Orderer
  # ---------------------------------------------------------------------------
  - Name: Orderer
    Domain: example.com

    # ---------------------------------------------------------------------------
    # "Specs" - See PeerOrgs below for complete description
    # ---------------------------------------------------------------------------
    Specs:
      - Hostname: orderer

# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1
  # ---------------------------------------------------------------------------
  - Name: Org1
    Domain: org1.example.com

    # ---------------------------------------------------------------------------
    # "Specs"
    # ---------------------------------------------------------------------------
    # Uncomment this section to enable the explicit definition of hosts in your
    # configuration.  Most users will want to use Template, below
    #
    # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
    #   - Hostname:   (Required) The desired hostname, sans the domain.
    #   - CommonName: (Optional) Specifies the template or explicit override for
    #                 the CN.  By default, this is the template:
    #
    #                              "{{.Hostname}}.{{.Domain}}"
    #
    #                 which obtains its values from the Spec.Hostname and
    #                 Org.Domain, respectively.
    # ---------------------------------------------------------------------------
    # Specs:
    #   - Hostname: foo # implicitly "foo.org1.example.com"
    #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
    #   - Hostname: bar
    #   - Hostname: baz

    # ---------------------------------------------------------------------------
    # "Template"
    # ---------------------------------------------------------------------------
    # Allows for the definition of 1 or more hosts that are created sequentially
    # from a template. By default, this looks like "peer%d" from 0 to Count-1.
    # You may override the number of nodes (Count), the starting index (Start)
    # or the template used to construct the name (Hostname).
    #
    # Note: Template and Specs are not mutually exclusive.  You may define both
    # sections and the aggregate nodes will be created for you.  Take care with
    # name collisions
    # ---------------------------------------------------------------------------
    Template:
      Count: 1
      # Start: 5
      # Hostname: {{.Prefix}}{{.Index}} # default

    # ---------------------------------------------------------------------------
    # "Users"
    # ---------------------------------------------------------------------------
    # Count: The number of user accounts _in addition_ to Admin
    # ---------------------------------------------------------------------------
    Users:
      Count: 1

  # ---------------------------------------------------------------------------
  # Org2: See "Org1" for full specification
  # ---------------------------------------------------------------------------
  - Name: Org2
    Domain: org2.example.com
    Template:
      Count: 1
    Users:
      Count: 1
`

//command line flags
var (
	app = kingpin.New("cryptogen", "Utility for generating Hyperledger Fabric key material")

	gen        = app.Command("generate", "Generate key material")
	outputDir  = gen.Flag("output", "The output directory in which to place artifacts").Default("crypto-config").String()
	configFile = gen.Flag("config", "The configuration template to use").File()

	showtemplate = app.Command("showtemplate", "Show the default configuration template")
)

func main() {
	kingpin.Version("0.0.1")
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {

	// "generate" command
	case gen.FullCommand():
		generate()

	// "showtemplate" command
	case showtemplate.FullCommand():
		fmt.Print(defaultConfig)
		os.Exit(0)
	}

}

func getConfig() (*Config, error) {
	var configData string

	if *configFile != nil {
		data, err := ioutil.ReadAll(*configFile)
		if err != nil {
			return nil, fmt.Errorf("Error reading configuration: %s", err)
		}

		configData = string(data)
	} else {
		configData = defaultConfig
	}

	config := &Config{}
	err := yaml.Unmarshal([]byte(configData), &config)
	if err != nil {
		return nil, fmt.Errorf("Error Unmarshaling YAML: %s", err)
	}

	return config, nil
}

func generate() {

	config, err := getConfig()
	if err != nil {
		fmt.Printf("Error reading config: %s", err)
		os.Exit(-1)
	}

	for _, orgSpec := range config.PeerOrgs {
		err = generateNodeSpec(&orgSpec, "peer")
		if err != nil {
			fmt.Printf("Error processing peer configuration: %s", err)
			os.Exit(-1)
		}
		generatePeerOrg(*outputDir, orgSpec)
	}

	for _, orgSpec := range config.OrdererOrgs {
		generateNodeSpec(&orgSpec, "orderer")
		if err != nil {
			fmt.Printf("Error processing orderer configuration: %s", err)
			os.Exit(-1)
		}
		generateOrdererOrg(*outputDir, orgSpec)
	}
}

func parseTemplate(input, defaultInput string, data interface{}) (string, error) {

	// Use the default if the input is an empty string
	if len(input) == 0 {
		input = defaultInput
	}

	t, err := template.New("parse").Parse(input)
	if err != nil {
		return "", fmt.Errorf("Error parsing template: %s", err)
	}

	output := new(bytes.Buffer)
	err = t.Execute(output, data)
	if err != nil {
		return "", fmt.Errorf("Error executing template: %s", err)
	}

	return output.String(), nil
}

func generateNodeSpec(orgSpec *OrgSpec, prefix string) error {
	// First process all of our templated nodes
	for i := 0; i < orgSpec.Template.Count; i++ {
		data := HostnameData{
			Prefix: prefix,
			Index:  i + orgSpec.Template.Start,
			Domain: orgSpec.Domain,
		}

		hostname, err := parseTemplate(orgSpec.Template.Hostname, defaultHostnameTemplate, data)
		if err != nil {
			return err
		}

		spec := NodeSpec{Hostname: hostname}
		orgSpec.Specs = append(orgSpec.Specs, spec)
	}

	// And finally touch up all specs to add the domain
	for idx, spec := range orgSpec.Specs {
		data := CommonNameData{
			Hostname: spec.Hostname,
			Domain:   orgSpec.Domain,
		}

		finalCN, err := parseTemplate(spec.CommonName, defaultCNTemplate, data)
		if err != nil {
			return err
		}

		orgSpec.Specs[idx].CommonName = finalCN
	}

	return nil
}

func generatePeerOrg(baseDir string, orgSpec OrgSpec) {

	orgName := orgSpec.Domain

	fmt.Println(orgName)
	// generate CA
	orgDir := filepath.Join(baseDir, "peerOrganizations", orgName)
	caDir := filepath.Join(orgDir, "ca")
	mspDir := filepath.Join(orgDir, "msp")
	peersDir := filepath.Join(orgDir, "peers")
	usersDir := filepath.Join(orgDir, "users")
	adminCertsDir := filepath.Join(mspDir, "admincerts")
	rootCA, err := ca.NewCA(caDir, orgName)
	if err != nil {
		fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}
	err = msp.GenerateVerifyingMSP(mspDir, rootCA)
	if err != nil {
		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}

	peerNames := []string{}
	for _, spec := range orgSpec.Specs {
		peerNames = append(peerNames, spec.CommonName)
	}
	generateNodes(peersDir, peerNames, rootCA)

	// TODO: add ability to specify usernames
	usernames := []string{}
	for j := 1; j <= orgSpec.Users.Count; j++ {
		usernames = append(usernames, fmt.Sprintf("%s%d@%s",
			userBaseName, j, orgName))
	}
	// add an admin user
	adminUserName := fmt.Sprintf("%s@%s",
		adminBaseName, orgName)

	usernames = append(usernames, adminUserName)
	generateNodes(usersDir, usernames, rootCA)

	// copy the admin cert to the org's MSP admincerts
	err = copyAdminCert(usersDir, adminCertsDir, adminUserName)
	if err != nil {
		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
			orgName, err)
		os.Exit(1)
	}

	// copy the admin cert to each of the org's peer's MSP admincerts
	for _, peerName := range peerNames {
		err = copyAdminCert(usersDir, filepath.Join(peersDir, peerName,
			"admincerts"), adminUserName)
		if err != nil {
			fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n",
				orgName, peerName, err)
			os.Exit(1)
		}
	}
}

func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error {
	// delete the contents of admincerts
	err := os.RemoveAll(adminCertsDir)
	if err != nil {
		return err
	}
	// recreate the admincerts directory
	err = os.MkdirAll(adminCertsDir, 0755)
	if err != nil {
		return err
	}
	err = copyFile(filepath.Join(usersDir, adminUserName, "signcerts",
		adminUserName+"-cert.pem"), filepath.Join(adminCertsDir,
		adminUserName+"-cert.pem"))
	if err != nil {
		return err
	}
	return nil

}

func generateNodes(baseDir string, nodeNames []string, rootCA *ca.CA) {

	for _, nodeName := range nodeNames {
		nodeDir := filepath.Join(baseDir, nodeName)
		err := msp.GenerateLocalMSP(nodeDir, nodeName, rootCA)
		if err != nil {
			fmt.Printf("Error generating local MSP for %s:\n%v\n", nodeName, err)
			os.Exit(1)
		}
	}

}

func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {

	orgName := orgSpec.Domain

	// generate CA
	orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)
	caDir := filepath.Join(orgDir, "ca")
	mspDir := filepath.Join(orgDir, "msp")
	orderersDir := filepath.Join(orgDir, "orderers")
	usersDir := filepath.Join(orgDir, "users")
	adminCertsDir := filepath.Join(mspDir, "admincerts")
	rootCA, err := ca.NewCA(caDir, orgName)
	if err != nil {
		fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}
	err = msp.GenerateVerifyingMSP(mspDir, rootCA)
	if err != nil {
		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
		os.Exit(1)
	}

	// TODO: add ability to specify orderer names
	// for name just use default base name
	ordererNames := []string{}
	for _, spec := range orgSpec.Specs {
		ordererNames = append(ordererNames, spec.CommonName)
	}
	generateNodes(orderersDir, ordererNames, rootCA)

	adminUserName := fmt.Sprintf("%s@%s",
		adminBaseName, orgName)

	// generate an admin for the orderer org
	usernames := []string{}
	// add an admin user
	usernames = append(usernames, adminUserName)
	generateNodes(usersDir, usernames, rootCA)

	// copy the admin cert to the org's MSP admincerts
	err = copyAdminCert(usersDir, adminCertsDir, adminUserName)
	if err != nil {
		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
			orgName, err)
		os.Exit(1)
	}

	// copy the admin cert to each of the org's orderers's MSP admincerts
	for _, ordererName := range ordererNames {
		err = copyAdminCert(usersDir, filepath.Join(orderersDir, ordererName,
			"admincerts"), adminUserName)
		if err != nil {
			fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n",
				orgName, ordererName, err)
			os.Exit(1)
		}
	}

}

func copyFile(src, dst string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()
	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	_, err = io.Copy(out, in)
	cerr := out.Close()
	if err != nil {
		return err
	}
	return cerr
}
<|endoftext|>


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

package compilergraph

import (
	"github.com/serulian/compiler/compilerutil"

	"github.com/cayleygraph/cayley/quad"
)

// nodeFilter is a filtering function for a graph query.
type nodeFilter func(q GraphQuery) Query

// FilteredQuery is a type which wraps a GraphQuery and executes additional filtering.
type FilteredQuery struct {
	query  GraphQuery
	filter nodeFilter
}

// BuildNodeIterator returns an iterator over the filtered query.
func (fq FilteredQuery) BuildNodeIterator(predicates ...Predicate) NodeIterator {
	// Build an iterator to collect the IDs matching the inner query.
	it := fq.query.BuildNodeIterator()
	if !it.Next() {
		return EmptyIterator{}
	}

	// Note that it.Next() is called in the check above, so we call it at the
	// *end* of each of the loop iterations. This ensure that we don't allocate
	// the slice unless absolutely necessary.
	var nodeIds = make([]GraphNodeId, 0, 16)
	for {
		nodeIds = append(nodeIds, it.Node().NodeId)
		if !it.Next() {
			break
		}
	}

	// Otherwise, create a new query starting from the nodes found and send it
	// to the filtering function.
	fullKindPredicate := fq.query.layer.getPrefixedPredicate(fq.query.layer.nodeKindPredicate)
	markID := compilerutil.NewUniqueId()
	subQuery := fq.query.layer.StartQueryFromNodes(nodeIds...).mark(markID).save(fullKindPredicate, markID+"-kind")
	filteredQuery := fq.filter(subQuery)

	// Build an iterator over the filtered query.
	fit := filteredQuery.BuildNodeIterator()
	if !fit.Next() {
		return EmptyIterator{}
	}

	// Collect the filtered nodes.
	var filtered = make([]GraphNode, 0, len(nodeIds))
	for {
		nodeID := valueToNodeId(fit.getMarked(markID))
		kindValue := fit.getMarked(markID + "-kind")
		filtered = append(filtered, GraphNode{nodeID, kindValue, fq.query.layer})
		if !fit.Next() {
			break
		}
	}

	return &nodeReturnIterator{fq.query.layer, filtered, -1}
}

// HasWhere starts a new client query.
func (fq FilteredQuery) HasWhere(predicate Predicate, op clientQueryOperation, value interface{}) Query {
	return getClientQuery(fq.query.layer, fq, predicate, op, value)
}

// TryGetNode executes the query and returns the single node found or false. If there is
// more than a single node as a result of the query, the first node is returned.
func (fq FilteredQuery) TryGetNode() (GraphNode, bool) {
	return tryGetNode(fq.BuildNodeIterator())
}

// nodeReturnIterator is an iterator that just returns a preset list of nodes.
type nodeReturnIterator struct {
	layer    *GraphLayer
	filtered []GraphNode
	index    int
}

func (nri *nodeReturnIterator) Next() bool {
	nri.index++
	return nri.index < len(nri.filtered)
}

func (nri *nodeReturnIterator) Node() GraphNode {
	return nri.filtered[nri.index]
}

func (nri *nodeReturnIterator) GetPredicate(predicate Predicate) GraphValue {
	// Note: This is a slightly slower path, but most filtered queries don't need extra
	// predicates.
	return nri.Node().GetValue(predicate)
}

func (nri *nodeReturnIterator) TaggedValue(predicate Predicate, example TaggedValue) interface{} {
	return nri.Node().GetTagged(predicate, example)
}

func (nri *nodeReturnIterator) getRequestedPredicate(predicate Predicate) quad.Value {
	panic("Should not be called")
}

func (nri *nodeReturnIterator) getMarked(name string) quad.Value {
	panic("Should not be called")
}
<commit_msg>Switch to faster ID generation<commit_after>// Copyright 2015 The Serulian Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package compilergraph

import (
	"github.com/cayleygraph/cayley/quad"
	uuid "github.com/satori/go.uuid"
)

// nodeFilter is a filtering function for a graph query.
type nodeFilter func(q GraphQuery) Query

// FilteredQuery is a type which wraps a GraphQuery and executes additional filtering.
type FilteredQuery struct {
	query  GraphQuery
	filter nodeFilter
}

// BuildNodeIterator returns an iterator over the filtered query.
func (fq FilteredQuery) BuildNodeIterator(predicates ...Predicate) NodeIterator {
	// Build an iterator to collect the IDs matching the inner query.
	it := fq.query.BuildNodeIterator()
	if !it.Next() {
		return EmptyIterator{}
	}

	// Note that it.Next() is called in the check above, so we call it at the
	// *end* of each of the loop iterations. This ensure that we don't allocate
	// the slice unless absolutely necessary.
	var nodeIds = make([]GraphNodeId, 0, 16)
	for {
		nodeIds = append(nodeIds, it.Node().NodeId)
		if !it.Next() {
			break
		}
	}

	// Otherwise, create a new query starting from the nodes found and send it
	// to the filtering function.
	fullKindPredicate := fq.query.layer.getPrefixedPredicate(fq.query.layer.nodeKindPredicate)
	markID := uuid.NewV1().String()
	subQuery := fq.query.layer.StartQueryFromNodes(nodeIds...).mark(markID).save(fullKindPredicate, markID+"-kind")
	filteredQuery := fq.filter(subQuery)

	// Build an iterator over the filtered query.
	fit := filteredQuery.BuildNodeIterator()
	if !fit.Next() {
		return EmptyIterator{}
	}

	// Collect the filtered nodes.
	var filtered = make([]GraphNode, 0, len(nodeIds))
	for {
		nodeID := valueToNodeId(fit.getMarked(markID))
		kindValue := fit.getMarked(markID + "-kind")
		filtered = append(filtered, GraphNode{nodeID, kindValue, fq.query.layer})
		if !fit.Next() {
			break
		}
	}

	return &nodeReturnIterator{fq.query.layer, filtered, -1}
}

// HasWhere starts a new client query.
func (fq FilteredQuery) HasWhere(predicate Predicate, op clientQueryOperation, value interface{}) Query {
	return getClientQuery(fq.query.layer, fq, predicate, op, value)
}

// TryGetNode executes the query and returns the single node found or false. If there is
// more than a single node as a result of the query, the first node is returned.
func (fq FilteredQuery) TryGetNode() (GraphNode, bool) {
	return tryGetNode(fq.BuildNodeIterator())
}

// nodeReturnIterator is an iterator that just returns a preset list of nodes.
type nodeReturnIterator struct {
	layer    *GraphLayer
	filtered []GraphNode
	index    int
}

func (nri *nodeReturnIterator) Next() bool {
	nri.index++
	return nri.index < len(nri.filtered)
}

func (nri *nodeReturnIterator) Node() GraphNode {
	return nri.filtered[nri.index]
}

func (nri *nodeReturnIterator) GetPredicate(predicate Predicate) GraphValue {
	// Note: This is a slightly slower path, but most filtered queries don't need extra
	// predicates.
	return nri.Node().GetValue(predicate)
}

func (nri *nodeReturnIterator) TaggedValue(predicate Predicate, example TaggedValue) interface{} {
	return nri.Node().GetTagged(predicate, example)
}

func (nri *nodeReturnIterator) getRequestedPredicate(predicate Predicate) quad.Value {
	panic("Should not be called")
}

func (nri *nodeReturnIterator) getMarked(name string) quad.Value {
	panic("Should not be called")
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package crdregistration

import (
	"fmt"
	"time"

	"k8s.io/klog/v2"

	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	crdinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1"
	crdlisters "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
	v1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
	"k8s.io/kube-aggregator/pkg/apiserver"
)

// AutoAPIServiceRegistration is an interface which callers can re-declare locally and properly cast to for
// adding and removing APIServices
type AutoAPIServiceRegistration interface {
	// AddAPIServiceToSync adds an API service to auto-register.
	AddAPIServiceToSync(in *v1.APIService)
	// RemoveAPIServiceToSync removes an API service to auto-register.
	RemoveAPIServiceToSync(name string)
}

type crdRegistrationController struct {
	crdLister crdlisters.CustomResourceDefinitionLister
	crdSynced cache.InformerSynced

	apiServiceRegistration AutoAPIServiceRegistration

	syncHandler func(groupVersion schema.GroupVersion) error

	syncedInitialSet chan struct{}

	// queue is where incoming work is placed to de-dup and to allow "easy" rate limited requeues on errors
	// this is actually keyed by a groupVersion
	queue workqueue.RateLimitingInterface
}

// NewCRDRegistrationController returns a controller which will register CRD GroupVersions with the auto APIService registration
// controller so they automatically stay in sync.
func NewCRDRegistrationController(crdinformer crdinformers.CustomResourceDefinitionInformer, apiServiceRegistration AutoAPIServiceRegistration) *crdRegistrationController {
	c := &crdRegistrationController{
		crdLister:              crdinformer.Lister(),
		crdSynced:              crdinformer.Informer().HasSynced,
		apiServiceRegistration: apiServiceRegistration,
		syncedInitialSet:       make(chan struct{}),
		queue:                  workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "crd_autoregistration_controller"),
	}
	c.syncHandler = c.handleVersionUpdate

	crdinformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			cast := obj.(*apiextensionsv1.CustomResourceDefinition)
			c.enqueueCRD(cast)
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			// Enqueue both old and new object to make sure we remove and add appropriate API services.
			// The working queue will resolve any duplicates and only changes will stay in the queue.
			c.enqueueCRD(oldObj.(*apiextensionsv1.CustomResourceDefinition))
			c.enqueueCRD(newObj.(*apiextensionsv1.CustomResourceDefinition))
		},
		DeleteFunc: func(obj interface{}) {
			cast, ok := obj.(*apiextensionsv1.CustomResourceDefinition)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					klog.V(2).Infof("Couldn't get object from tombstone %#v", obj)
					return
				}
				cast, ok = tombstone.Obj.(*apiextensionsv1.CustomResourceDefinition)
				if !ok {
					klog.V(2).Infof("Tombstone contained unexpected object: %#v", obj)
					return
				}
			}
			c.enqueueCRD(cast)
		},
	})

	return c
}

func (c *crdRegistrationController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	// make sure the work queue is shutdown which will trigger workers to end
	defer c.queue.ShutDown()

	klog.Infof("Starting crd-autoregister controller")
	defer klog.Infof("Shutting down crd-autoregister controller")

	// wait for your secondary caches to fill before starting your work
	if !cache.WaitForNamedCacheSync("crd-autoregister", stopCh, c.crdSynced) {
		return
	}

	// process each item in the list once
	if crds, err := c.crdLister.List(labels.Everything()); err != nil {
		utilruntime.HandleError(err)
	} else {
		for _, crd := range crds {
			for _, version := range crd.Spec.Versions {
				if err := c.syncHandler(schema.GroupVersion{Group: crd.Spec.Group, Version: version.Name}); err != nil {
					utilruntime.HandleError(err)
				}
			}
		}
	}
	close(c.syncedInitialSet)

	// start up your worker threads based on workers.  Some controllers have multiple kinds of workers
	for i := 0; i < workers; i++ {
		// runWorker will loop until "something bad" happens.  The .Until will then rekick the worker
		// after one second
		go wait.Until(c.runWorker, time.Second, stopCh)
	}

	// wait until we're told to stop
	<-stopCh
}

// WaitForInitialSync blocks until the initial set of CRD resources has been processed
func (c *crdRegistrationController) WaitForInitialSync() {
	<-c.syncedInitialSet
}

func (c *crdRegistrationController) runWorker() {
	// hot loop until we're told to stop.  processNextWorkItem will automatically wait until there's work
	// available, so we don't worry about secondary waits
	for c.processNextWorkItem() {
	}
}

// processNextWorkItem deals with one key off the queue.  It returns false when it's time to quit.
func (c *crdRegistrationController) processNextWorkItem() bool {
	// pull the next work item from queue.  It should be a key we use to lookup something in a cache
	key, quit := c.queue.Get()
	if quit {
		return false
	}
	// you always have to indicate to the queue that you've completed a piece of work
	defer c.queue.Done(key)

	// do your work on the key.  This method will contains your "do stuff" logic
	err := c.syncHandler(key.(schema.GroupVersion))
	if err == nil {
		// if you had no error, tell the queue to stop tracking history for your key.  This will
		// reset things like failure counts for per-item rate limiting
		c.queue.Forget(key)
		return true
	}

	// there was a failure so be sure to report it.  This method allows for pluggable error handling
	// which can be used for things like cluster-monitoring
	utilruntime.HandleError(fmt.Errorf("%v failed with : %v", key, err))
	// since we failed, we should requeue the item to work on later.  This method will add a backoff
	// to avoid hotlooping on particular items (they're probably still not going to work right away)
	// and overall controller protection (everything I've done is broken, this controller needs to
	// calm down or it can starve other useful work) cases.
	c.queue.AddRateLimited(key)

	return true
}

func (c *crdRegistrationController) enqueueCRD(crd *apiextensionsv1.CustomResourceDefinition) {
	for _, version := range crd.Spec.Versions {
		c.queue.Add(schema.GroupVersion{Group: crd.Spec.Group, Version: version.Name})
	}
}

func (c *crdRegistrationController) handleVersionUpdate(groupVersion schema.GroupVersion) error {
	apiServiceName := groupVersion.Version + "." + groupVersion.Group

	if apiserver.APIServiceAlreadyExists(groupVersion) {
		return nil
	}

	// check all CRDs.  There shouldn't that many, but if we have problems later we can index them
	crds, err := c.crdLister.List(labels.Everything())
	if err != nil {
		return err
	}
	for _, crd := range crds {
		if crd.Spec.Group != groupVersion.Group {
			continue
		}
		for _, version := range crd.Spec.Versions {
			if version.Name != groupVersion.Version || !version.Served {
				continue
			}

			c.apiServiceRegistration.AddAPIServiceToSync(&v1.APIService{
				ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
				Spec: v1.APIServiceSpec{
					Group:                groupVersion.Group,
					Version:              groupVersion.Version,
					GroupPriorityMinimum: 1000, // CRDs should have relatively low priority
					VersionPriority:      100,  // CRDs will be sorted by kube-like versions like any other APIService with the same VersionPriority
				},
			})
			return nil
		}
	}

	c.apiServiceRegistration.RemoveAPIServiceToSync(apiServiceName)
	return nil
}
<commit_msg>UPSTREAM: <carry>: remove apiservice from sync in CRD registration when it exists<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package crdregistration

import (
	"fmt"
	"time"

	"k8s.io/klog/v2"

	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	crdinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1"
	crdlisters "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
	v1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
	"k8s.io/kube-aggregator/pkg/apiserver"
)

// AutoAPIServiceRegistration is an interface which callers can re-declare locally and properly cast to for
// adding and removing APIServices
type AutoAPIServiceRegistration interface {
	// AddAPIServiceToSync adds an API service to auto-register.
	AddAPIServiceToSync(in *v1.APIService)
	// RemoveAPIServiceToSync removes an API service to auto-register.
	RemoveAPIServiceToSync(name string)
}

type crdRegistrationController struct {
	crdLister crdlisters.CustomResourceDefinitionLister
	crdSynced cache.InformerSynced

	apiServiceRegistration AutoAPIServiceRegistration

	syncHandler func(groupVersion schema.GroupVersion) error

	syncedInitialSet chan struct{}

	// queue is where incoming work is placed to de-dup and to allow "easy" rate limited requeues on errors
	// this is actually keyed by a groupVersion
	queue workqueue.RateLimitingInterface
}

// NewCRDRegistrationController returns a controller which will register CRD GroupVersions with the auto APIService registration
// controller so they automatically stay in sync.
func NewCRDRegistrationController(crdinformer crdinformers.CustomResourceDefinitionInformer, apiServiceRegistration AutoAPIServiceRegistration) *crdRegistrationController {
	c := &crdRegistrationController{
		crdLister:              crdinformer.Lister(),
		crdSynced:              crdinformer.Informer().HasSynced,
		apiServiceRegistration: apiServiceRegistration,
		syncedInitialSet:       make(chan struct{}),
		queue:                  workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "crd_autoregistration_controller"),
	}
	c.syncHandler = c.handleVersionUpdate

	crdinformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			cast := obj.(*apiextensionsv1.CustomResourceDefinition)
			c.enqueueCRD(cast)
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			// Enqueue both old and new object to make sure we remove and add appropriate API services.
			// The working queue will resolve any duplicates and only changes will stay in the queue.
			c.enqueueCRD(oldObj.(*apiextensionsv1.CustomResourceDefinition))
			c.enqueueCRD(newObj.(*apiextensionsv1.CustomResourceDefinition))
		},
		DeleteFunc: func(obj interface{}) {
			cast, ok := obj.(*apiextensionsv1.CustomResourceDefinition)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					klog.V(2).Infof("Couldn't get object from tombstone %#v", obj)
					return
				}
				cast, ok = tombstone.Obj.(*apiextensionsv1.CustomResourceDefinition)
				if !ok {
					klog.V(2).Infof("Tombstone contained unexpected object: %#v", obj)
					return
				}
			}
			c.enqueueCRD(cast)
		},
	})

	return c
}

func (c *crdRegistrationController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	// make sure the work queue is shutdown which will trigger workers to end
	defer c.queue.ShutDown()

	klog.Infof("Starting crd-autoregister controller")
	defer klog.Infof("Shutting down crd-autoregister controller")

	// wait for your secondary caches to fill before starting your work
	if !cache.WaitForNamedCacheSync("crd-autoregister", stopCh, c.crdSynced) {
		return
	}

	// process each item in the list once
	if crds, err := c.crdLister.List(labels.Everything()); err != nil {
		utilruntime.HandleError(err)
	} else {
		for _, crd := range crds {
			for _, version := range crd.Spec.Versions {
				if err := c.syncHandler(schema.GroupVersion{Group: crd.Spec.Group, Version: version.Name}); err != nil {
					utilruntime.HandleError(err)
				}
			}
		}
	}
	close(c.syncedInitialSet)

	// start up your worker threads based on workers.  Some controllers have multiple kinds of workers
	for i := 0; i < workers; i++ {
		// runWorker will loop until "something bad" happens.  The .Until will then rekick the worker
		// after one second
		go wait.Until(c.runWorker, time.Second, stopCh)
	}

	// wait until we're told to stop
	<-stopCh
}

// WaitForInitialSync blocks until the initial set of CRD resources has been processed
func (c *crdRegistrationController) WaitForInitialSync() {
	<-c.syncedInitialSet
}

func (c *crdRegistrationController) runWorker() {
	// hot loop until we're told to stop.  processNextWorkItem will automatically wait until there's work
	// available, so we don't worry about secondary waits
	for c.processNextWorkItem() {
	}
}

// processNextWorkItem deals with one key off the queue.  It returns false when it's time to quit.
func (c *crdRegistrationController) processNextWorkItem() bool {
	// pull the next work item from queue.  It should be a key we use to lookup something in a cache
	key, quit := c.queue.Get()
	if quit {
		return false
	}
	// you always have to indicate to the queue that you've completed a piece of work
	defer c.queue.Done(key)

	// do your work on the key.  This method will contains your "do stuff" logic
	err := c.syncHandler(key.(schema.GroupVersion))
	if err == nil {
		// if you had no error, tell the queue to stop tracking history for your key.  This will
		// reset things like failure counts for per-item rate limiting
		c.queue.Forget(key)
		return true
	}

	// there was a failure so be sure to report it.  This method allows for pluggable error handling
	// which can be used for things like cluster-monitoring
	utilruntime.HandleError(fmt.Errorf("%v failed with : %v", key, err))
	// since we failed, we should requeue the item to work on later.  This method will add a backoff
	// to avoid hotlooping on particular items (they're probably still not going to work right away)
	// and overall controller protection (everything I've done is broken, this controller needs to
	// calm down or it can starve other useful work) cases.
	c.queue.AddRateLimited(key)

	return true
}

func (c *crdRegistrationController) enqueueCRD(crd *apiextensionsv1.CustomResourceDefinition) {
	for _, version := range crd.Spec.Versions {
		c.queue.Add(schema.GroupVersion{Group: crd.Spec.Group, Version: version.Name})
	}
}

func (c *crdRegistrationController) handleVersionUpdate(groupVersion schema.GroupVersion) error {
	apiServiceName := groupVersion.Version + "." + groupVersion.Group

	if apiserver.APIServiceAlreadyExists(groupVersion) {
		// Removing APIService from sync means the CRD registration controller won't sync this APIService
		// anymore. If the APIService is managed externally, this will mean the external component can
		// update this APIService without CRD controller stomping the changes on it.
		c.apiServiceRegistration.RemoveAPIServiceToSync(apiServiceName)
		return nil
	}

	// check all CRDs.  There shouldn't that many, but if we have problems later we can index them
	crds, err := c.crdLister.List(labels.Everything())
	if err != nil {
		return err
	}
	for _, crd := range crds {
		if crd.Spec.Group != groupVersion.Group {
			continue
		}
		for _, version := range crd.Spec.Versions {
			if version.Name != groupVersion.Version || !version.Served {
				continue
			}

			c.apiServiceRegistration.AddAPIServiceToSync(&v1.APIService{
				ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
				Spec: v1.APIServiceSpec{
					Group:                groupVersion.Group,
					Version:              groupVersion.Version,
					GroupPriorityMinimum: 1000, // CRDs should have relatively low priority
					VersionPriority:      100,  // CRDs will be sorted by kube-like versions like any other APIService with the same VersionPriority
				},
			})
			return nil
		}
	}

	c.apiServiceRegistration.RemoveAPIServiceToSync(apiServiceName)
	return nil
}
<|endoftext|>


<commit_before><commit_msg>Remove now-unused stemFunc<commit_after><|endoftext|>


<commit_before><commit_msg>Coalesce events<commit_after><|endoftext|>


<commit_before>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package propagation_test

import (
	"context"
	"net/http"
	"testing"

	"go.opentelemetry.io/otel/oteltest"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/trace"
)

func BenchmarkInject(b *testing.B) {
	var t propagation.TraceContext

	injectSubBenchmarks(b, func(ctx context.Context, b *testing.B) {
		req, _ := http.NewRequest("GET", "http://example.com", nil)
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			t.Inject(ctx, propagation.HeaderCarrier(req.Header))
		}
	})
}

func injectSubBenchmarks(b *testing.B, fn func(context.Context, *testing.B)) {
	b.Run("SampledSpanContext", func(b *testing.B) {
		spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7")
		traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")

		mockTracer := oteltest.DefaultTracer()
		b.ReportAllocs()
		sc := trace.NewSpanContext(trace.SpanContextConfig{
			TraceID:    traceID,
			SpanID:     spanID,
			TraceFlags: trace.FlagsSampled,
		})
		ctx := trace.ContextWithRemoteSpanContext(context.Background(), sc)
		ctx, _ = mockTracer.Start(ctx, "inject")
		fn(ctx, b)
	})

	b.Run("WithoutSpanContext", func(b *testing.B) {
		b.ReportAllocs()
		ctx := context.Background()
		fn(ctx, b)
	})
}

func BenchmarkExtract(b *testing.B) {
	extractSubBenchmarks(b, func(b *testing.B, req *http.Request) {
		var propagator propagation.TraceContext
		ctx := context.Background()
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			propagator.Extract(ctx, propagation.HeaderCarrier(req.Header))
		}
	})
}

func extractSubBenchmarks(b *testing.B, fn func(*testing.B, *http.Request)) {
	b.Run("Sampled", func(b *testing.B) {
		req, _ := http.NewRequest("GET", "http://example.com", nil)
		req.Header.Set("traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01")
		b.ReportAllocs()

		fn(b, req)
	})

	b.Run("BogusVersion", func(b *testing.B) {
		req, _ := http.NewRequest("GET", "http://example.com", nil)
		req.Header.Set("traceparent", "qw-00000000000000000000000000000000-0000000000000000-01")
		b.ReportAllocs()
		fn(b, req)
	})

	b.Run("FutureAdditionalData", func(b *testing.B) {
		req, _ := http.NewRequest("GET", "http://example.com", nil)
		req.Header.Set("traceparent", "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-XYZxsf09")
		b.ReportAllocs()
		fn(b, req)
	})
}
<commit_msg>Simplify trace context benchmark test (#2109)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package propagation_test

import (
	"context"
	"net/http"
	"testing"

	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/trace"
)

func BenchmarkInject(b *testing.B) {
	var t propagation.TraceContext

	injectSubBenchmarks(b, func(ctx context.Context, b *testing.B) {
		h := http.Header{}
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			t.Inject(ctx, propagation.HeaderCarrier(h))
		}
	})
}

func injectSubBenchmarks(b *testing.B, fn func(context.Context, *testing.B)) {
	b.Run("SampledSpanContext", func(b *testing.B) {
		b.ReportAllocs()
		sc := trace.NewSpanContext(trace.SpanContextConfig{
			TraceID:    traceID,
			SpanID:     spanID,
			TraceFlags: trace.FlagsSampled,
		})
		ctx := trace.ContextWithRemoteSpanContext(context.Background(), sc)
		fn(ctx, b)
	})

	b.Run("WithoutSpanContext", func(b *testing.B) {
		b.ReportAllocs()
		ctx := context.Background()
		fn(ctx, b)
	})
}

func BenchmarkExtract(b *testing.B) {
	extractSubBenchmarks(b, func(b *testing.B, req *http.Request) {
		var propagator propagation.TraceContext
		ctx := context.Background()
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			propagator.Extract(ctx, propagation.HeaderCarrier(req.Header))
		}
	})
}

func extractSubBenchmarks(b *testing.B, fn func(*testing.B, *http.Request)) {
	b.Run("Sampled", func(b *testing.B) {
		req, _ := http.NewRequest("GET", "http://example.com", nil)
		req.Header.Set("traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01")
		b.ReportAllocs()

		fn(b, req)
	})

	b.Run("BogusVersion", func(b *testing.B) {
		req, _ := http.NewRequest("GET", "http://example.com", nil)
		req.Header.Set("traceparent", "qw-00000000000000000000000000000000-0000000000000000-01")
		b.ReportAllocs()
		fn(b, req)
	})

	b.Run("FutureAdditionalData", func(b *testing.B) {
		req, _ := http.NewRequest("GET", "http://example.com", nil)
		req.Header.Set("traceparent", "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09-XYZxsf09")
		b.ReportAllocs()
		fn(b, req)
	})
}
<|endoftext|>


<commit_before>//
// util.go -- various utilities
//

package srnd

import (
  "github.com/majestrate/srndv2/src/nacl"
  "crypto/sha1"
  "crypto/sha512"
  "encoding/base64"
  "encoding/hex"
  "fmt"
  "io"
  "log"
  "net"
  "os"
  "path/filepath"
  "strconv"
  "strings"
  "time"
)

func DelFile(fname string) {
  if CheckFile(fname) {
    os.Remove(fname)
  }
}

func CheckFile(fname string) bool {
  if _, err := os.Stat(fname) ; os.IsNotExist(err) {
    return false
  }
  return true
}

func IsDir(dirname string) bool {
  stat, err := os.Stat(dirname)
  if err != nil {
    log.Fatal(err)
  }
  return stat.IsDir()
}

// ensure a directory exists
func EnsureDir(dirname string) {
  stat, err := os.Stat(dirname)
  if os.IsNotExist(err) {
    os.Mkdir(dirname, 0755)
  } else if ! stat.IsDir() {
    os.Remove(dirname)
    os.Mkdir(dirname, 0755)
  }
}

// TODO make this work better
func ValidMessageID(id string) bool {
  id_len := len(id)
  if id_len < 5 {
    return false
  }

  at_idx := strings.Index(id, "@")
  if at_idx < 3 {
    return false
  }

  for idx, c := range id {
    if idx == 0 {
      if c == '<' {
        continue
      }
    } else if idx == id_len - 1 {
      if c == '>' {
        continue
      }
    } else {
      if idx == at_idx {
        continue
      }
      if c >= 'a' && c <= 'z' {
        continue
      }
      if c >= 'A' && c <= 'Z' {
        continue
      }
      if c >= '0' && c <= '9' {
        continue
      }
      if c == '.' {
        continue
      }
    }
    log.Printf("bad message ID: %s , invalid char at %d: %c", id, idx, c)
    return false
  }
  return true
}

// message id hash
func HashMessageID(msgid string) string {
  return fmt.Sprintf("%x", sha1.Sum([]byte(msgid)))
}
// short message id hash
// >>hash
func ShortHashMessageID(msgid string) string {
  return HashMessageID(msgid)[:10]
}

type lineWriter struct {
  io.Writer
  wr io.Writer
  delim []byte
}

func NewLineWriter(wr io.Writer, delim string) io.Writer {
  return lineWriter{wr, wr, []byte(delim)}
}

func (self lineWriter) Write(data []byte) (n int, err error) {
  n, err = self.wr.Write(data)
  self.wr.Write(self.delim)
  return n, err
}

func OpenFileWriter(fname string) (io.WriteCloser, error) {
  return os.Create(fname)
}

// make a random string
func randStr(length int) string {
  return hex.EncodeToString(nacl.RandBytes(length))[length:]
}

// time for right now as int64
func timeNow() int64 {
  return time.Now().Unix()
}

// sanitize data for nntp
func nntpSanitize(data string) string {
  parts := strings.Split(data, "\n.\n")
  return parts[0]
}

type int64Sorter []int64

func (self int64Sorter) Len() int {
  return len(self)
}

func (self int64Sorter) Less(i, j int) bool {
  return self[i] < self[j]
}

func (self int64Sorter) Swap(i, j int) {
  tmp := self[j]
  self[j] = self[i]
  self[i] = tmp
}

// obtain the "real" ip address
func getRealIP(name string) string {
  if len(name) > 0 {
    ip , err := net.ResolveIPAddr("ip", name)
    if err == nil {
      if ip.IP.IsGlobalUnicast() {
      return ip.IP.String()
      }
    }
  }
  return ""
}

// check that we have permission to access this
// fatal on fail
func checkPerms(fname string) {
  fstat, err := os.Stat(fname)
  if err != nil {
    log.Fatalf("Cannot access %s, %s", fname, err)
  }
  // check if we can access this dir
  if fstat.IsDir() {
    tmpfname := filepath.Join(fname, ".test")
    f, err := os.Create(tmpfname)
    if err != nil {
      log.Fatalf("No Write access in %s, %s", fname, err)
    }
    err = f.Close()
    if err != nil {
      log.Fatalf("failed to close test file %s !? %s", tmpfname, err)
    }
    err = os.Remove(tmpfname)
    if err != nil {
      log.Fatalf("failed to remove test file %s, %s", tmpfname, err)
    }
  } else {
    // this isn't a dir, treat it like a regular file
    f, err := os.Open(fname)
    if err != nil {
      log.Fatalf("cannot read file %s, %s", fname, err)
    }
    f.Close()
  }
}

// given an address
// generate a new encryption key for it
// return the encryption key and the encrypted address
func newAddrEnc(addr string) (string, string) {
  key_bytes := nacl.RandBytes(32)
  key := base64.StdEncoding.EncodeToString(key_bytes)
  return key, encAddr(addr, key)
}

// xor address with a one time pad
// if the address isn't long enough it's padded with spaces
func encAddr(addr, key string) string {
  key_bytes, err := base64.StdEncoding.DecodeString(key)

  if err != nil {
    log.Println("encAddr() key base64 decode", err)
    return ""
  }

  if len(addr) > len(key_bytes) {
    log.Println("encAddr() len(addr) > len(key_bytes)")
    return ""
  }

  // pad with spaces
  for len(addr) < len(key_bytes) {
    addr += " "
  }

  addr_bytes := []byte(addr)
  res_bytes := make([]byte, len(addr_bytes))
  for idx, b := range key_bytes {
    res_bytes[idx] = addr_bytes[idx] ^ b
  }

  return base64.StdEncoding.EncodeToString(res_bytes)
}

// decrypt an address
// strips any whitespaces
func decAddr(encaddr, key string) string {
  encaddr_bytes, err := base64.StdEncoding.DecodeString(encaddr)
  if err != nil {
    log.Println("decAddr() encaddr base64 decode", err)
    return ""
  }
  if len(encaddr_bytes) != len(key) {
    log.Println("decAddr() len(encaddr_bytes) != len(key)")
    return ""
  }
  key_bytes, err := base64.StdEncoding.DecodeString(key)
  if err != nil {
    log.Println("decAddr() key base64 decode", err)
  }
  res_bytes := make([]byte, len(key))
  for idx, b := range key_bytes {
    res_bytes[idx] = encaddr_bytes[idx] ^ b
  }
  res := string(res_bytes)
  return strings.Trim(res, " ")
}

func newsgroupValidFormat(newsgroup string) bool {
  // too long newsgroup
  if len(newsgroup) > 128 {
    return false
  }
  for _, ch := range newsgroup {
    if ch >= 'a' && ch <= 'z' {
      continue
    }
    if ch >= '0' && ch <= '9' {
      continue
    }
    if ch >= 'A' && ch <= 'Z' {
      continue
    }
    if ch == '.' {
      continue
    }
    return false
  }
  return true
}

// generate a new signing keypair
// public, secret
func newSignKeypair() (string, string) {
  kp := nacl.GenSignKeypair()
  defer kp.Free()
  pk := kp.Public()
  sk := kp.Secret()
  return hex.EncodeToString(pk), hex.EncodeToString(sk)
}

// make a utf-8 tripcode
func makeTripcode(pk string) string {
  data, err := hex.DecodeString(pk)
  if err == nil {
    tripcode := ""
    //  here is the python code this is based off of
    //  i do something slightly different but this is the base
    //
    //  for x in range(0, length / 2):
    //    pub_short += '&#%i;' % (9600 + int(full_pubkey_hex[x*2:x*2+2], 16))
    //  length -= length / 2
    //  for x in range(0, length):
    //    pub_short += '&#%i;' % (9600 + int(full_pubkey_hex[-(length*2):][x*2:x*2+2], 16))
    //
    for _, c := range data {
      ch := 9600
      ch += int(c)
      tripcode += fmt.Sprintf("&#%04d;", ch)
    }
    return tripcode
  }
  return "[invalid]"
}

// generate a new message id with base name
func genMessageID(name string) string {
  return fmt.Sprintf("<%s%d@%s>", randStr(5), timeNow(), name)
}

// time now as a string timestamp
func timeNowStr() string {
  return time.Unix(timeNow(), 0).UTC().Format(time.RFC1123Z)
}

// get from a map an int given a key or fall back to a default value
func mapGetInt(m map[string]string, key string, fallback int) int {
  val, ok := m[key]
  if ok {
    i, err := strconv.ParseInt(val, 10, 32)
    if err == nil {
      return int(i)
    }
  }
  return fallback
}

func isSage(str string) bool {
  str = strings.ToLower(str)
  return str == "sage" || strings.HasPrefix(str, "sage ")
}

func unhex(str string) []byte {
  buff, _ := hex.DecodeString(str)
  return buff
}

func hexify(data []byte) string {
  return hex.EncodeToString(data)
}

// extract pubkey from secret key
// return as base32
func getSignPubkey(sk []byte) string {
  return hexify(nacl.GetSignPubkey(sk))
}

// sign data with secret key the fucky srnd way
// return signature as base32
func cryptoSign(data, sk []byte) string {
  // hash
  hash := sha512.Sum512(data)
  log.Printf("hash=%s len=%s", hexify(hash[:]), len(data))
  // sign
  sig := nacl.CryptoSignFucky(hash[:], sk)
  return hexify(sig)
}

// given a tripcode after the #
// make a private key byteslice
func parseTripcodeSecret(str string) []byte {
  // try decoding hex
  raw := unhex(str)
  keylen := nacl.CryptoSignSecretLen()
  if raw == nil || len(raw) != keylen {
    // treat this as a "regular" chan tripcode
    // decode as bytes then pad the rest with 0s if it doesn't fit
    raw = make([]byte, keylen)
    str_bytes := []byte(str)
    if len(str_bytes) > keylen {
      copy(raw, str_bytes[:keylen])
    } else {
      copy(raw, str_bytes)
    }
  }
  return raw
}
<commit_msg>debugging<commit_after>//
// util.go -- various utilities
//

package srnd

import (
  "github.com/majestrate/srndv2/src/nacl"
  "crypto/sha1"
  "crypto/sha512"
  "encoding/base64"
  "encoding/hex"
  "fmt"
  "io"
  "log"
  "net"
  "os"
  "path/filepath"
  "strconv"
  "strings"
  "time"
)

func DelFile(fname string) {
  if CheckFile(fname) {
    os.Remove(fname)
  }
}

func CheckFile(fname string) bool {
  if _, err := os.Stat(fname) ; os.IsNotExist(err) {
    return false
  }
  return true
}

func IsDir(dirname string) bool {
  stat, err := os.Stat(dirname)
  if err != nil {
    log.Fatal(err)
  }
  return stat.IsDir()
}

// ensure a directory exists
func EnsureDir(dirname string) {
  stat, err := os.Stat(dirname)
  if os.IsNotExist(err) {
    os.Mkdir(dirname, 0755)
  } else if ! stat.IsDir() {
    os.Remove(dirname)
    os.Mkdir(dirname, 0755)
  }
}

// TODO make this work better
func ValidMessageID(id string) bool {
  id_len := len(id)
  if id_len < 5 {
    return false
  }

  at_idx := strings.Index(id, "@")
  if at_idx < 3 {
    return false
  }

  for idx, c := range id {
    if idx == 0 {
      if c == '<' {
        continue
      }
    } else if idx == id_len - 1 {
      if c == '>' {
        continue
      }
    } else {
      if idx == at_idx {
        continue
      }
      if c >= 'a' && c <= 'z' {
        continue
      }
      if c >= 'A' && c <= 'Z' {
        continue
      }
      if c >= '0' && c <= '9' {
        continue
      }
      if c == '.' {
        continue
      }
    }
    log.Printf("bad message ID: len=%d %s , invalid char at %d: %c", id_len, id, idx, c)
    return false
  }
  return true
}

// message id hash
func HashMessageID(msgid string) string {
  return fmt.Sprintf("%x", sha1.Sum([]byte(msgid)))
}
// short message id hash
// >>hash
func ShortHashMessageID(msgid string) string {
  return HashMessageID(msgid)[:10]
}

type lineWriter struct {
  io.Writer
  wr io.Writer
  delim []byte
}

func NewLineWriter(wr io.Writer, delim string) io.Writer {
  return lineWriter{wr, wr, []byte(delim)}
}

func (self lineWriter) Write(data []byte) (n int, err error) {
  n, err = self.wr.Write(data)
  self.wr.Write(self.delim)
  return n, err
}

func OpenFileWriter(fname string) (io.WriteCloser, error) {
  return os.Create(fname)
}

// make a random string
func randStr(length int) string {
  return hex.EncodeToString(nacl.RandBytes(length))[length:]
}

// time for right now as int64
func timeNow() int64 {
  return time.Now().Unix()
}

// sanitize data for nntp
func nntpSanitize(data string) string {
  parts := strings.Split(data, "\n.\n")
  return parts[0]
}

type int64Sorter []int64

func (self int64Sorter) Len() int {
  return len(self)
}

func (self int64Sorter) Less(i, j int) bool {
  return self[i] < self[j]
}

func (self int64Sorter) Swap(i, j int) {
  tmp := self[j]
  self[j] = self[i]
  self[i] = tmp
}

// obtain the "real" ip address
func getRealIP(name string) string {
  if len(name) > 0 {
    ip , err := net.ResolveIPAddr("ip", name)
    if err == nil {
      if ip.IP.IsGlobalUnicast() {
      return ip.IP.String()
      }
    }
  }
  return ""
}

// check that we have permission to access this
// fatal on fail
func checkPerms(fname string) {
  fstat, err := os.Stat(fname)
  if err != nil {
    log.Fatalf("Cannot access %s, %s", fname, err)
  }
  // check if we can access this dir
  if fstat.IsDir() {
    tmpfname := filepath.Join(fname, ".test")
    f, err := os.Create(tmpfname)
    if err != nil {
      log.Fatalf("No Write access in %s, %s", fname, err)
    }
    err = f.Close()
    if err != nil {
      log.Fatalf("failed to close test file %s !? %s", tmpfname, err)
    }
    err = os.Remove(tmpfname)
    if err != nil {
      log.Fatalf("failed to remove test file %s, %s", tmpfname, err)
    }
  } else {
    // this isn't a dir, treat it like a regular file
    f, err := os.Open(fname)
    if err != nil {
      log.Fatalf("cannot read file %s, %s", fname, err)
    }
    f.Close()
  }
}

// given an address
// generate a new encryption key for it
// return the encryption key and the encrypted address
func newAddrEnc(addr string) (string, string) {
  key_bytes := nacl.RandBytes(32)
  key := base64.StdEncoding.EncodeToString(key_bytes)
  return key, encAddr(addr, key)
}

// xor address with a one time pad
// if the address isn't long enough it's padded with spaces
func encAddr(addr, key string) string {
  key_bytes, err := base64.StdEncoding.DecodeString(key)

  if err != nil {
    log.Println("encAddr() key base64 decode", err)
    return ""
  }

  if len(addr) > len(key_bytes) {
    log.Println("encAddr() len(addr) > len(key_bytes)")
    return ""
  }

  // pad with spaces
  for len(addr) < len(key_bytes) {
    addr += " "
  }

  addr_bytes := []byte(addr)
  res_bytes := make([]byte, len(addr_bytes))
  for idx, b := range key_bytes {
    res_bytes[idx] = addr_bytes[idx] ^ b
  }

  return base64.StdEncoding.EncodeToString(res_bytes)
}

// decrypt an address
// strips any whitespaces
func decAddr(encaddr, key string) string {
  encaddr_bytes, err := base64.StdEncoding.DecodeString(encaddr)
  if err != nil {
    log.Println("decAddr() encaddr base64 decode", err)
    return ""
  }
  if len(encaddr_bytes) != len(key) {
    log.Println("decAddr() len(encaddr_bytes) != len(key)")
    return ""
  }
  key_bytes, err := base64.StdEncoding.DecodeString(key)
  if err != nil {
    log.Println("decAddr() key base64 decode", err)
  }
  res_bytes := make([]byte, len(key))
  for idx, b := range key_bytes {
    res_bytes[idx] = encaddr_bytes[idx] ^ b
  }
  res := string(res_bytes)
  return strings.Trim(res, " ")
}

func newsgroupValidFormat(newsgroup string) bool {
  // too long newsgroup
  if len(newsgroup) > 128 {
    return false
  }
  for _, ch := range newsgroup {
    if ch >= 'a' && ch <= 'z' {
      continue
    }
    if ch >= '0' && ch <= '9' {
      continue
    }
    if ch >= 'A' && ch <= 'Z' {
      continue
    }
    if ch == '.' {
      continue
    }
    return false
  }
  return true
}

// generate a new signing keypair
// public, secret
func newSignKeypair() (string, string) {
  kp := nacl.GenSignKeypair()
  defer kp.Free()
  pk := kp.Public()
  sk := kp.Secret()
  return hex.EncodeToString(pk), hex.EncodeToString(sk)
}

// make a utf-8 tripcode
func makeTripcode(pk string) string {
  data, err := hex.DecodeString(pk)
  if err == nil {
    tripcode := ""
    //  here is the python code this is based off of
    //  i do something slightly different but this is the base
    //
    //  for x in range(0, length / 2):
    //    pub_short += '&#%i;' % (9600 + int(full_pubkey_hex[x*2:x*2+2], 16))
    //  length -= length / 2
    //  for x in range(0, length):
    //    pub_short += '&#%i;' % (9600 + int(full_pubkey_hex[-(length*2):][x*2:x*2+2], 16))
    //
    for _, c := range data {
      ch := 9600
      ch += int(c)
      tripcode += fmt.Sprintf("&#%04d;", ch)
    }
    return tripcode
  }
  return "[invalid]"
}

// generate a new message id with base name
func genMessageID(name string) string {
  return fmt.Sprintf("<%s%d@%s>", randStr(5), timeNow(), name)
}

// time now as a string timestamp
func timeNowStr() string {
  return time.Unix(timeNow(), 0).UTC().Format(time.RFC1123Z)
}

// get from a map an int given a key or fall back to a default value
func mapGetInt(m map[string]string, key string, fallback int) int {
  val, ok := m[key]
  if ok {
    i, err := strconv.ParseInt(val, 10, 32)
    if err == nil {
      return int(i)
    }
  }
  return fallback
}

func isSage(str string) bool {
  str = strings.ToLower(str)
  return str == "sage" || strings.HasPrefix(str, "sage ")
}

func unhex(str string) []byte {
  buff, _ := hex.DecodeString(str)
  return buff
}

func hexify(data []byte) string {
  return hex.EncodeToString(data)
}

// extract pubkey from secret key
// return as base32
func getSignPubkey(sk []byte) string {
  return hexify(nacl.GetSignPubkey(sk))
}

// sign data with secret key the fucky srnd way
// return signature as base32
func cryptoSign(data, sk []byte) string {
  // hash
  hash := sha512.Sum512(data)
  log.Printf("hash=%s len=%s", hexify(hash[:]), len(data))
  // sign
  sig := nacl.CryptoSignFucky(hash[:], sk)
  return hexify(sig)
}

// given a tripcode after the #
// make a private key byteslice
func parseTripcodeSecret(str string) []byte {
  // try decoding hex
  raw := unhex(str)
  keylen := nacl.CryptoSignSecretLen()
  if raw == nil || len(raw) != keylen {
    // treat this as a "regular" chan tripcode
    // decode as bytes then pad the rest with 0s if it doesn't fit
    raw = make([]byte, keylen)
    str_bytes := []byte(str)
    if len(str_bytes) > keylen {
      copy(raw, str_bytes[:keylen])
    } else {
      copy(raw, str_bytes)
    }
  }
  return raw
}
<|endoftext|>


<commit_before><commit_msg>add license<commit_after><|endoftext|>


<commit_before>package somaproto

import (
	"github.com/satori/go.uuid"
)

type ProtoRequestOncall struct {
	OnCall  ProtoOncall         `json:"oncall,omitempty"`
	Filter  ProtoOncallFilter   `json:"filter,omitempty"`
	Members []ProtoOncallMember `json:"members,omitempty"`
}

type ProtoResultOncall struct {
	Code    uint16        `json:"code,omitempty"`
	Status  string        `json:"status,omitempty"`
	Text    []string      `json:"text,omitempty"`
	Oncalls []ProtoOncall `json:"oncalls,omitempty"`
}

type ProtoOncall struct {
	Id      uuid.UUID          `json:"id,omitempty"`
	Name    string             `json:"name,omitempty"`
	Number  string             `json:"number,omitempty"`
	Details ProtoOncallDetails `json:"details,omitempty"`
}

type ProtoOncallDetails struct {
	CreatedAt string   `json:"createdat,omitempty"`
	CreatedBy string   `json:"createdby,omitempty"`
	Members   []string `json:"members,omitempty"`
}

type ProtoOncallMember struct {
	UserName string    `json:"username,omitempty"`
	UserId   uuid.UUID `json"userid,omitempty"`
}

type ProtoOncallFilter struct {
	Name   string `json:"name,omitempty"`
	Number string `json:"number,omitempty"`
}
<commit_msg>oncall: add missing vim modeline<commit_after>package somaproto

import (
	"github.com/satori/go.uuid"
)

type ProtoRequestOncall struct {
	OnCall  ProtoOncall         `json:"oncall,omitempty"`
	Filter  ProtoOncallFilter   `json:"filter,omitempty"`
	Members []ProtoOncallMember `json:"members,omitempty"`
}

type ProtoResultOncall struct {
	Code    uint16        `json:"code,omitempty"`
	Status  string        `json:"status,omitempty"`
	Text    []string      `json:"text,omitempty"`
	Oncalls []ProtoOncall `json:"oncalls,omitempty"`
}

type ProtoOncall struct {
	Id      uuid.UUID          `json:"id,omitempty"`
	Name    string             `json:"name,omitempty"`
	Number  string             `json:"number,omitempty"`
	Details ProtoOncallDetails `json:"details,omitempty"`
}

type ProtoOncallDetails struct {
	CreatedAt string   `json:"createdat,omitempty"`
	CreatedBy string   `json:"createdby,omitempty"`
	Members   []string `json:"members,omitempty"`
}

type ProtoOncallMember struct {
	UserName string    `json:"username,omitempty"`
	UserId   uuid.UUID `json"userid,omitempty"`
}

type ProtoOncallFilter struct {
	Name   string `json:"name,omitempty"`
	Number string `json:"number,omitempty"`
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd-benchmark/benchmark"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
	"github.com/lxc/lxd/shared/version"
)

var argCount = gnuflag.Int("count", 1, "Number of containers to create")
var argParallel = gnuflag.Int("parallel", -1, "Number of threads to use")
var argImage = gnuflag.String("image", "ubuntu:", "Image to use for the test")
var argPrivileged = gnuflag.Bool("privileged", false, "Use privileged containers")
var argStart = gnuflag.Bool("start", true, "Start the container after creation")
var argFreeze = gnuflag.Bool("freeze", false, "Freeze the container right after start")
var argReportFile = gnuflag.String("report-file", "", "A CSV file to write test file to. If the file is present, it will be appended to.")
var argReportLabel = gnuflag.String("report-label", "", "A label for the report entry. By default, the action is used.")

func main() {
	err := run(os.Args)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}

	os.Exit(0)
}

func run(args []string) error {
	// Parse command line
	// "spawn" is being deprecated, use "launch" instead.
	if len(os.Args) == 1 || !shared.StringInSlice(os.Args[1], []string{"launch", "spawn", "start", "stop", "delete"}) {
		if len(os.Args) > 1 && os.Args[1] == "--version" {
			fmt.Println(version.Version)
			return nil
		}

		out := os.Stderr
		if len(os.Args) > 1 && os.Args[1] == "--help" {
			out = os.Stdout
		}
		gnuflag.SetOut(out)

		fmt.Fprintf(out, "Usage: %s launch [--count=COUNT] [--image=IMAGE] [--privileged=BOOL] [--start=BOOL] [--freeze=BOOL] [--parallel=COUNT]\n", os.Args[0])
		fmt.Fprintf(out, "       %s start [--parallel=COUNT]\n", os.Args[0])
		fmt.Fprintf(out, "       %s stop [--parallel=COUNT]\n", os.Args[0])
		fmt.Fprintf(out, "       %s delete [--parallel=COUNT]\n\n", os.Args[0])
		gnuflag.PrintDefaults()
		fmt.Fprintf(out, "\n")

		if len(os.Args) > 1 && os.Args[1] == "--help" {
			return nil
		}

		return fmt.Errorf("A valid action (launch, start, stop, delete) must be passed.")
	}

	gnuflag.Parse(true)

	// Connect to LXD
	c, err := lxd.ConnectLXDUnix("", nil)
	if err != nil {
		return err
	}

	benchmark.PrintServerInfo(c)

	var report *benchmark.CSVReport
	if *argReportFile != "" {
		report = &benchmark.CSVReport{Filename: *argReportFile}
		if shared.PathExists(*argReportFile) {
			err := report.Load()
			if err != nil {
				return err
			}
		}
	}

	action := os.Args[1]
	var duration time.Duration
	switch action {
	// "spawn" is being deprecated.
	case "launch", "spawn":
		duration, err = benchmark.LaunchContainers(
			c, *argCount, *argParallel, *argImage, *argPrivileged, *argStart, *argFreeze)
		if err != nil {
			return err
		}
	case "start":
		containers, err := benchmark.GetContainers(c)
		if err != nil {
			return err
		}
		duration, err = benchmark.StartContainers(c, containers, *argParallel)
		if err != nil {
			return err
		}
	case "stop":
		containers, err := benchmark.GetContainers(c)
		if err != nil {
			return err
		}
		duration, err = benchmark.StopContainers(c, containers, *argParallel)
		if err != nil {
			return err
		}
	case "delete":
		containers, err := benchmark.GetContainers(c)
		if err != nil {
			return err
		}
		duration, err = benchmark.DeleteContainers(c, containers, *argParallel)
		if err != nil {
			return err
		}
	}

	if report != nil {
		label := action
		if *argReportLabel != "" {
			label = *argReportLabel
		}
		report.AddRecord(label, duration)
		err := report.Write()
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>lxd-benchmark: Fix golint<commit_after>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd-benchmark/benchmark"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
	"github.com/lxc/lxd/shared/version"
)

var argCount = gnuflag.Int("count", 1, "Number of containers to create")
var argParallel = gnuflag.Int("parallel", -1, "Number of threads to use")
var argImage = gnuflag.String("image", "ubuntu:", "Image to use for the test")
var argPrivileged = gnuflag.Bool("privileged", false, "Use privileged containers")
var argStart = gnuflag.Bool("start", true, "Start the container after creation")
var argFreeze = gnuflag.Bool("freeze", false, "Freeze the container right after start")
var argReportFile = gnuflag.String("report-file", "", "A CSV file to write test file to. If the file is present, it will be appended to.")
var argReportLabel = gnuflag.String("report-label", "", "A label for the report entry. By default, the action is used.")

func main() {
	err := run(os.Args)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %s\n", err)
		os.Exit(1)
	}

	os.Exit(0)
}

func run(args []string) error {
	// Parse command line
	// "spawn" is being deprecated, use "launch" instead.
	if len(os.Args) == 1 || !shared.StringInSlice(os.Args[1], []string{"launch", "spawn", "start", "stop", "delete"}) {
		if len(os.Args) > 1 && os.Args[1] == "--version" {
			fmt.Println(version.Version)
			return nil
		}

		out := os.Stderr
		if len(os.Args) > 1 && os.Args[1] == "--help" {
			out = os.Stdout
		}
		gnuflag.SetOut(out)

		fmt.Fprintf(out, "Usage: %s launch [--count=COUNT] [--image=IMAGE] [--privileged=BOOL] [--start=BOOL] [--freeze=BOOL] [--parallel=COUNT]\n", os.Args[0])
		fmt.Fprintf(out, "       %s start [--parallel=COUNT]\n", os.Args[0])
		fmt.Fprintf(out, "       %s stop [--parallel=COUNT]\n", os.Args[0])
		fmt.Fprintf(out, "       %s delete [--parallel=COUNT]\n\n", os.Args[0])
		gnuflag.PrintDefaults()
		fmt.Fprintf(out, "\n")

		if len(os.Args) > 1 && os.Args[1] == "--help" {
			return nil
		}

		return fmt.Errorf("A valid action (launch, start, stop, delete) must be passed")
	}

	gnuflag.Parse(true)

	// Connect to LXD
	c, err := lxd.ConnectLXDUnix("", nil)
	if err != nil {
		return err
	}

	benchmark.PrintServerInfo(c)

	var report *benchmark.CSVReport
	if *argReportFile != "" {
		report = &benchmark.CSVReport{Filename: *argReportFile}
		if shared.PathExists(*argReportFile) {
			err := report.Load()
			if err != nil {
				return err
			}
		}
	}

	action := os.Args[1]
	var duration time.Duration
	switch action {
	// "spawn" is being deprecated.
	case "launch", "spawn":
		duration, err = benchmark.LaunchContainers(
			c, *argCount, *argParallel, *argImage, *argPrivileged, *argStart, *argFreeze)
		if err != nil {
			return err
		}
	case "start":
		containers, err := benchmark.GetContainers(c)
		if err != nil {
			return err
		}
		duration, err = benchmark.StartContainers(c, containers, *argParallel)
		if err != nil {
			return err
		}
	case "stop":
		containers, err := benchmark.GetContainers(c)
		if err != nil {
			return err
		}
		duration, err = benchmark.StopContainers(c, containers, *argParallel)
		if err != nil {
			return err
		}
	case "delete":
		containers, err := benchmark.GetContainers(c)
		if err != nil {
			return err
		}
		duration, err = benchmark.DeleteContainers(c, containers, *argParallel)
		if err != nil {
			return err
		}
	}

	if report != nil {
		label := action
		if *argReportLabel != "" {
			label = *argReportLabel
		}
		report.AddRecord(label, duration)
		err := report.Write()
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/spf13/cobra"
)

/*
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

extern char* advance_arg(bool required);
extern void error(char *msg);
extern void attach_userns(int pid);
extern int dosetns(int pid, char *nstype);

int mkdir_p(const char *dir, mode_t mode)
{
	const char *tmp = dir;
	const char *orig = dir;
	char *makeme;

	do {
		dir = tmp + strspn(tmp, "/");
		tmp = dir + strcspn(dir, "/");
		makeme = strndup(orig, dir - orig);
		if (*makeme) {
			if (mkdir(makeme, mode) && errno != EEXIST) {
				fprintf(stderr, "failed to create directory '%s': %s\n", makeme, strerror(errno));
				free(makeme);
				return -1;
			}
		}
		free(makeme);
	} while(tmp != dir);

	return 0;
}

void ensure_dir(char *dest) {
	struct stat sb;
	if (stat(dest, &sb) == 0) {
		if ((sb.st_mode & S_IFMT) == S_IFDIR)
			return;
		if (unlink(dest) < 0) {
			fprintf(stderr, "Failed to remove old %s: %s\n", dest, strerror(errno));
			_exit(1);
		}
	}
	if (mkdir(dest, 0755) < 0) {
		fprintf(stderr, "Failed to mkdir %s: %s\n", dest, strerror(errno));
		_exit(1);
	}
}

void ensure_file(char *dest) {
	struct stat sb;
	int fd;

	if (stat(dest, &sb) == 0) {
		if ((sb.st_mode & S_IFMT) != S_IFDIR)
			return;
		if (rmdir(dest) < 0) {
			fprintf(stderr, "Failed to remove old %s: %s\n", dest, strerror(errno));
			_exit(1);
		}
	}

	fd = creat(dest, 0755);
	if (fd < 0) {
		fprintf(stderr, "Failed to mkdir %s: %s\n", dest, strerror(errno));
		_exit(1);
	}
	close(fd);
}

void create(char *src, char *dest) {
	char *dirdup;
	char *destdirname;

	struct stat sb;
	if (stat(src, &sb) < 0) {
		fprintf(stderr, "source %s does not exist\n", src);
		_exit(1);
	}

	dirdup = strdup(dest);
	if (!dirdup)
		_exit(1);

	destdirname = dirname(dirdup);

	if (mkdir_p(destdirname, 0755) < 0) {
		fprintf(stderr, "failed to create path: %s\n", destdirname);
		free(dirdup);
		_exit(1);
	}
	free(dirdup);

	switch (sb.st_mode & S_IFMT) {
	case S_IFDIR:
		ensure_dir(dest);
		return;
	default:
		ensure_file(dest);
		return;
	}
}

void forkdomount(pid_t pid) {
	char *src, *dest, *opts;

	attach_userns(pid);

	if (dosetns(pid, "mnt") < 0) {
		fprintf(stderr, "Failed setns to container mount namespace: %s\n", strerror(errno));
		_exit(1);
	}

	src = advance_arg(true);
	dest = advance_arg(true);

	create(src, dest);

	if (access(src, F_OK) < 0) {
		fprintf(stderr, "Mount source doesn't exist: %s\n", strerror(errno));
		_exit(1);
	}

	if (access(dest, F_OK) < 0) {
		fprintf(stderr, "Mount destination doesn't exist: %s\n", strerror(errno));
		_exit(1);
	}

	// Here, we always move recursively, because we sometimes allow
	// recursive mounts. If the mount has no kids then it doesn't matter,
	// but if it does, we want to move those too.
	if (mount(src, dest, "none", MS_MOVE | MS_REC, NULL) < 0) {
		fprintf(stderr, "Failed mounting %s onto %s: %s\n", src, dest, strerror(errno));
		_exit(1);
	}

	_exit(0);
}

void forkdoumount(pid_t pid) {
	char *path = NULL;

	if (dosetns(pid, "mnt") < 0) {
		fprintf(stderr, "Failed setns to container mount namespace: %s\n", strerror(errno));
		_exit(1);
	}

	path = advance_arg(true);
	if (access(path, F_OK) < 0) {
		fprintf(stderr, "Mount path doesn't exist: %s\n", strerror(errno));
		_exit(1);
	}

	if (umount2(path, MNT_DETACH) < 0) {
		fprintf(stderr, "Error unmounting %s: %s\n", path, strerror(errno));
		_exit(1);
	}
	_exit(0);
}

void forkmount() {
	char *cur = NULL;

	char *command = NULL;
	char *rootfs = NULL;
	pid_t pid = 0;

	// Get the subcommand
	command = advance_arg(false);
	if (command == NULL || (strcmp(command, "--help") == 0 || strcmp(command, "--version") == 0 || strcmp(command, "-h") == 0)) {
		return;
	}

	// Get the pid
	cur = advance_arg(false);
	if (cur == NULL || (strcmp(cur, "--help") == 0 || strcmp(cur, "--version") == 0 || strcmp(cur, "-h") == 0)) {
		return;
	}
	pid = atoi(cur);

	// Check that we're root
	if (geteuid() != 0) {
		fprintf(stderr, "Error: forkmount requires root privileges\n");
		_exit(1);
	}

	// Call the subcommands
	if (strcmp(command, "mount") == 0) {
		forkdomount(pid);
	} else if (strcmp(command, "umount") == 0) {
		forkdoumount(pid);
	}
}
*/
import "C"

type cmdForkmount struct {
	global *cmdGlobal
}

func (c *cmdForkmount) Command() *cobra.Command {
	// Main subcommand
	cmd := &cobra.Command{}
	cmd.Use = "forkmount"
	cmd.Short = "Perform mount operations"
	cmd.Long = `Description:
  Perform mount operations

  This set of internal commands are used for all container mount
  operations.
`
	cmd.Hidden = true

	// mount
	cmdMount := &cobra.Command{}
	cmdMount.Use = "mount <PID> <source> <destination>"
	cmdMount.Args = cobra.ExactArgs(3)
	cmdMount.RunE = c.Run
	cmd.AddCommand(cmdMount)

	// umount
	cmdUmount := &cobra.Command{}
	cmdUmount.Use = "umount <PID> <path>"
	cmdUmount.Args = cobra.ExactArgs(2)
	cmdUmount.RunE = c.Run
	cmd.AddCommand(cmdUmount)

	return cmd
}

func (c *cmdForkmount) Run(cmd *cobra.Command, args []string) error {
	return fmt.Errorf("This command should have been intercepted in cgo")
}
<commit_msg>forkmount: ignore ENOENT and EINVAL on umount2()<commit_after>package main

import (
	"fmt"

	"github.com/spf13/cobra"
)

/*
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

extern char* advance_arg(bool required);
extern void error(char *msg);
extern void attach_userns(int pid);
extern int dosetns(int pid, char *nstype);

int mkdir_p(const char *dir, mode_t mode)
{
	const char *tmp = dir;
	const char *orig = dir;
	char *makeme;

	do {
		dir = tmp + strspn(tmp, "/");
		tmp = dir + strcspn(dir, "/");
		makeme = strndup(orig, dir - orig);
		if (*makeme) {
			if (mkdir(makeme, mode) && errno != EEXIST) {
				fprintf(stderr, "failed to create directory '%s': %s\n", makeme, strerror(errno));
				free(makeme);
				return -1;
			}
		}
		free(makeme);
	} while(tmp != dir);

	return 0;
}

void ensure_dir(char *dest) {
	struct stat sb;
	if (stat(dest, &sb) == 0) {
		if ((sb.st_mode & S_IFMT) == S_IFDIR)
			return;
		if (unlink(dest) < 0) {
			fprintf(stderr, "Failed to remove old %s: %s\n", dest, strerror(errno));
			_exit(1);
		}
	}
	if (mkdir(dest, 0755) < 0) {
		fprintf(stderr, "Failed to mkdir %s: %s\n", dest, strerror(errno));
		_exit(1);
	}
}

void ensure_file(char *dest) {
	struct stat sb;
	int fd;

	if (stat(dest, &sb) == 0) {
		if ((sb.st_mode & S_IFMT) != S_IFDIR)
			return;
		if (rmdir(dest) < 0) {
			fprintf(stderr, "Failed to remove old %s: %s\n", dest, strerror(errno));
			_exit(1);
		}
	}

	fd = creat(dest, 0755);
	if (fd < 0) {
		fprintf(stderr, "Failed to mkdir %s: %s\n", dest, strerror(errno));
		_exit(1);
	}
	close(fd);
}

void create(char *src, char *dest) {
	char *dirdup;
	char *destdirname;

	struct stat sb;
	if (stat(src, &sb) < 0) {
		fprintf(stderr, "source %s does not exist\n", src);
		_exit(1);
	}

	dirdup = strdup(dest);
	if (!dirdup)
		_exit(1);

	destdirname = dirname(dirdup);

	if (mkdir_p(destdirname, 0755) < 0) {
		fprintf(stderr, "failed to create path: %s\n", destdirname);
		free(dirdup);
		_exit(1);
	}
	free(dirdup);

	switch (sb.st_mode & S_IFMT) {
	case S_IFDIR:
		ensure_dir(dest);
		return;
	default:
		ensure_file(dest);
		return;
	}
}

void forkdomount(pid_t pid) {
	char *src, *dest, *opts;

	attach_userns(pid);

	if (dosetns(pid, "mnt") < 0) {
		fprintf(stderr, "Failed setns to container mount namespace: %s\n", strerror(errno));
		_exit(1);
	}

	src = advance_arg(true);
	dest = advance_arg(true);

	create(src, dest);

	if (access(src, F_OK) < 0) {
		fprintf(stderr, "Mount source doesn't exist: %s\n", strerror(errno));
		_exit(1);
	}

	if (access(dest, F_OK) < 0) {
		fprintf(stderr, "Mount destination doesn't exist: %s\n", strerror(errno));
		_exit(1);
	}

	// Here, we always move recursively, because we sometimes allow
	// recursive mounts. If the mount has no kids then it doesn't matter,
	// but if it does, we want to move those too.
	if (mount(src, dest, "none", MS_MOVE | MS_REC, NULL) < 0) {
		fprintf(stderr, "Failed mounting %s onto %s: %s\n", src, dest, strerror(errno));
		_exit(1);
	}

	_exit(0);
}

void forkdoumount(pid_t pid) {
	int ret;
	char *path = NULL;

	ret = dosetns(pid, "mnt");
	if (ret < 0) {
		fprintf(stderr, "Failed to setns to container mount namespace: %s\n", strerror(errno));
		_exit(1);
	}

	path = advance_arg(true);

	ret = umount2(path, MNT_DETACH);
	if (ret < 0) {
		// - ENOENT: The user must have unmounted and removed the path.
		// - EINVAL: The user must have unmounted. Other explanations
		//           for EINVAL do not apply.
		if (errno == ENOENT || errno == EINVAL)
			_exit(0);

		fprintf(stderr, "Error unmounting %s: %s\n", path, strerror(errno));
		_exit(1);
	}

	_exit(0);
}

void forkmount() {
	char *cur = NULL;

	char *command = NULL;
	char *rootfs = NULL;
	pid_t pid = 0;

	// Get the subcommand
	command = advance_arg(false);
	if (command == NULL || (strcmp(command, "--help") == 0 || strcmp(command, "--version") == 0 || strcmp(command, "-h") == 0)) {
		return;
	}

	// Get the pid
	cur = advance_arg(false);
	if (cur == NULL || (strcmp(cur, "--help") == 0 || strcmp(cur, "--version") == 0 || strcmp(cur, "-h") == 0)) {
		return;
	}
	pid = atoi(cur);

	// Check that we're root
	if (geteuid() != 0) {
		fprintf(stderr, "Error: forkmount requires root privileges\n");
		_exit(1);
	}

	// Call the subcommands
	if (strcmp(command, "mount") == 0) {
		forkdomount(pid);
	} else if (strcmp(command, "umount") == 0) {
		forkdoumount(pid);
	}
}
*/
import "C"

type cmdForkmount struct {
	global *cmdGlobal
}

func (c *cmdForkmount) Command() *cobra.Command {
	// Main subcommand
	cmd := &cobra.Command{}
	cmd.Use = "forkmount"
	cmd.Short = "Perform mount operations"
	cmd.Long = `Description:
  Perform mount operations

  This set of internal commands are used for all container mount
  operations.
`
	cmd.Hidden = true

	// mount
	cmdMount := &cobra.Command{}
	cmdMount.Use = "mount <PID> <source> <destination>"
	cmdMount.Args = cobra.ExactArgs(3)
	cmdMount.RunE = c.Run
	cmd.AddCommand(cmdMount)

	// umount
	cmdUmount := &cobra.Command{}
	cmdUmount.Use = "umount <PID> <path>"
	cmdUmount.Args = cobra.ExactArgs(2)
	cmdUmount.RunE = c.Run
	cmd.AddCommand(cmdUmount)

	return cmd
}

func (c *cmdForkmount) Run(cmd *cobra.Command, args []string) error {
	return fmt.Errorf("This command should have been intercepted in cgo")
}
<|endoftext|>