<commit_before>/*
Copyright 2020 The cert-manager 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 vault

import (
	"crypto/x509"
	"errors"
	"fmt"
	"net/http"
	"path"
	"path/filepath"
	"strings"
	"time"

	vault "github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/sdk/helper/certutil"
	corelisters "k8s.io/client-go/listers/core/v1"

	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

var _ Interface = &Vault{}

// ClientBuilder is a function type that returns a new Interface.
// Can be used in tests to create a mock signer of Vault certificate requests.
type ClientBuilder func(namespace string, secretsLister corelisters.SecretLister,
	issuer v1.GenericIssuer) (Interface, error)

// Interface implements various high level functionality related to connecting
// with a Vault server, verifying its status and signing certificate request for
// Vault's certificate.
// TODO: Sys() is duplicated here and in Client interface
type Interface interface {
	Sign(csrPEM []byte, duration time.Duration) (certPEM []byte, caPEM []byte, err error)
	Sys() *vault.Sys
	IsVaultInitializedAndUnsealed() error
}

// Client implements functionality to talk to a Vault server.
type Client interface {
	NewRequest(method, requestPath string) *vault.Request
	RawRequest(r *vault.Request) (*vault.Response, error)
	SetToken(v string)
	Token() string
	Sys() *vault.Sys
}

// Vault implements Interface and holds a Vault issuer, secrets lister and a
// Vault client.
type Vault struct {
	secretsLister corelisters.SecretLister
	issuer        v1.GenericIssuer
	namespace     string

	client Client
}

// New returns a new Vault instance with the given namespace, issuer and
// secrets lister.
// Returned errors may be network failures and should be considered for
// retrying.
func New(namespace string, secretsLister corelisters.SecretLister, issuer v1.GenericIssuer) (Interface, error) {
	v := &Vault{
		secretsLister: secretsLister,
		namespace:     namespace,
		issuer:        issuer,
	}

	cfg, err := v.newConfig()
	if err != nil {
		return nil, err
	}

	client, err := vault.NewClient(cfg)
	if err != nil {
		return nil, fmt.Errorf("error initializing Vault client: %s", err.Error())
	}

	if err := v.setToken(client); err != nil {
		return nil, err
	}

	v.client = client

	return v, nil
}

// Sign will connect to a Vault instance to sign a certificate signing request.
func (v *Vault) Sign(csrPEM []byte, duration time.Duration) (cert []byte, ca []byte, err error) {
	csr, err := pki.DecodeX509CertificateRequestBytes(csrPEM)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode CSR for signing: %s", err)
	}

	parameters := map[string]string{
		"common_name": csr.Subject.CommonName,
		"alt_names":   strings.Join(csr.DNSNames, ","),
		"ip_sans":     strings.Join(pki.IPAddressesToString(csr.IPAddresses), ","),
		"uri_sans":    strings.Join(pki.URLsToString(csr.URIs), ","),
		"ttl":         duration.String(),
		"csr":         string(csrPEM),

		"exclude_cn_from_sans": "true",
	}

	vaultIssuer := v.issuer.GetSpec().Vault
	url := path.Join("/v1", vaultIssuer.Path)

	request := v.client.NewRequest("POST", url)

	v.addVaultNamespaceToRequest(request)

	if err := request.SetJSONBody(parameters); err != nil {
		return nil, nil, fmt.Errorf("failed to build vault request: %s", err)
	}

	resp, err := v.client.RawRequest(request)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to sign certificate by vault: %s", err)
	}

	defer resp.Body.Close()

	vaultResult := certutil.Secret{}
	err = resp.DecodeJSON(&vaultResult)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode response returned by vault: %s", err)
	}

	return extractCertificatesFromVaultCertificateSecret(&vaultResult)
}

func (v *Vault) setToken(client Client) error {
	tokenRef := v.issuer.GetSpec().Vault.Auth.TokenSecretRef
	if tokenRef != nil {
		token, err := v.tokenRef(tokenRef.Name, v.namespace, tokenRef.Key)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	appRole := v.issuer.GetSpec().Vault.Auth.AppRole
	if appRole != nil {
		token, err := v.requestTokenWithAppRoleRef(client, appRole)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	kubernetesAuth := v.issuer.GetSpec().Vault.Auth.Kubernetes
	if kubernetesAuth != nil {
		token, err := v.requestTokenWithKubernetesAuth(client, kubernetesAuth)
		if err != nil {
			return fmt.Errorf("error reading Kubernetes service account token from %s: %s", kubernetesAuth.SecretRef.Name, err.Error())
		}
		client.SetToken(token)
		return nil
	}

	return fmt.Errorf("error initializing Vault client: tokenSecretRef, appRoleSecretRef, or Kubernetes auth role not set")
}

func (v *Vault) newConfig() (*vault.Config, error) {
	cfg := vault.DefaultConfig()
	cfg.Address = v.issuer.GetSpec().Vault.Server

	certs := v.issuer.GetSpec().Vault.CABundle
	if len(certs) == 0 {
		return cfg, nil
	}

	caCertPool := x509.NewCertPool()
	ok := caCertPool.AppendCertsFromPEM(certs)
	if !ok {
		return nil, fmt.Errorf("error loading Vault CA bundle")
	}

	cfg.HttpClient.Transport.(*http.Transport).TLSClientConfig.RootCAs = caCertPool

	return cfg, nil
}

func (v *Vault) tokenRef(name, namespace, key string) (string, error) {
	secret, err := v.secretsLister.Secrets(namespace).Get(name)
	if err != nil {
		return "", err
	}

	if key == "" {
		key = v1.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, name, namespace)
	}

	token := string(keyBytes)
	token = strings.TrimSpace(token)

	return token, nil
}

func (v *Vault) appRoleRef(appRole *v1.VaultAppRole) (roleId, secretId string, err error) {
	roleId = strings.TrimSpace(appRole.RoleId)

	secret, err := v.secretsLister.Secrets(v.namespace).Get(appRole.SecretRef.Name)
	if err != nil {
		return "", "", err
	}

	key := appRole.SecretRef.Key

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, appRole.SecretRef.Name)
	}

	secretId = string(keyBytes)
	secretId = strings.TrimSpace(secretId)

	return roleId, secretId, nil
}

func (v *Vault) requestTokenWithAppRoleRef(client Client, appRole *v1.VaultAppRole) (string, error) {
	roleId, secretId, err := v.appRoleRef(appRole)
	if err != nil {
		return "", err
	}

	parameters := map[string]string{
		"role_id":   roleId,
		"secret_id": secretId,
	}

	authPath := appRole.Path
	if authPath == "" {
		authPath = "approle"
	}

	url := path.Join("/v1", "auth", authPath, "login")

	request := client.NewRequest("POST", url)

	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	v.addVaultNamespaceToRequest(request)

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error logging in to Vault server: %s", err.Error())
	}

	defer resp.Body.Close()

	vaultResult := vault.Secret{}
	if err := resp.DecodeJSON(&vaultResult); err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	if token == "" {
		return "", errors.New("no token returned")
	}

	return token, nil
}

func (v *Vault) requestTokenWithKubernetesAuth(client Client, kubernetesAuth *v1.VaultKubernetesAuth) (string, error) {
	secret, err := v.secretsLister.Secrets(v.namespace).Get(kubernetesAuth.SecretRef.Name)
	if err != nil {
		return "", err
	}

	key := kubernetesAuth.SecretRef.Key
	if key == "" {
		key = v1.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, kubernetesAuth.SecretRef.Name)
	}

	jwt := string(keyBytes)

	parameters := map[string]string{
		"role": kubernetesAuth.Role,
		"jwt":  jwt,
	}

	mountPath := kubernetesAuth.Path
	if mountPath == "" {
		mountPath = v1.DefaultVaultKubernetesAuthMountPath
	}

	url := filepath.Join(mountPath, "login")
	request := client.NewRequest("POST", url)
	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	v.addVaultNamespaceToRequest(request)

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error calling Vault server: %s", err.Error())
	}

	defer resp.Body.Close()
	vaultResult := vault.Secret{}
	err = resp.DecodeJSON(&vaultResult)
	if err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	return token, nil
}

func (v *Vault) Sys() *vault.Sys {
	return v.client.Sys()
}

func extractCertificatesFromVaultCertificateSecret(secret *certutil.Secret) ([]byte, []byte, error) {
	parsedBundle, err := certutil.ParsePKIMap(secret.Data)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode response returned by vault: %s", err)
	}

	vbundle, err := parsedBundle.ToCertBundle()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to convert certificate bundle to PEM bundle: %s", err.Error())
	}

	bundle, err := pki.ParseSingleCertificateChainPEM([]byte(
		strings.Join(append(
			vbundle.CAChain,
			vbundle.IssuingCA,
			vbundle.Certificate,
		), "\n")))
	if err != nil {
		return nil, nil, fmt.Errorf("failed to parse certificate chain from vault: %w", err)
	}

	return bundle.ChainPEM, bundle.CAPEM, nil
}

func (v *Vault) IsVaultInitializedAndUnsealed() error {
	healthURL := path.Join("/v1", "sys", "health")
	healthRequest := v.client.NewRequest("GET", healthURL)
	healthResp, err := v.client.RawRequest(healthRequest)
	// 429 = if unsealed and standby
	// 472 = if disaster recovery mode replication secondary and active
	// 473 = if performance standby
	if err != nil && healthResp.StatusCode != 429 && healthResp.StatusCode != 472 && healthResp.StatusCode != 473 {
		return err
	}
	defer healthResp.Body.Close()
	return nil
}

func (v *Vault) addVaultNamespaceToRequest(request *vault.Request) {
	vaultIssuer := v.issuer.GetSpec().Vault
	if vaultIssuer != nil && vaultIssuer.Namespace != "" {
		if request.Headers != nil {
			request.Headers.Add("X-VAULT-NAMESPACE", vaultIssuer.Namespace)
		} else {
			vaultReqHeaders := http.Header{}
			vaultReqHeaders.Add("X-VAULT-NAMESPACE", vaultIssuer.Namespace)
			request.Headers = vaultReqHeaders
		}
	}
}
<commit_msg>Vault internal client should check health conn err before checking response status<commit_after>/*
Copyright 2020 The cert-manager 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 vault

import (
	"crypto/x509"
	"errors"
	"fmt"
	"net/http"
	"path"
	"path/filepath"
	"strings"
	"time"

	vault "github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/sdk/helper/certutil"
	corelisters "k8s.io/client-go/listers/core/v1"

	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	"github.com/jetstack/cert-manager/pkg/util/pki"
)

var _ Interface = &Vault{}

// ClientBuilder is a function type that returns a new Interface.
// Can be used in tests to create a mock signer of Vault certificate requests.
type ClientBuilder func(namespace string, secretsLister corelisters.SecretLister,
	issuer v1.GenericIssuer) (Interface, error)

// Interface implements various high level functionality related to connecting
// with a Vault server, verifying its status and signing certificate request for
// Vault's certificate.
// TODO: Sys() is duplicated here and in Client interface
type Interface interface {
	Sign(csrPEM []byte, duration time.Duration) (certPEM []byte, caPEM []byte, err error)
	Sys() *vault.Sys
	IsVaultInitializedAndUnsealed() error
}

// Client implements functionality to talk to a Vault server.
type Client interface {
	NewRequest(method, requestPath string) *vault.Request
	RawRequest(r *vault.Request) (*vault.Response, error)
	SetToken(v string)
	Token() string
	Sys() *vault.Sys
}

// Vault implements Interface and holds a Vault issuer, secrets lister and a
// Vault client.
type Vault struct {
	secretsLister corelisters.SecretLister
	issuer        v1.GenericIssuer
	namespace     string

	client Client
}

// New returns a new Vault instance with the given namespace, issuer and
// secrets lister.
// Returned errors may be network failures and should be considered for
// retrying.
func New(namespace string, secretsLister corelisters.SecretLister, issuer v1.GenericIssuer) (Interface, error) {
	v := &Vault{
		secretsLister: secretsLister,
		namespace:     namespace,
		issuer:        issuer,
	}

	cfg, err := v.newConfig()
	if err != nil {
		return nil, err
	}

	client, err := vault.NewClient(cfg)
	if err != nil {
		return nil, fmt.Errorf("error initializing Vault client: %s", err.Error())
	}

	if err := v.setToken(client); err != nil {
		return nil, err
	}

	v.client = client

	return v, nil
}

// Sign will connect to a Vault instance to sign a certificate signing request.
func (v *Vault) Sign(csrPEM []byte, duration time.Duration) (cert []byte, ca []byte, err error) {
	csr, err := pki.DecodeX509CertificateRequestBytes(csrPEM)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode CSR for signing: %s", err)
	}

	parameters := map[string]string{
		"common_name": csr.Subject.CommonName,
		"alt_names":   strings.Join(csr.DNSNames, ","),
		"ip_sans":     strings.Join(pki.IPAddressesToString(csr.IPAddresses), ","),
		"uri_sans":    strings.Join(pki.URLsToString(csr.URIs), ","),
		"ttl":         duration.String(),
		"csr":         string(csrPEM),

		"exclude_cn_from_sans": "true",
	}

	vaultIssuer := v.issuer.GetSpec().Vault
	url := path.Join("/v1", vaultIssuer.Path)

	request := v.client.NewRequest("POST", url)

	v.addVaultNamespaceToRequest(request)

	if err := request.SetJSONBody(parameters); err != nil {
		return nil, nil, fmt.Errorf("failed to build vault request: %s", err)
	}

	resp, err := v.client.RawRequest(request)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to sign certificate by vault: %s", err)
	}

	defer resp.Body.Close()

	vaultResult := certutil.Secret{}
	err = resp.DecodeJSON(&vaultResult)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode response returned by vault: %s", err)
	}

	return extractCertificatesFromVaultCertificateSecret(&vaultResult)
}

func (v *Vault) setToken(client Client) error {
	tokenRef := v.issuer.GetSpec().Vault.Auth.TokenSecretRef
	if tokenRef != nil {
		token, err := v.tokenRef(tokenRef.Name, v.namespace, tokenRef.Key)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	appRole := v.issuer.GetSpec().Vault.Auth.AppRole
	if appRole != nil {
		token, err := v.requestTokenWithAppRoleRef(client, appRole)
		if err != nil {
			return err
		}
		client.SetToken(token)

		return nil
	}

	kubernetesAuth := v.issuer.GetSpec().Vault.Auth.Kubernetes
	if kubernetesAuth != nil {
		token, err := v.requestTokenWithKubernetesAuth(client, kubernetesAuth)
		if err != nil {
			return fmt.Errorf("error reading Kubernetes service account token from %s: %s", kubernetesAuth.SecretRef.Name, err.Error())
		}
		client.SetToken(token)
		return nil
	}

	return fmt.Errorf("error initializing Vault client: tokenSecretRef, appRoleSecretRef, or Kubernetes auth role not set")
}

func (v *Vault) newConfig() (*vault.Config, error) {
	cfg := vault.DefaultConfig()
	cfg.Address = v.issuer.GetSpec().Vault.Server

	certs := v.issuer.GetSpec().Vault.CABundle
	if len(certs) == 0 {
		return cfg, nil
	}

	caCertPool := x509.NewCertPool()
	ok := caCertPool.AppendCertsFromPEM(certs)
	if !ok {
		return nil, fmt.Errorf("error loading Vault CA bundle")
	}

	cfg.HttpClient.Transport.(*http.Transport).TLSClientConfig.RootCAs = caCertPool

	return cfg, nil
}

func (v *Vault) tokenRef(name, namespace, key string) (string, error) {
	secret, err := v.secretsLister.Secrets(namespace).Get(name)
	if err != nil {
		return "", err
	}

	if key == "" {
		key = v1.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, name, namespace)
	}

	token := string(keyBytes)
	token = strings.TrimSpace(token)

	return token, nil
}

func (v *Vault) appRoleRef(appRole *v1.VaultAppRole) (roleId, secretId string, err error) {
	roleId = strings.TrimSpace(appRole.RoleId)

	secret, err := v.secretsLister.Secrets(v.namespace).Get(appRole.SecretRef.Name)
	if err != nil {
		return "", "", err
	}

	key := appRole.SecretRef.Key

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, appRole.SecretRef.Name)
	}

	secretId = string(keyBytes)
	secretId = strings.TrimSpace(secretId)

	return roleId, secretId, nil
}

func (v *Vault) requestTokenWithAppRoleRef(client Client, appRole *v1.VaultAppRole) (string, error) {
	roleId, secretId, err := v.appRoleRef(appRole)
	if err != nil {
		return "", err
	}

	parameters := map[string]string{
		"role_id":   roleId,
		"secret_id": secretId,
	}

	authPath := appRole.Path
	if authPath == "" {
		authPath = "approle"
	}

	url := path.Join("/v1", "auth", authPath, "login")

	request := client.NewRequest("POST", url)

	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	v.addVaultNamespaceToRequest(request)

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error logging in to Vault server: %s", err.Error())
	}

	defer resp.Body.Close()

	vaultResult := vault.Secret{}
	if err := resp.DecodeJSON(&vaultResult); err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	if token == "" {
		return "", errors.New("no token returned")
	}

	return token, nil
}

func (v *Vault) requestTokenWithKubernetesAuth(client Client, kubernetesAuth *v1.VaultKubernetesAuth) (string, error) {
	secret, err := v.secretsLister.Secrets(v.namespace).Get(kubernetesAuth.SecretRef.Name)
	if err != nil {
		return "", err
	}

	key := kubernetesAuth.SecretRef.Key
	if key == "" {
		key = v1.DefaultVaultTokenAuthSecretKey
	}

	keyBytes, ok := secret.Data[key]
	if !ok {
		return "", fmt.Errorf("no data for %q in secret '%s/%s'", key, v.namespace, kubernetesAuth.SecretRef.Name)
	}

	jwt := string(keyBytes)

	parameters := map[string]string{
		"role": kubernetesAuth.Role,
		"jwt":  jwt,
	}

	mountPath := kubernetesAuth.Path
	if mountPath == "" {
		mountPath = v1.DefaultVaultKubernetesAuthMountPath
	}

	url := filepath.Join(mountPath, "login")
	request := client.NewRequest("POST", url)
	err = request.SetJSONBody(parameters)
	if err != nil {
		return "", fmt.Errorf("error encoding Vault parameters: %s", err.Error())
	}

	v.addVaultNamespaceToRequest(request)

	resp, err := client.RawRequest(request)
	if err != nil {
		return "", fmt.Errorf("error calling Vault server: %s", err.Error())
	}

	defer resp.Body.Close()
	vaultResult := vault.Secret{}
	err = resp.DecodeJSON(&vaultResult)
	if err != nil {
		return "", fmt.Errorf("unable to decode JSON payload: %s", err.Error())
	}

	token, err := vaultResult.TokenID()
	if err != nil {
		return "", fmt.Errorf("unable to read token: %s", err.Error())
	}

	return token, nil
}

func (v *Vault) Sys() *vault.Sys {
	return v.client.Sys()
}

func extractCertificatesFromVaultCertificateSecret(secret *certutil.Secret) ([]byte, []byte, error) {
	parsedBundle, err := certutil.ParsePKIMap(secret.Data)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to decode response returned by vault: %s", err)
	}

	vbundle, err := parsedBundle.ToCertBundle()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to convert certificate bundle to PEM bundle: %s", err.Error())
	}

	bundle, err := pki.ParseSingleCertificateChainPEM([]byte(
		strings.Join(append(
			vbundle.CAChain,
			vbundle.IssuingCA,
			vbundle.Certificate,
		), "\n")))
	if err != nil {
		return nil, nil, fmt.Errorf("failed to parse certificate chain from vault: %w", err)
	}

	return bundle.ChainPEM, bundle.CAPEM, nil
}

func (v *Vault) IsVaultInitializedAndUnsealed() error {
	healthURL := path.Join("/v1", "sys", "health")
	healthRequest := v.client.NewRequest("GET", healthURL)
	healthResp, err := v.client.RawRequest(healthRequest)

	if healthResp != nil {
		defer healthResp.Body.Close()
	}

	// 429 = if unsealed and standby
	// 472 = if disaster recovery mode replication secondary and active
	// 473 = if performance standby
	if err != nil {
		switch {
		case healthResp == nil:
			return err
		case healthResp.StatusCode == 429, healthResp.StatusCode == 472, healthResp.StatusCode == 473:
			return nil
		default:
			return fmt.Errorf("error calling Vault %s: %w", healthURL, err)
		}
	}

	return nil
}

func (v *Vault) addVaultNamespaceToRequest(request *vault.Request) {
	vaultIssuer := v.issuer.GetSpec().Vault
	if vaultIssuer != nil && vaultIssuer.Namespace != "" {
		if request.Headers != nil {
			request.Headers.Add("X-VAULT-NAMESPACE", vaultIssuer.Namespace)
		} else {
			vaultReqHeaders := http.Header{}
			vaultReqHeaders.Add("X-VAULT-NAMESPACE", vaultIssuer.Namespace)
			request.Headers = vaultReqHeaders
		}
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"strings"

	"github.com/nextgearcapital/pepper/pkg/device42"
	"github.com/nextgearcapital/pepper/pkg/log"
	"github.com/nextgearcapital/pepper/pkg/salt"
	"github.com/nextgearcapital/pepper/template/vsphere"

	"github.com/spf13/cobra"
)

var (
	profile    string
	roles      string
	osTemplate string
	ipam       bool
)

func init() {
	RootCmd.AddCommand(deployCmd)

	deployCmd.Flags().StringVarP(&profile, "profile", "p", "", "Profile to generate and output to /etc/salt/cloud.profiles.d for salt-cloud to use")
	deployCmd.Flags().StringVarP(&roles, "roles", "r", "", "List of roles to assign to the host in D42 [eg: dcos,dcos-master]")
	deployCmd.Flags().StringVarP(&osTemplate, "template", "t", "", "Which OS template you want to use [eg: Ubuntu, CentOS, someothertemplatename]")
	deployCmd.Flags().BoolVarP(&ipam, "no-ipam", "", false, "Whether or not to use Device42 IPAM [This is only used internally]")
	deployCmd.Flags().BoolVarP(&log.IsDebugging, "debug", "d", false, "Turn debugging on")
}

var deployCmd = &cobra.Command{
	Use:   "deploy",
	Short: "Deploy VM's via salt-cloud",
	Long: `pepper is a wrapper around salt-cloud that will generate salt-cloud profiles based on information you provide in profile configs.
Profile configs live in "/etc/pepper/config.d/{platform}/{environment}. Pepper is opinionated and looks at the profile you pass in as it's source
of truth. For example: If you pass in "vmware-dev-large" as the profile, it will look for your profile config in "/etc/pepper/config.d/vmware/large.yaml".
This allows for maximum flexibility due to the fact that everyone has different environments and may have some sort of naming scheme associated with them
so Pepper makes no assumptions on that. Pepper does however make assumptions on your instance type. [eg: nano, micro, small, medium, etc] Although these
options are available to you, you are free to override them as you see fit.
For example:

Provision new host web01 (Ubuntu) in the dev environment from the nano profile using vmware as a provider:

$ pepper deploy -p vmware-dev-nano -t Ubuntu web01

Or alternatively:

$ pepper deploy --profile vmware-dev-nano --template Ubuntu web01

Provision new host web02 (CentOS) in the prd environment from the large profile using vmware as a provider:

$ pepper deploy -p vmware-prd-large -t CentOS web02

Provision new host web03 (Ubuntu) in the uat environment from the hyper profile using vmware as a provider:

$ pepper deploy -p vmware-uat-hyper -t Ubuntu web03

Are you getting this yet?

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r dcos,dcos-master dcos01 dcos02 dcos03`,
	Run: func(cmd *cobra.Command, args []string) {
		if profile == "" {
			log.Die("You didn't specify a profile.")
		} else if osTemplate == "" {
			log.Die("You didn't specify an OS template.")
		} else if len(args) == 0 {
			log.Die("You didn't specify any hosts.")
		}

		splitProfile := strings.Split(profile, "-")

		// These will be the basis for how the profile gets generated.
		platform := splitProfile[0]
		environment := splitProfile[1]
		instancetype := splitProfile[2]

		// Nothing really gained here it just makes the code more readable.
		hosts := args

		var ipAddress string
		var serviceLevel string

		for _, host := range hosts {
			if ipam != true {
				if err := device42.ReadConfig(environment); err != nil {
					log.Die("%s", err)
				}
				// Get a new IP
				newIP, err := device42.GetNextIP(device42.IPRange)
				if err != nil {
					log.Die("%s", err)
				}
				ipAddress = newIP
				// Create the Device
				if err := device42.CreateDevice(host, serviceLevel); err != nil {
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Reserve IP
				if err := device42.ReserveIP(newIP, host); err != nil {
					if err = device42.CleanDeviceAndIP(newIP, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Update custom fields
				if err := device42.UpdateCustomFields(host, "roles", roles); err != nil {
					if err = device42.CleanDeviceAndIP(newIP, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
			}
			switch platform {
			case "vmware":
				var vsphere vsphere.ProfileConfig
				if err := vsphere.Prepare(platform, environment, instancetype, osTemplate, ipAddress); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Generate(); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := salt.Provision(profile, host); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Remove(); err != nil {
					log.Die("%s", err)
				}
			default:
				log.Die("I don't recognize this platform!")
			}
		}
	},
}
<commit_msg>Keep variable consistent<commit_after>package cmd

import (
	"strings"

	"github.com/nextgearcapital/pepper/pkg/device42"
	"github.com/nextgearcapital/pepper/pkg/log"
	"github.com/nextgearcapital/pepper/pkg/salt"
	"github.com/nextgearcapital/pepper/template/vsphere"

	"github.com/spf13/cobra"
)

var (
	profile    string
	roles      string
	osTemplate string
	ipam       bool
)

func init() {
	RootCmd.AddCommand(deployCmd)

	deployCmd.Flags().StringVarP(&profile, "profile", "p", "", "Profile to generate and output to /etc/salt/cloud.profiles.d for salt-cloud to use")
	deployCmd.Flags().StringVarP(&roles, "roles", "r", "", "List of roles to assign to the host in D42 [eg: dcos,dcos-master]")
	deployCmd.Flags().StringVarP(&osTemplate, "template", "t", "", "Which OS template you want to use [eg: Ubuntu, CentOS, someothertemplatename]")
	deployCmd.Flags().BoolVarP(&ipam, "no-ipam", "", false, "Whether or not to use Device42 IPAM [This is only used internally]")
	deployCmd.Flags().BoolVarP(&log.IsDebugging, "debug", "d", false, "Turn debugging on")
}

var deployCmd = &cobra.Command{
	Use:   "deploy",
	Short: "Deploy VM's via salt-cloud",
	Long: `pepper is a wrapper around salt-cloud that will generate salt-cloud profiles based on information you provide in profile configs.
Profile configs live in "/etc/pepper/config.d/{platform}/{environment}. Pepper is opinionated and looks at the profile you pass in as it's source
of truth. For example: If you pass in "vmware-dev-large" as the profile, it will look for your profile config in "/etc/pepper/config.d/vmware/large.yaml".
This allows for maximum flexibility due to the fact that everyone has different environments and may have some sort of naming scheme associated with them
so Pepper makes no assumptions on that. Pepper does however make assumptions on your instance type. [eg: nano, micro, small, medium, etc] Although these
options are available to you, you are free to override them as you see fit.
For example:

Provision new host web01 (Ubuntu) in the dev environment from the nano profile using vmware as a provider:

$ pepper deploy -p vmware-dev-nano -t Ubuntu web01

Or alternatively:

$ pepper deploy --profile vmware-dev-nano --template Ubuntu web01

Provision new host web02 (CentOS) in the prd environment from the large profile using vmware as a provider:

$ pepper deploy -p vmware-prd-large -t CentOS web02

Provision new host web03 (Ubuntu) in the uat environment from the hyper profile using vmware as a provider:

$ pepper deploy -p vmware-uat-hyper -t Ubuntu web03

Are you getting this yet?

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r dcos,dcos-master dcos01 dcos02 dcos03`,
	Run: func(cmd *cobra.Command, args []string) {
		if profile == "" {
			log.Die("You didn't specify a profile.")
		} else if osTemplate == "" {
			log.Die("You didn't specify an OS template.")
		} else if len(args) == 0 {
			log.Die("You didn't specify any hosts.")
		}

		splitProfile := strings.Split(profile, "-")

		// These will be the basis for how the profile gets generated.
		platform := splitProfile[0]
		environment := splitProfile[1]
		instancetype := splitProfile[2]

		// Nothing really gained here it just makes the code more readable.
		hosts := args

		var ipAddress string
		var serviceLevel string

		for _, host := range hosts {
			if ipam != true {
				if err := device42.ReadConfig(environment); err != nil {
					log.Die("%s", err)
				}
				// Get a new IP
				newIP, err := device42.GetNextIP(device42.IPRange)
				if err != nil {
					log.Die("%s", err)
				}
				ipAddress = newIP
				// Create the Device
				if err := device42.CreateDevice(host, serviceLevel); err != nil {
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Reserve IP
				if err := device42.ReserveIP(ipAddress, host); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Update custom fields
				if err := device42.UpdateCustomFields(host, "roles", roles); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
			}
			switch platform {
			case "vmware":
				var vsphere vsphere.ProfileConfig
				if err := vsphere.Prepare(platform, environment, instancetype, osTemplate, ipAddress); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Generate(); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := salt.Provision(profile, host); err != nil {
					if err = device42.CleanDeviceAndIP(ipAddress, host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Remove(); err != nil {
					log.Die("%s", err)
				}
			default:
				log.Die("I don't recognize this platform!")
			}
		}
	},
}
<|endoftext|>


<commit_before>package lwcache

import (
	"errors"
	"fmt"
	"testing"
	"time"

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

func TestSetAndGet(t *testing.T) {
	assert := assert.New(t)
	c := New("test-1")

	key := "test-1"
	expect := "test-1-value"

	c.Set(key, expect, 500*time.Millisecond)
	actual, ok := c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)

	// after expire
	time.Sleep(550 * time.Millisecond)
	actual, ok = c.Get(key)
	assert.False(ok)
	assert.Equal(nil, actual)
}

func TestSetExpire(t *testing.T) {
	assert := assert.New(t)
	c := New("test-2")

	key := "test-2"
	expect := "test-1-value"

	c.Set(key, expect, 500*time.Millisecond)
	actual, ok := c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)

	c.SetExpire(key, 1*time.Second)
	// after first expiration
	time.Sleep(550 * time.Millisecond)
	actual, ok = c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)
}

func TestSetRefresher(t *testing.T) {
	assert := assert.New(t)
	c := New("test-4")

	key := "test-4"
	expect := 0
	refresher := func(c Cache, key interface{}, currentValue interface{}) (interface{}, error) {
		num, ok := currentValue.(int)
		if ok {
			return num + 1, nil
		}
		return 0, errors.New("refresh failed")
	}

	c.Set(key, expect, 10*time.Second)
	c.SetRefresher(refresher)
	c.StartRefresher(key, 1*time.Second)

	for i := 0; i < 5; i++ {
		actual, ok := c.Get(key)
		assert.True(ok)
		assert.Equal(expect, actual, fmt.Sprintf("Test No. %d", i+1))
		time.Sleep(1050 * time.Millisecond)
		expect++
	}
}

func TestSetRefresher_OnExpired(t *testing.T) {
	assert := assert.New(t)
	c := New("test-5")

	key := "test-5"
	expect := 0
	refresher := func(c Cache, key interface{}, currentValue interface{}) (interface{}, error) {
		num, ok := currentValue.(int)
		if ok {
			return num + 1, nil
		}
		return 0, errors.New("refresh failed")
	}

	c.Set(key, expect, 2*time.Second)
	c.SetRefresher(refresher)
	c.StartRefresher(key, 1*time.Second)

	actual, ok := c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)
	time.Sleep(1500 * time.Millisecond)

	// refresh
	actual, ok = c.Get(key)
	assert.True(ok)
	assert.Equal(expect+1, actual)
	time.Sleep(1500 * time.Millisecond)

	// expire
	actual, ok = c.Get(key)
	assert.False(ok)
	assert.Equal(nil, actual)
}

func TestSetRefresher_OnRefreshError(t *testing.T) {
	assert := assert.New(t)
	c := New("test-3")

	key := "test-3"
	expect := 0
	refresher := func(c Cache, key interface{}, currentValue interface{}) (interface{}, error) {
		return 0, errors.New("refresh failed")
	}

	c.Set(key, expect, 10*time.Second)
	c.SetRefresher(refresher)
	c.StartRefresher(key, 1*time.Second)

	for i := 0; i < 5; i++ {
		actual, ok := c.Get(key)
		assert.True(ok)
		assert.Equal(expect, actual, fmt.Sprintf("Test No. %d", i+1))
		time.Sleep(1050 * time.Millisecond)
	}
}
<commit_msg>modify test<commit_after>package lwcache

import (
	"errors"
	"fmt"
	"testing"
	"time"

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

func TestSetAndGet(t *testing.T) {
	assert := assert.New(t)
	c := New("test-1")

	key := "test-1"
	expect := "test-1-value"

	c.Set(key, expect, 500*time.Millisecond)
	actual, ok := c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)

	// after expire
	time.Sleep(550 * time.Millisecond)
	actual, ok = c.Get(key)
	assert.False(ok)
	assert.Equal(nil, actual)
}

func TestSetExpire(t *testing.T) {
	assert := assert.New(t)
	c := New("test-2")

	key := "test-2"
	expect := "test-1-value"

	c.Set(key, expect, 500*time.Millisecond)
	actual, ok := c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)

	c.SetExpire(key, 1*time.Second)
	// after first expiration
	time.Sleep(550 * time.Millisecond)
	actual, ok = c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)
}

func TestSetRefresher(t *testing.T) {
	assert := assert.New(t)
	c := New("test-4")

	key := "test-4"
	expect := 0
	refresher := func(c Cache, key interface{}, currentValue interface{}) (interface{}, error) {
		num, ok := currentValue.(int)
		if ok {
			return num + 1, nil
		}
		return 0, errors.New("refresh failed")
	}

	c.Set(key, expect, 10*time.Second)
	c.SetRefresher(refresher)
	c.StartRefresher(key, 1*time.Second)

	for i := 0; i < 5; i++ {
		actual, ok := c.Get(key)
		assert.True(ok)
		assert.Equal(expect, actual, fmt.Sprintf("Test No. %d", i+1))
		time.Sleep(1050 * time.Millisecond)
		expect++
	}

	c.StopRefresher(key)
	for i := 0; i < 2; i++ {
		time.Sleep(1050 * time.Millisecond)
		actual, ok := c.Get(key)
		assert.True(ok)
		assert.Equal(expect, actual) // expect not changed
	}
}

func TestSetRefresher_OnExpired(t *testing.T) {
	assert := assert.New(t)
	c := New("test-5")

	key := "test-5"
	expect := 0
	refresher := func(c Cache, key interface{}, currentValue interface{}) (interface{}, error) {
		num, ok := currentValue.(int)
		if ok {
			return num + 1, nil
		}
		return 0, errors.New("refresh failed")
	}

	c.Set(key, expect, 2*time.Second)
	c.SetRefresher(refresher)
	c.StartRefresher(key, 1*time.Second)

	actual, ok := c.Get(key)
	assert.True(ok)
	assert.Equal(expect, actual)
	time.Sleep(1500 * time.Millisecond)

	// refresh
	actual, ok = c.Get(key)
	assert.True(ok)
	assert.Equal(expect+1, actual)
	time.Sleep(1500 * time.Millisecond)

	// expire
	actual, ok = c.Get(key)
	assert.False(ok)
	assert.Equal(nil, actual)
}

func TestSetRefresher_OnRefreshError(t *testing.T) {
	assert := assert.New(t)
	c := New("test-3")

	key := "test-3"
	expect := 0
	refresher := func(c Cache, key interface{}, currentValue interface{}) (interface{}, error) {
		return 0, errors.New("refresh failed")
	}

	c.Set(key, expect, 10*time.Second)
	c.SetRefresher(refresher)
	c.StartRefresher(key, 1*time.Second)

	for i := 0; i < 5; i++ {
		actual, ok := c.Get(key)
		assert.True(ok)
		assert.Equal(expect, actual, fmt.Sprintf("Test No. %d", i+1))
		time.Sleep(1050 * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>package chip8

import "testing"

func checkHex(t *testing.T, subject string, got, want uint16) {
	if got != want {
		t.Errorf("%s => 0x%04X; want 0x%04X", subject, got, want)
	}
}

func TestCPU_Step(t *testing.T) {
	c := NewCPU(nil)
	c.Memory[200] = 0xA1
	c.Memory[201] = 0x00

	if err := c.Step(); err != nil {
		t.Fatal(err)
	}

	checkHex(t, "PC", c.PC, uint16(202))
}

func TestCPU_Dispatch(t *testing.T) {
	tests := []struct {
		op     uint16
		before func(*CPU)
		check  func(*CPU)
	}{
		{
			uint16(0x2100),
			nil,
			func(c *CPU) {
				checkHex(t, "Stack[0]", c.Stack[0], uint16(0xC8))
				checkHex(t, "SP", uint16(c.SP), uint16(0x1))
				checkHex(t, "PC", c.PC, uint16(0x100))
			},
		},

		{
			uint16(0x3123),
			nil,
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},

		{
			uint16(0x3103),
			func(c *CPU) {
				c.V[1] = 0x03
			},
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},

		{
			uint16(0x4123),
			nil,
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},

		{
			uint16(0x4103),
			func(c *CPU) {
				c.V[1] = 0x03
			},
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},

		{
			uint16(0x5120),
			func(c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0x04
			},
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},

		{
			uint16(0x5120),
			func(c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0x03
			},
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},

		{
			uint16(0x6102),
			nil,
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x02))
			},
		},

		{
			uint16(0x7102),
			nil,
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x02))
			},
		},

		{
			uint16(0x7102),
			func(c *CPU) {
				c.V[1] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x03))
			},
		},

		{
			uint16(0x8120),
			func(c *CPU) {
				c.V[2] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x01))
			},
		},

		{
			uint16(0x8121),
			func(c *CPU) {
				c.V[1] = 0x10
				c.V[2] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x11))
			},
		},

		{
			uint16(0x8122),
			func(c *CPU) {
				c.V[1] = 0x10
				c.V[2] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x00))
			},
		},

		{
			uint16(0x8123),
			func(c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x00))
			},
		},

		{
			uint16(0x8124),
			func(c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
			},
		},

		{
			uint16(0x8124),
			func(c *CPU) {
				c.V[1] = 0xFF
				c.V[2] = 0x03
			},
			func(c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
			},
		},

		{
			uint16(0x8125),
			func(c *CPU) {
				c.V[1] = 0xFF
				c.V[2] = 0x03
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFC))
			},
		},

		{
			uint16(0x8125),
			func(c *CPU) {
				c.V[1] = 0x02
				c.V[2] = 0x03
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFF))
			},
		},

		{
			uint16(0x8126),
			func(c *CPU) {
				c.V[1] = 0x03
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x1))
			},
		},

		{
			uint16(0x8126),
			func(c *CPU) {
				c.V[1] = 0x02
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x1))
			},
		},

		{
			uint16(0x8127),
			func(c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0xFF
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFC))
			},
		},

		{
			uint16(0x8127),
			func(c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0x02
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFF))
			},
		},

		{
			uint16(0x812E),
			func(c *CPU) {
				c.V[1] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
			},
		},

		{
			uint16(0x812E),
			func(c *CPU) {
				c.V[1] = 0x81
			},
			func(c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
			},
		},

		{
			uint16(0x9120),
			func(c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x02
			},
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},

		{
			uint16(0x9120),
			func(c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x01
			},
			func(c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},

		{
			uint16(0xA100),
			nil,
			func(c *CPU) {
				checkHex(t, "I", c.I, uint16(0x100))
			},
		},
	}

	for _, tt := range tests {
		c := NewCPU(nil)
		if tt.before != nil {
			tt.before(c)
		}
		c.Dispatch(tt.op)
		tt.check(c)

		if t.Failed() {
			t.Logf("==============")
			t.Logf("Opcode: 0x%04X", tt.op)
			t.Logf("CPU: %v", c)
			t.Logf("==============")
			t.FailNow()
		}
	}
}

func TestCPU_op(t *testing.T) {
	c := NewCPU(nil)
	c.Memory[200] = 0xA2
	c.Memory[201] = 0xF0

	checkHex(t, "op", c.op(), uint16(0xA2F0))
}
<commit_msg>Cleanup tests.<commit_after>package chip8

import "testing"

var opcodeTests = map[string][]struct {
	op     uint16
	before func(*testing.T, *CPU)
	check  func(*testing.T, *CPU)
}{
	"2nnn - CALL addr": {
		{
			uint16(0x2100),
			nil,
			func(t *testing.T, c *CPU) {
				checkHex(t, "Stack[0]", c.Stack[0], uint16(0xC8))
				checkHex(t, "SP", uint16(c.SP), uint16(0x1))
				checkHex(t, "PC", c.PC, uint16(0x100))
			},
		},
	},

	"3xkk - SE Vx, byte": {
		{
			uint16(0x3123),
			nil,
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},

		{
			uint16(0x3103),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x03
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},
	},

	"4xkk - SNE Vx, byte": {
		{
			uint16(0x4123),
			nil,
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},

		{
			uint16(0x4103),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x03
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},
	},

	"5xy0 - SE Vx, Vy": {
		{
			uint16(0x5120),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0x04
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},

		{
			uint16(0x5120),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0x03
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},
	},

	"6xkk - LD Vx, byte": {
		{
			uint16(0x6102),
			nil,
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x02))
			},
		},
	},

	"7xkk - ADD Vx, byte": {
		{
			uint16(0x7102),
			nil,
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x02))
			},
		},

		{
			uint16(0x7102),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x03))
			},
		},
	},

	"8xy0 - LD Vx, Vy": {
		{
			uint16(0x8120),
			func(t *testing.T, c *CPU) {
				c.V[2] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x01))
			},
		},
	},

	"8xy1 - OR Vx, Vy": {
		{
			uint16(0x8121),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x10
				c.V[2] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x11))
			},
		},
	},

	"8xy2 - AND Vx, Vy": {
		{
			uint16(0x8122),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x10
				c.V[2] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x00))
			},
		},
	},

	// TODO
	"Set Vx = Vx AND Vy": {
		{
			uint16(0x8123),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x00))
			},
		},
	},

	"8xy4 - ADD Vx, Vy": {
		{
			uint16(0x8124),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
			},
		},

		{
			uint16(0x8124),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0xFF
				c.V[2] = 0x03
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
			},
		},
	},

	"8xy5 - SUB Vx, Vy": {
		{
			uint16(0x8125),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0xFF
				c.V[2] = 0x03
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFC))
			},
		},

		{
			uint16(0x8125),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x02
				c.V[2] = 0x03
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFF))
			},
		},
	},

	"8xy6 - SHR Vx {, Vy}": {
		{
			uint16(0x8126),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x03
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x1))
			},
		},

		{
			uint16(0x8126),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x02
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x1))
			},
		},
	},

	"8xy7 - SUBN Vx, Vy": {
		{
			uint16(0x8127),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0xFF
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFC))
			},
		},

		{
			uint16(0x8127),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x03
				c.V[2] = 0x02
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0xFF))
			},
		},
	},

	"8xyE - SHL Vx {, Vy}": {
		{
			uint16(0x812E),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x0))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
			},
		},

		{
			uint16(0x812E),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x81
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "VF", uint16(c.V[0xF]), uint16(0x1))
				checkHex(t, "V[1]", uint16(c.V[1]), uint16(0x2))
			},
		},
	},

	"9xy0 - SNE Vx, Vy": {
		{
			uint16(0x9120),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x02
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(202))
			},
		},

		{
			uint16(0x9120),
			func(t *testing.T, c *CPU) {
				c.V[1] = 0x01
				c.V[2] = 0x01
			},
			func(t *testing.T, c *CPU) {
				checkHex(t, "PC", c.PC, uint16(200))
			},
		},
	},

	"Annn - LD I, addr": {
		{
			uint16(0xA100),
			nil,
			func(t *testing.T, c *CPU) {
				checkHex(t, "I", c.I, uint16(0x100))
			},
		},
	},
}

func checkHex(t *testing.T, subject string, got, want uint16) {
	if got != want {
		t.Errorf("%s => 0x%04X; want 0x%04X", subject, got, want)
	}
}

func TestCPU_Step(t *testing.T) {
	c := NewCPU(nil)
	c.Memory[200] = 0xA1
	c.Memory[201] = 0x00

	if err := c.Step(); err != nil {
		t.Fatal(err)
	}

	checkHex(t, "PC", c.PC, uint16(202))
}

func TestOpcodes(t *testing.T) {
	for i, tests := range opcodeTests {
		for _, tt := range tests {
			c := NewCPU(nil)
			if tt.before != nil {
				tt.before(t, c)
			}
			c.Dispatch(tt.op)
			tt.check(t, c)

			if t.Failed() {
				t.Logf("==============")
				t.Logf("Instruction: %s", i)
				t.Logf("Opcode: 0x%04X", tt.op)
				t.Logf("CPU: %v", c)
				t.Logf("==============")
				t.FailNow()
			}
		}
	}
}

func TestCPU_op(t *testing.T) {
	c := NewCPU(nil)
	c.Memory[200] = 0xA2
	c.Memory[201] = 0xF0

	checkHex(t, "op", c.op(), uint16(0xA2F0))
}
<|endoftext|>


<commit_before>// Copyright 2017, OpenCensus 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 stats contains support for OpenCensus stats collection.

OpenCensus allows users to create typed measures, record measurements,
aggregate the collected data, and export the aggregated data.

Measures

A measure represents a type of metric to be tracked and recorded.
For example, latency, request Mb/s, and response Mb/s are measures
to collect from a server.

Each measure needs to be registered before being used. Measure
constructors such as NewMeasureInt64 and NewMeasureFloat64 automatically
registers the measure by the given name. Each registered measure needs
to be unique by name. Measures also have a description and a unit.

Libraries can define and export measures for their end users to
create views and collect instrumentation data.

Recording measurements

Measurement is a data point to be collected for a measure. For example,
for a latency (ms) measure, 100 is a measurement that represents a 100ms
latency event. Users collect data points on the existing measures with
the current context. Tags from the current context is recorded with the
measurements if they are any.

Recorded measurements are dropped immediately if user is not aggregating
them via views. Users don't necessarily need to conditionally enable/disable
recording to reduce cost. Recording of measurements is cheap.

Libraries can always record measurements, and end-user can later decide
on which measurements they want to collect by registering views. This allows
libraries to turn on the instrumentation by default.

Views

In order to collect measurements, views need to be defined and registered.
A view allows recorded measurements to be filtered and aggregated over a time window.

All recorded measurements can be filtered by a list of tags.

OpenCensus provides several aggregation methods: count, distribution, sum and mean.
Count aggregation only counts the number of measurement points. Distribution
aggregation provides statistical summary of the aggregated data. Sum distribution
sums up the measurement points. Mean provides the mean of the recorded measurements.
Aggregations can either happen cumulatively or over an interval.

Users can dynamically create and delete views.

Libraries can export their own views and claim the view names
by registering them themselves.

Exporting

Collected and aggregated data can be exported to a metric collection
backend by registering its exporter.

Multiple exporters can be registered to upload the data to various
different backends. Users need to unregister the exporters once they
no longer are needed.
*/
package stats // import "go.opencensus.io/stats"

// TODO(acetechnologist): Add a link to the language independent OpenCensus
// spec when it is available.
<commit_msg>Fix minor stats/doc.go typos (#266)<commit_after>// Copyright 2017, OpenCensus 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 stats contains support for OpenCensus stats collection.

OpenCensus allows users to create typed measures, record measurements,
aggregate the collected data, and export the aggregated data.

Measures

A measure represents a type of metric to be tracked and recorded.
For example, latency, request Mb/s, and response Mb/s are measures
to collect from a server.

Each measure needs to be registered before being used. Measure
constructors such as NewMeasureInt64 and NewMeasureFloat64 automatically
register the measure by the given name. Each registered measure needs
to be unique by name. Measures also have a description and a unit.

Libraries can define and export measures for their end users to
create views and collect instrumentation data.

Recording measurements

Measurement is a data point to be collected for a measure. For example,
for a latency (ms) measure, 100 is a measurement that represents a 100ms
latency event. Users collect data points on the existing measures with
the current context. Tags from the current context are recorded with the
measurements if they are any.

Recorded measurements are dropped immediately if user is not aggregating
them via views. Users don't necessarily need to conditionally enable/disable
recording to reduce cost. Recording of measurements is cheap.

Libraries can always record measurements, and end-users can later decide
on which measurements they want to collect by registering views. This allows
libraries to turn on the instrumentation by default.

Views

In order to collect measurements, views need to be defined and registered.
A view allows recorded measurements to be filtered and aggregated over a time window.

All recorded measurements can be filtered by a list of tags.

OpenCensus provides several aggregation methods: count, distribution, sum and mean.
Count aggregation only counts the number of measurement points. Distribution
aggregation provides statistical summary of the aggregated data. Sum distribution
sums up the measurement points. Mean provides the mean of the recorded measurements.
Aggregations can either happen cumulatively or over an interval.

Users can dynamically create and delete views.

Libraries can export their own views and claim the view names
by registering them themselves.

Exporting

Collected and aggregated data can be exported to a metric collection
backend by registering its exporter.

Multiple exporters can be registered to upload the data to various
different backends. Users need to unregister the exporters once they
no longer are needed.
*/
package stats // import "go.opencensus.io/stats"

// TODO(acetechnologist): Add a link to the language independent OpenCensus
// spec when it is available.
<|endoftext|>


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

package libkbfs

import (
	"fmt"

	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/kbfs/kbfscrypto"

	"github.com/keybase/kbfs/tlf"

	"golang.org/x/net/context"
)

// journalMDOps is an implementation of MDOps that delegates to a
// TLF's mdJournal, if one exists. Specifically, it intercepts put
// calls to write to the journal instead of the MDServer, where
// something else is presumably flushing the journal to the MDServer.
//
// It then intercepts get calls to provide a combined view of the MDs
// from the journal and the server when the journal is
// non-empty. Specifically, if rev is the earliest revision in the
// journal, and BID is the branch ID of the journal (which can only
// have one), then any requests for revisions >= rev on BID will be
// served from the journal instead of the server. If BID is empty,
// i.e. the journal is holding merged revisions, then this means that
// all merged revisions on the server from rev are hidden.
//
// TODO: This makes server updates meaningless for revisions >=
// rev. Fix this.
type journalMDOps struct {
	MDOps
	jServer *JournalServer
}

var _ MDOps = journalMDOps{}

// convertImmutableBareRMDToIRMD decrypts the bare MD into a
// full-fledged RMD.
func (j journalMDOps) convertImmutableBareRMDToIRMD(ctx context.Context,
	ibrmd ImmutableBareRootMetadata, handle *TlfHandle,
	uid keybase1.UID, key kbfscrypto.VerifyingKey) (
	ImmutableRootMetadata, error) {
	// TODO: Avoid having to do this type assertion.
	brmd, ok := ibrmd.BareRootMetadata.(MutableBareRootMetadata)
	if !ok {
		return ImmutableRootMetadata{}, MutableBareRootMetadataNoImplError{}
	}

	rmd := makeRootMetadata(brmd, ibrmd.extra, handle)

	config := j.jServer.config
	pmd, err := decryptMDPrivateData(ctx, config.Codec(), config.Crypto(),
		config.BlockCache(), config.BlockOps(), config.KeyManager(),
		uid, rmd.GetSerializedPrivateMetadata(), rmd, rmd)
	if err != nil {
		return ImmutableRootMetadata{}, err
	}

	rmd.data = pmd
	irmd := MakeImmutableRootMetadata(
		rmd, key, ibrmd.mdID, ibrmd.localTimestamp)
	return irmd, nil
}

// getHeadFromJournal returns the head RootMetadata for the TLF with
// the given ID stored in the journal, assuming it exists and matches
// the given branch ID and merge status. As a special case, if bid is
// NullBranchID and mStatus is Unmerged, the branch ID check is
// skipped.
func (j journalMDOps) getHeadFromJournal(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	handle *TlfHandle) (
	ImmutableRootMetadata, error) {
	tlfJournal, ok := j.jServer.getTLFJournal(id)
	if !ok {
		return ImmutableRootMetadata{}, nil
	}

	head, err := tlfJournal.getMDHead(ctx)
	if err == errTLFJournalDisabled {
		return ImmutableRootMetadata{}, nil
	} else if err != nil {
		return ImmutableRootMetadata{}, err
	}

	if head == (ImmutableBareRootMetadata{}) {
		return ImmutableRootMetadata{}, nil
	}

	if head.MergedStatus() != mStatus {
		return ImmutableRootMetadata{}, nil
	}

	if mStatus == Unmerged && bid != NullBranchID && bid != head.BID() {
		// The given branch ID doesn't match the one in the
		// journal, which can only be an error.
		return ImmutableRootMetadata{},
			fmt.Errorf("Expected branch ID %s, got %s",
				bid, head.BID())
	}

	headBareHandle, err := head.MakeBareTlfHandleWithExtra()
	if err != nil {
		return ImmutableRootMetadata{}, err
	}

	if handle == nil {
		handle, err = MakeTlfHandle(
			ctx, headBareHandle, j.jServer.config.KBPKI())
		if err != nil {
			return ImmutableRootMetadata{}, err
		}
	} else {
		// Check for mutual handle resolution.
		headHandle, err := MakeTlfHandle(ctx, headBareHandle,
			j.jServer.config.KBPKI())
		if err != nil {
			return ImmutableRootMetadata{}, err
		}

		if err := headHandle.MutuallyResolvesTo(ctx, j.jServer.config.Codec(),
			j.jServer.config.KBPKI(), *handle, head.RevisionNumber(),
			head.TlfID(), j.jServer.log); err != nil {
			return ImmutableRootMetadata{}, err
		}
	}

	irmd, err := j.convertImmutableBareRMDToIRMD(
		ctx, head, handle, tlfJournal.uid, tlfJournal.key)
	if err != nil {
		return ImmutableRootMetadata{}, err
	}

	return irmd, nil
}

func (j journalMDOps) getRangeFromJournal(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	start, stop MetadataRevision) (
	[]ImmutableRootMetadata, error) {
	tlfJournal, ok := j.jServer.getTLFJournal(id)
	if !ok {
		return nil, nil
	}

	ibrmds, err := tlfJournal.getMDRange(ctx, start, stop)
	if err == errTLFJournalDisabled {
		return nil, nil
	} else if err != nil {
		return nil, err
	}

	if len(ibrmds) == 0 {
		return nil, nil
	}

	head := ibrmds[len(ibrmds)-1]

	if head.MergedStatus() != mStatus {
		return nil, nil
	}

	if mStatus == Unmerged && bid != NullBranchID && bid != head.BID() {
		// The given branch ID doesn't match the one in the
		// journal, which can only be an error.
		return nil, fmt.Errorf("Expected branch ID %s, got %s",
			bid, head.BID())
	}

	bareHandle, err := head.MakeBareTlfHandleWithExtra()
	if err != nil {
		return nil, err
	}
	handle, err := MakeTlfHandle(ctx, bareHandle, j.jServer.config.KBPKI())
	if err != nil {
		return nil, err
	}

	irmds := make([]ImmutableRootMetadata, 0, len(ibrmds))

	for _, ibrmd := range ibrmds {
		irmd, err := j.convertImmutableBareRMDToIRMD(
			ctx, ibrmd, handle, tlfJournal.uid, tlfJournal.key)
		if err != nil {
			return nil, err
		}

		irmds = append(irmds, irmd)
	}

	return irmds, nil
}

func (j journalMDOps) GetForHandle(
	ctx context.Context, handle *TlfHandle, mStatus MergeStatus) (
	tlf.ID, ImmutableRootMetadata, error) {
	// Need to always consult the server to get the tlfID. No need to
	// optimize this, since all subsequent lookups will be by
	// TLF. Although if we did want to, we could store a handle -> TLF
	// ID mapping with the journals.  If we are looking for an
	// unmerged head, that exists only in the journal, so check the
	// remote server only to get the TLF ID.
	remoteMStatus := mStatus
	if mStatus == Unmerged {
		remoteMStatus = Merged
	}
	tlfID, rmd, err := j.MDOps.GetForHandle(ctx, handle, remoteMStatus)
	if err != nil {
		return tlf.ID{}, ImmutableRootMetadata{}, err
	}

	if rmd != (ImmutableRootMetadata{}) && (rmd.TlfID() != tlfID) {
		return tlf.ID{}, ImmutableRootMetadata{},
			fmt.Errorf("Expected RMD to have TLF ID %s, but got %s",
				tlfID, rmd.TlfID())
	}

	// If the journal has a head, use that.
	irmd, err := j.getHeadFromJournal(
		ctx, tlfID, NullBranchID, mStatus, handle)
	if err != nil {
		return tlf.ID{}, ImmutableRootMetadata{}, err
	}
	if irmd != (ImmutableRootMetadata{}) {
		return tlf.ID{}, irmd, nil
	}
	if remoteMStatus != mStatus {
		return tlfID, ImmutableRootMetadata{}, nil
	}

	// Otherwise, use the server's head.
	return tlfID, rmd, nil
}

// TODO: Combine the two GetForTLF functions in MDOps to avoid the
// need for this helper function.
func (j journalMDOps) getForTLF(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	delegateFn func(context.Context, tlf.ID) (ImmutableRootMetadata, error)) (
	ImmutableRootMetadata, error) {
	// If the journal has a head, use that.
	irmd, err := j.getHeadFromJournal(ctx, id, bid, mStatus, nil)
	if err != nil {
		return ImmutableRootMetadata{}, err
	}
	if irmd != (ImmutableRootMetadata{}) {
		return irmd, nil
	}

	// Otherwise, consult the server instead.
	return delegateFn(ctx, id)
}

func (j journalMDOps) GetForTLF(
	ctx context.Context, id tlf.ID) (ImmutableRootMetadata, error) {
	return j.getForTLF(ctx, id, NullBranchID, Merged, j.MDOps.GetForTLF)
}

func (j journalMDOps) GetUnmergedForTLF(
	ctx context.Context, id tlf.ID, bid BranchID) (
	ImmutableRootMetadata, error) {
	delegateFn := func(ctx context.Context, id tlf.ID) (
		ImmutableRootMetadata, error) {
		return j.MDOps.GetUnmergedForTLF(ctx, id, bid)
	}
	return j.getForTLF(ctx, id, bid, Unmerged, delegateFn)
}

// TODO: Combine the two GetRange functions in MDOps to avoid the need
// for this helper function.
func (j journalMDOps) getRange(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	start, stop MetadataRevision,
	delegateFn func(ctx context.Context, id tlf.ID,
		start, stop MetadataRevision) (
		[]ImmutableRootMetadata, error)) (
	[]ImmutableRootMetadata, error) {
	// Grab the range from the journal first.
	jirmds, err := j.getRangeFromJournal(ctx, id, bid, mStatus, start, stop)
	if err != nil {
		return nil, err
	}

	// If it's empty or disabled, just fall back to the server.
	if len(jirmds) == 0 || err == errTLFJournalDisabled {
		return delegateFn(ctx, id, start, stop)
	}

	// If the first revision from the journal is the first
	// revision we asked for, then just return the range from the
	// journal.
	if jirmds[0].Revision() == start {
		return jirmds, nil
	}

	// Otherwise, fetch the rest from the server and prepend them.
	serverStop := jirmds[0].Revision() - 1
	irmds, err := delegateFn(ctx, id, start, serverStop)
	if err != nil {
		return nil, err
	}

	if len(irmds) == 0 {
		return jirmds, nil
	}

	lastRev := irmds[len(irmds)-1].Revision()
	if lastRev != serverStop {
		return nil, fmt.Errorf(
			"Expected last server rev %d, got %d",
			serverStop, lastRev)
	}

	return append(irmds, jirmds...), nil
}

func (j journalMDOps) GetRange(
	ctx context.Context, id tlf.ID, start, stop MetadataRevision) (
	[]ImmutableRootMetadata, error) {
	return j.getRange(ctx, id, NullBranchID, Merged, start, stop,
		j.MDOps.GetRange)
}

func (j journalMDOps) GetUnmergedRange(
	ctx context.Context, id tlf.ID, bid BranchID,
	start, stop MetadataRevision) ([]ImmutableRootMetadata, error) {
	delegateFn := func(ctx context.Context, id tlf.ID,
		start, stop MetadataRevision) (
		[]ImmutableRootMetadata, error) {
		return j.MDOps.GetUnmergedRange(ctx, id, bid, start, stop)
	}
	return j.getRange(ctx, id, bid, Unmerged, start, stop,
		delegateFn)
}

func (j journalMDOps) Put(ctx context.Context, rmd *RootMetadata) (
	MdID, error) {
	if tlfJournal, ok := j.jServer.getTLFJournal(rmd.TlfID()); ok {
		// Just route to the journal.
		mdID, err := tlfJournal.putMD(ctx, rmd)
		if err != errTLFJournalDisabled {
			return mdID, err
		}
	}

	return j.MDOps.Put(ctx, rmd)
}

func (j journalMDOps) PutUnmerged(ctx context.Context, rmd *RootMetadata) (
	MdID, error) {
	if tlfJournal, ok := j.jServer.getTLFJournal(rmd.TlfID()); ok {
		rmd.SetUnmerged()
		mdID, err := tlfJournal.putMD(ctx, rmd)
		if err != errTLFJournalDisabled {
			return mdID, err
		}
	}

	return j.MDOps.PutUnmerged(ctx, rmd)
}

func (j journalMDOps) PruneBranch(
	ctx context.Context, id tlf.ID, bid BranchID) error {
	if tlfJournal, ok := j.jServer.getTLFJournal(id); ok {
		// Prune the journal, too.
		err := tlfJournal.clearMDs(ctx, bid)
		if err != nil && err != errTLFJournalDisabled {
			return err
		}
	}

	return j.MDOps.PruneBranch(ctx, id, bid)
}

func (j journalMDOps) ResolveBranch(
	ctx context.Context, id tlf.ID, bid BranchID,
	blocksToDelete []BlockID, rmd *RootMetadata) (MdID, error) {
	if tlfJournal, ok := j.jServer.getTLFJournal(id); ok {
		mdID, err := tlfJournal.resolveBranch(
			ctx, bid, blocksToDelete, rmd, rmd.extra)
		if err != errTLFJournalDisabled {
			return mdID, err
		}
	}

	return j.MDOps.ResolveBranch(ctx, id, bid, blocksToDelete, rmd)
}
<commit_msg>journal_md_ops: don't return an err if journal is disabled<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"fmt"

	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/kbfs/kbfscrypto"

	"github.com/keybase/kbfs/tlf"

	"golang.org/x/net/context"
)

// journalMDOps is an implementation of MDOps that delegates to a
// TLF's mdJournal, if one exists. Specifically, it intercepts put
// calls to write to the journal instead of the MDServer, where
// something else is presumably flushing the journal to the MDServer.
//
// It then intercepts get calls to provide a combined view of the MDs
// from the journal and the server when the journal is
// non-empty. Specifically, if rev is the earliest revision in the
// journal, and BID is the branch ID of the journal (which can only
// have one), then any requests for revisions >= rev on BID will be
// served from the journal instead of the server. If BID is empty,
// i.e. the journal is holding merged revisions, then this means that
// all merged revisions on the server from rev are hidden.
//
// TODO: This makes server updates meaningless for revisions >=
// rev. Fix this.
type journalMDOps struct {
	MDOps
	jServer *JournalServer
}

var _ MDOps = journalMDOps{}

// convertImmutableBareRMDToIRMD decrypts the bare MD into a
// full-fledged RMD.
func (j journalMDOps) convertImmutableBareRMDToIRMD(ctx context.Context,
	ibrmd ImmutableBareRootMetadata, handle *TlfHandle,
	uid keybase1.UID, key kbfscrypto.VerifyingKey) (
	ImmutableRootMetadata, error) {
	// TODO: Avoid having to do this type assertion.
	brmd, ok := ibrmd.BareRootMetadata.(MutableBareRootMetadata)
	if !ok {
		return ImmutableRootMetadata{}, MutableBareRootMetadataNoImplError{}
	}

	rmd := makeRootMetadata(brmd, ibrmd.extra, handle)

	config := j.jServer.config
	pmd, err := decryptMDPrivateData(ctx, config.Codec(), config.Crypto(),
		config.BlockCache(), config.BlockOps(), config.KeyManager(),
		uid, rmd.GetSerializedPrivateMetadata(), rmd, rmd)
	if err != nil {
		return ImmutableRootMetadata{}, err
	}

	rmd.data = pmd
	irmd := MakeImmutableRootMetadata(
		rmd, key, ibrmd.mdID, ibrmd.localTimestamp)
	return irmd, nil
}

// getHeadFromJournal returns the head RootMetadata for the TLF with
// the given ID stored in the journal, assuming it exists and matches
// the given branch ID and merge status. As a special case, if bid is
// NullBranchID and mStatus is Unmerged, the branch ID check is
// skipped.
func (j journalMDOps) getHeadFromJournal(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	handle *TlfHandle) (
	ImmutableRootMetadata, error) {
	tlfJournal, ok := j.jServer.getTLFJournal(id)
	if !ok {
		return ImmutableRootMetadata{}, nil
	}

	head, err := tlfJournal.getMDHead(ctx)
	if err == errTLFJournalDisabled {
		return ImmutableRootMetadata{}, nil
	} else if err != nil {
		return ImmutableRootMetadata{}, err
	}

	if head == (ImmutableBareRootMetadata{}) {
		return ImmutableRootMetadata{}, nil
	}

	if head.MergedStatus() != mStatus {
		return ImmutableRootMetadata{}, nil
	}

	if mStatus == Unmerged && bid != NullBranchID && bid != head.BID() {
		// The given branch ID doesn't match the one in the
		// journal, which can only be an error.
		return ImmutableRootMetadata{},
			fmt.Errorf("Expected branch ID %s, got %s",
				bid, head.BID())
	}

	headBareHandle, err := head.MakeBareTlfHandleWithExtra()
	if err != nil {
		return ImmutableRootMetadata{}, err
	}

	if handle == nil {
		handle, err = MakeTlfHandle(
			ctx, headBareHandle, j.jServer.config.KBPKI())
		if err != nil {
			return ImmutableRootMetadata{}, err
		}
	} else {
		// Check for mutual handle resolution.
		headHandle, err := MakeTlfHandle(ctx, headBareHandle,
			j.jServer.config.KBPKI())
		if err != nil {
			return ImmutableRootMetadata{}, err
		}

		if err := headHandle.MutuallyResolvesTo(ctx, j.jServer.config.Codec(),
			j.jServer.config.KBPKI(), *handle, head.RevisionNumber(),
			head.TlfID(), j.jServer.log); err != nil {
			return ImmutableRootMetadata{}, err
		}
	}

	irmd, err := j.convertImmutableBareRMDToIRMD(
		ctx, head, handle, tlfJournal.uid, tlfJournal.key)
	if err != nil {
		return ImmutableRootMetadata{}, err
	}

	return irmd, nil
}

func (j journalMDOps) getRangeFromJournal(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	start, stop MetadataRevision) (
	[]ImmutableRootMetadata, error) {
	tlfJournal, ok := j.jServer.getTLFJournal(id)
	if !ok {
		return nil, nil
	}

	ibrmds, err := tlfJournal.getMDRange(ctx, start, stop)
	if err == errTLFJournalDisabled {
		return nil, nil
	} else if err != nil {
		return nil, err
	}

	if len(ibrmds) == 0 {
		return nil, nil
	}

	head := ibrmds[len(ibrmds)-1]

	if head.MergedStatus() != mStatus {
		return nil, nil
	}

	if mStatus == Unmerged && bid != NullBranchID && bid != head.BID() {
		// The given branch ID doesn't match the one in the
		// journal, which can only be an error.
		return nil, fmt.Errorf("Expected branch ID %s, got %s",
			bid, head.BID())
	}

	bareHandle, err := head.MakeBareTlfHandleWithExtra()
	if err != nil {
		return nil, err
	}
	handle, err := MakeTlfHandle(ctx, bareHandle, j.jServer.config.KBPKI())
	if err != nil {
		return nil, err
	}

	irmds := make([]ImmutableRootMetadata, 0, len(ibrmds))

	for _, ibrmd := range ibrmds {
		irmd, err := j.convertImmutableBareRMDToIRMD(
			ctx, ibrmd, handle, tlfJournal.uid, tlfJournal.key)
		if err != nil {
			return nil, err
		}

		irmds = append(irmds, irmd)
	}

	return irmds, nil
}

func (j journalMDOps) GetForHandle(
	ctx context.Context, handle *TlfHandle, mStatus MergeStatus) (
	tlf.ID, ImmutableRootMetadata, error) {
	// Need to always consult the server to get the tlfID. No need to
	// optimize this, since all subsequent lookups will be by
	// TLF. Although if we did want to, we could store a handle -> TLF
	// ID mapping with the journals.  If we are looking for an
	// unmerged head, that exists only in the journal, so check the
	// remote server only to get the TLF ID.
	remoteMStatus := mStatus
	if mStatus == Unmerged {
		remoteMStatus = Merged
	}
	tlfID, rmd, err := j.MDOps.GetForHandle(ctx, handle, remoteMStatus)
	if err != nil {
		return tlf.ID{}, ImmutableRootMetadata{}, err
	}

	if rmd != (ImmutableRootMetadata{}) && (rmd.TlfID() != tlfID) {
		return tlf.ID{}, ImmutableRootMetadata{},
			fmt.Errorf("Expected RMD to have TLF ID %s, but got %s",
				tlfID, rmd.TlfID())
	}

	// If the journal has a head, use that.
	irmd, err := j.getHeadFromJournal(
		ctx, tlfID, NullBranchID, mStatus, handle)
	if err != nil {
		return tlf.ID{}, ImmutableRootMetadata{}, err
	}
	if irmd != (ImmutableRootMetadata{}) {
		return tlf.ID{}, irmd, nil
	}
	if remoteMStatus != mStatus {
		return tlfID, ImmutableRootMetadata{}, nil
	}

	// Otherwise, use the server's head.
	return tlfID, rmd, nil
}

// TODO: Combine the two GetForTLF functions in MDOps to avoid the
// need for this helper function.
func (j journalMDOps) getForTLF(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	delegateFn func(context.Context, tlf.ID) (ImmutableRootMetadata, error)) (
	ImmutableRootMetadata, error) {
	// If the journal has a head, use that.
	irmd, err := j.getHeadFromJournal(ctx, id, bid, mStatus, nil)
	if err != nil {
		return ImmutableRootMetadata{}, err
	}
	if irmd != (ImmutableRootMetadata{}) {
		return irmd, nil
	}

	// Otherwise, consult the server instead.
	return delegateFn(ctx, id)
}

func (j journalMDOps) GetForTLF(
	ctx context.Context, id tlf.ID) (ImmutableRootMetadata, error) {
	return j.getForTLF(ctx, id, NullBranchID, Merged, j.MDOps.GetForTLF)
}

func (j journalMDOps) GetUnmergedForTLF(
	ctx context.Context, id tlf.ID, bid BranchID) (
	ImmutableRootMetadata, error) {
	delegateFn := func(ctx context.Context, id tlf.ID) (
		ImmutableRootMetadata, error) {
		return j.MDOps.GetUnmergedForTLF(ctx, id, bid)
	}
	return j.getForTLF(ctx, id, bid, Unmerged, delegateFn)
}

// TODO: Combine the two GetRange functions in MDOps to avoid the need
// for this helper function.
func (j journalMDOps) getRange(
	ctx context.Context, id tlf.ID, bid BranchID, mStatus MergeStatus,
	start, stop MetadataRevision,
	delegateFn func(ctx context.Context, id tlf.ID,
		start, stop MetadataRevision) (
		[]ImmutableRootMetadata, error)) (
	[]ImmutableRootMetadata, error) {
	// Grab the range from the journal first.
	jirmds, err := j.getRangeFromJournal(ctx, id, bid, mStatus, start, stop)
	if err != nil && err != errTLFJournalDisabled {
		return nil, err
	}

	// If it's empty or disabled, just fall back to the server.
	if len(jirmds) == 0 || err == errTLFJournalDisabled {
		return delegateFn(ctx, id, start, stop)
	}

	// If the first revision from the journal is the first
	// revision we asked for, then just return the range from the
	// journal.
	if jirmds[0].Revision() == start {
		return jirmds, nil
	}

	// Otherwise, fetch the rest from the server and prepend them.
	serverStop := jirmds[0].Revision() - 1
	irmds, err := delegateFn(ctx, id, start, serverStop)
	if err != nil {
		return nil, err
	}

	if len(irmds) == 0 {
		return jirmds, nil
	}

	lastRev := irmds[len(irmds)-1].Revision()
	if lastRev != serverStop {
		return nil, fmt.Errorf(
			"Expected last server rev %d, got %d",
			serverStop, lastRev)
	}

	return append(irmds, jirmds...), nil
}

func (j journalMDOps) GetRange(
	ctx context.Context, id tlf.ID, start, stop MetadataRevision) (
	[]ImmutableRootMetadata, error) {
	return j.getRange(ctx, id, NullBranchID, Merged, start, stop,
		j.MDOps.GetRange)
}

func (j journalMDOps) GetUnmergedRange(
	ctx context.Context, id tlf.ID, bid BranchID,
	start, stop MetadataRevision) ([]ImmutableRootMetadata, error) {
	delegateFn := func(ctx context.Context, id tlf.ID,
		start, stop MetadataRevision) (
		[]ImmutableRootMetadata, error) {
		return j.MDOps.GetUnmergedRange(ctx, id, bid, start, stop)
	}
	return j.getRange(ctx, id, bid, Unmerged, start, stop,
		delegateFn)
}

func (j journalMDOps) Put(ctx context.Context, rmd *RootMetadata) (
	MdID, error) {
	if tlfJournal, ok := j.jServer.getTLFJournal(rmd.TlfID()); ok {
		// Just route to the journal.
		mdID, err := tlfJournal.putMD(ctx, rmd)
		if err != errTLFJournalDisabled {
			return mdID, err
		}
	}

	return j.MDOps.Put(ctx, rmd)
}

func (j journalMDOps) PutUnmerged(ctx context.Context, rmd *RootMetadata) (
	MdID, error) {
	if tlfJournal, ok := j.jServer.getTLFJournal(rmd.TlfID()); ok {
		rmd.SetUnmerged()
		mdID, err := tlfJournal.putMD(ctx, rmd)
		if err != errTLFJournalDisabled {
			return mdID, err
		}
	}

	return j.MDOps.PutUnmerged(ctx, rmd)
}

func (j journalMDOps) PruneBranch(
	ctx context.Context, id tlf.ID, bid BranchID) error {
	if tlfJournal, ok := j.jServer.getTLFJournal(id); ok {
		// Prune the journal, too.
		err := tlfJournal.clearMDs(ctx, bid)
		if err != nil && err != errTLFJournalDisabled {
			return err
		}
	}

	return j.MDOps.PruneBranch(ctx, id, bid)
}

func (j journalMDOps) ResolveBranch(
	ctx context.Context, id tlf.ID, bid BranchID,
	blocksToDelete []BlockID, rmd *RootMetadata) (MdID, error) {
	if tlfJournal, ok := j.jServer.getTLFJournal(id); ok {
		mdID, err := tlfJournal.resolveBranch(
			ctx, bid, blocksToDelete, rmd, rmd.extra)
		if err != errTLFJournalDisabled {
			return mdID, err
		}
	}

	return j.MDOps.ResolveBranch(ctx, id, bid, blocksToDelete, rmd)
}
<|endoftext|>


<commit_before><commit_msg>S종목별_일일_가격정보_모음 함수 변경<commit_after><|endoftext|>


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

/*
Hist shows the history of a given file, using Arq backups.

    usage: hist [-d] [-h host] [-m mtpt] [-s yyyy/mmdd] file ...

The -d flag causes it to show diffs between successive versions.

By default, hist assumes backups are mounted at mtpt/host, where
mtpt defaults to /mnt/arq and host is the first element of the local host name.
Hist starts the file list with the present copy of the file.

The -h and -s flags override these assumptions.

*/
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var usageString = `usage: hist [-d] [-h host] [-m mtpt] [-s yyyy/mmdd] file ...

Hist lists the known versions of the given file.
The -d flag causes it to show diffs between successive versions.

By default, hist assumes backups are mounted at mtpt/host, where
mtpt defaults to /mnt/arq and host is the first element of the local host name.
Hist starts the file list with the present copy of the file.

The -h and -s flags override these assumptions.
`

var (
	diff = flag.Bool("d", false, "diff")
	host = flag.String("h", defaultHost(), "host name")
	mtpt = flag.String("m", "/mnt/arq", "mount point")
	vers = flag.String("s", "", "version")
)

func defaultHost() string {
	name, _ := os.Hostname()
	if name == "" {
		name = "gnot"
	}
	if i := strings.Index(name, "."); i >= 0 {
		name = name[:i]
	}
	return name
}

func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, usageString)
		os.Exit(2)
	}

	flag.Parse()
	args := flag.Args()
	if len(args) == 0 {
		flag.Usage()
	}

	dates := loadDates()
	for _, file := range args {
		list(dates, file)
	}
}

var (
	yyyy = regexp.MustCompile(`^\d{4}$`)
	mmdd = regexp.MustCompile(`^\d{4}(\.\d+)?$`)
)

func loadDates() []string {
	var all []string
	ydir, err := ioutil.ReadDir(filepath.Join(*mtpt, *host))
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(3)
	}
	for _, y := range ydir {
		if !y.IsDir() || !yyyy.MatchString(y.Name()) {
			continue
		}
		ddir, err := ioutil.ReadDir(filepath.Join(*mtpt, *host, y.Name()))
		if err != nil {
			continue
		}
		for _, d := range ddir {
			if !d.IsDir() || !mmdd.MatchString(d.Name()) {
				continue
			}
			date := y.Name() + "/" + d.Name()
			if *vers > date {
				continue
			}
			all = append(all, filepath.Join(*mtpt, *host, date))
		}
	}
	return all
}

const timeFormat = "Jan 02 15:04:05 MST 2006"

func list(dates []string, file string) {
	var (
		last os.FileInfo
		lastPath string
	)

	fi, err := os.Stat(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "hist: warning: %s: %v\n", file, err)
	} else {
		fmt.Printf("%s %s %d\n", fi.ModTime().Format(timeFormat), file, fi.Size())
		last = fi
		lastPath = file
	}

	file, err = filepath.Abs(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "hist: abs: %v\n", err)
		return
	}

	for i := len(dates)-1; i >= 0; i-- {
		p := filepath.Join(dates[i], file)
		fi, err := os.Stat(p)
		if err != nil {
			continue
		}
		if last != nil && fi.ModTime() == last.ModTime() && fi.Size() == last.Size() {
			continue
		}
		if *diff {
			cmd := exec.Command("diff", lastPath, p)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			if err := cmd.Start(); err != nil {
				fmt.Fprintf(os.Stderr, "%s\n", err)
			}
			cmd.Wait()
		}
		fmt.Printf("%s %s %d\n", fi.ModTime().Format(timeFormat), file, fi.Size())
		last = fi
		lastPath = p
	}
}

<commit_msg>arq/hist: fix print<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Hist shows the history of a given file, using Arq backups.

    usage: hist [-d] [-h host] [-m mtpt] [-s yyyy/mmdd] file ...

The -d flag causes it to show diffs between successive versions.

By default, hist assumes backups are mounted at mtpt/host, where
mtpt defaults to /mnt/arq and host is the first element of the local host name.
Hist starts the file list with the present copy of the file.

The -h and -s flags override these assumptions.

*/
package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

var usageString = `usage: hist [-d] [-h host] [-m mtpt] [-s yyyy/mmdd] file ...

Hist lists the known versions of the given file.
The -d flag causes it to show diffs between successive versions.

By default, hist assumes backups are mounted at mtpt/host, where
mtpt defaults to /mnt/arq and host is the first element of the local host name.
Hist starts the file list with the present copy of the file.

The -h and -s flags override these assumptions.
`

var (
	diff = flag.Bool("d", false, "diff")
	host = flag.String("h", defaultHost(), "host name")
	mtpt = flag.String("m", "/mnt/arq", "mount point")
	vers = flag.String("s", "", "version")
)

func defaultHost() string {
	name, _ := os.Hostname()
	if name == "" {
		name = "gnot"
	}
	if i := strings.Index(name, "."); i >= 0 {
		name = name[:i]
	}
	return name
}

func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, usageString)
		os.Exit(2)
	}

	flag.Parse()
	args := flag.Args()
	if len(args) == 0 {
		flag.Usage()
	}

	dates := loadDates()
	for _, file := range args {
		list(dates, file)
	}
}

var (
	yyyy = regexp.MustCompile(`^\d{4}$`)
	mmdd = regexp.MustCompile(`^\d{4}(\.\d+)?$`)
)

func loadDates() []string {
	var all []string
	ydir, err := ioutil.ReadDir(filepath.Join(*mtpt, *host))
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(3)
	}
	for _, y := range ydir {
		if !y.IsDir() || !yyyy.MatchString(y.Name()) {
			continue
		}
		ddir, err := ioutil.ReadDir(filepath.Join(*mtpt, *host, y.Name()))
		if err != nil {
			continue
		}
		for _, d := range ddir {
			if !d.IsDir() || !mmdd.MatchString(d.Name()) {
				continue
			}
			date := y.Name() + "/" + d.Name()
			if *vers > date {
				continue
			}
			all = append(all, filepath.Join(*mtpt, *host, date))
		}
	}
	return all
}

const timeFormat = "Jan 02 15:04:05 MST 2006"

func list(dates []string, file string) {
	var (
		last os.FileInfo
		lastPath string
	)

	fi, err := os.Stat(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "hist: warning: %s: %v\n", file, err)
	} else {
		fmt.Printf("%s %s %d\n", fi.ModTime().Format(timeFormat), file, fi.Size())
		last = fi
		lastPath = file
	}

	file, err = filepath.Abs(file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "hist: abs: %v\n", err)
		return
	}

	for i := len(dates)-1; i >= 0; i-- {
		p := filepath.Join(dates[i], file)
		fi, err := os.Stat(p)
		if err != nil {
			continue
		}
		if last != nil && fi.ModTime() == last.ModTime() && fi.Size() == last.Size() {
			continue
		}
		if *diff {
			cmd := exec.Command("diff", lastPath, p)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			if err := cmd.Start(); err != nil {
				fmt.Fprintf(os.Stderr, "%s\n", err)
			}
			cmd.Wait()
		}
		fmt.Printf("%s %s %d\n", fi.ModTime().Format(timeFormat), p, fi.Size())
		last = fi
		lastPath = p
	}
}

<|endoftext|>


<commit_before>package main

func main()              {}
func sink(id int, v interface{}) {}

func link(from interface{}, into interface{}) {}

func newSource(id int) interface{} {
	return nil
}
<commit_msg>Fix go autoformat<commit_after>package main

func main()                      {}
func sink(id int, v interface{}) {}

func link(from interface{}, into interface{}) {}

func newSource(id int) interface{} {
	return nil
}
<|endoftext|>


<commit_before>package make

import (
	log "github.com/Sirupsen/logrus"
	"os"
	"os/exec"
	"strings"
)

type SolrCore struct {
	Address  string
	Name     string
	Template string
	Path     string
	Legacy   bool
}

func logSolrInstall() bool {
	if verifySolrInstall() {
		log.Infoln("Found Solr installation")
		return true
	} else {
		log.Errorln("Could not find Solr installation")
		return false
	}
}
func logSolrCLI() bool {
	if verifySolrCLI() {
		log.Infoln("Found Solr command-line tools")
		return true
	} else {
		log.Warnln("Could not find Solr command-line tools")
		return false
	}
}
func logResources(Template string) bool {
	if verifyResources(Template) {
		log.Infoln("Found configuration folder")
		return true
	} else {
		log.Errorln("Could not find configuration folder")
		return false
	}
}
func logSolrCore(SolrCore *SolrCore) bool {
	if verifySolrCore(SolrCore) {
		log.Infoln("Solr core is installed.")
		return true
	} else {
		log.Warnln("Solr core is not installed.")
		return false
	}
}
func verifySolrInstall() bool {
	_, err := os.Stat("/opt/solr")
	if err == nil {
		return true
	} else {
		return false
	}
}
func verifySolrCLI() bool {
	_, err := os.Stat("/opt/solr/bin/solr")
	if err == nil {
		return true
	} else {
		return false
	}
}
func verifyResources(Template string) bool {
	_, err := os.Stat(Template)
	if err == nil {
		return true
	} else {
		return false
	}
}
func verifySolrCore(SolrCore *SolrCore) bool {
	curlResponse, err := exec.Command("curl", SolrCore.Address+"/solr/admin/cores?action=STATUS").Output()
	if err == nil {
		if strings.Contains(string(curlResponse), `<str name="name">`+SolrCore.Name+`</str>`) == true {
			return true
		} else {
			return false
		}
	} else {
		log.Errorln("Solr could not be accessed using CURL:", err.Error())
	}
	return false
}

func NewCore(Address, Name, Template, Path string) SolrCore {
	return SolrCore{Address, Name, Template, Path, false}
}

func (SolrCore *SolrCore) Install() {
	if logSolrInstall() && logResources(SolrCore.Template) {
		log.Infoln("All checks have passed.")
		dataDir := ""
		if SolrCore.Legacy {
			log.Infoln("Installing legacy file system for Solr < 5.0")
			dataDir = SolrCore.Path + "/" + SolrCore.Name + "/conf/"
		} else {
			dataDir = SolrCore.Path + "/data/" + SolrCore.Name + "/conf/"
		}

		// Create data directories
		err := os.MkdirAll(dataDir, 0777)
		if err == nil {
			log.Infoln("Directory has been created.", dataDir)
		} else {
			log.Errorln("Directory has not been created:", err.Error())
		}

		// Sync
		_, err = exec.Command("rsync", "-a", SolrCore.Template+"/", dataDir).Output()
		if err == nil {
			log.Infoln("Configuration has been synced with boilerplate resources.")
		} else {
			log.Errorln("Configuration could not be synced with boilerplate resources:", err.Error())
		}

		if logSolrCLI() == true {
			// Install core via CLI
			cliOut, err := exec.Command("/opt/solr/bin/solr", "create", "-c", SolrCore.Name).Output()
			if err == nil && strings.Contains(string(cliOut), "Unable to create core") == false {
				if verifySolrCore(SolrCore) {
					log.Infoln("Core has been installed and verified successfully.")
				} else {
					log.Errorln("Core could not be installed, check logs for details.")
				}
			} else {
				log.Errorln("Core could not be installed:", err.Error(), string(cliOut))
			}
		} else {
			// Install core via CURL
			_, err = exec.Command("curl", SolrCore.Address+"/solr/admin/cores?action=CREATE&name="+SolrCore.Name+"&instanceDir="+SolrCore.Name+"&dataDir=data&config=solrconfig.xml&schema=schema.xml").Output()
			if err == nil {
				log.Infoln("Core has been successfully installed.")
			} else {
				log.Errorln("Core could not be installed:", err)
			}
		}
	}
	verifySolrCore(SolrCore)
}

func (SolrCore *SolrCore) Uninstall() {
	if verifySolrInstall() && verifySolrCLI() {
		_, err := exec.Command("sh", "-c", "/opt/solr/bin/solr", "delete", "-c", SolrCore.Name).Output()
		if err == nil {
			log.Infoln("Core has been successfully uninstalled.")
		} else {
			log.Errorln("Core could not be uninstalled:", err)
		}
	} else if verifySolrInstall() && !verifySolrCLI() {
		_, err := exec.Command("curl", SolrCore.Address+"/solr/admin/cores?action=UNLOAD&core="+SolrCore.Name).Output()
		if err == nil {
			log.Infoln("Core has been successfully uninstalled.")
		} else {
			log.Errorln("Core could not be uninstalled:", err)
		}
	}
	err := os.RemoveAll(SolrCore.Path + "/" + SolrCore.Name)
	if err == nil {
		log.Infoln("Core resources have been removed.")
	} else {
		log.Errorln("Core resources could not be removed:", err)
	}
}
<commit_msg>Fallback to curl as a fixed solution for creating and deleting cores.<commit_after>package make

import (
	log "github.com/Sirupsen/logrus"
	"os"
	"os/exec"
	"strings"
)

type SolrCore struct {
	Address  string
	Name     string
	Template string
	Path     string
	Legacy   bool
}

func logSolrInstall() bool {
	if verifySolrInstall() {
		log.Infoln("Found Solr installation")
		return true
	} else {
		log.Errorln("Could not find Solr installation")
		return false
	}
}
func logSolrCLI() bool {
	if verifySolrCLI() {
		log.Infoln("Found Solr command-line tools")
		return true
	} else {
		log.Warnln("Could not find Solr command-line tools")
		return false
	}
}
func logResources(Template string) bool {
	if verifyResources(Template) {
		log.Infoln("Found configuration folder")
		return true
	} else {
		log.Errorln("Could not find configuration folder")
		return false
	}
}
func logSolrCore(SolrCore *SolrCore) bool {
	if verifySolrCore(SolrCore) {
		log.Infoln("Solr core is installed.")
		return true
	} else {
		log.Warnln("Solr core is not installed.")
		return false
	}
}
func verifySolrInstall() bool {
	_, err := os.Stat("/opt/solr")
	if err == nil {
		return true
	} else {
		return false
	}
}
func verifySolrCLI() bool {
	_, err := os.Stat("/opt/solr/bin/solr")
	if err == nil {
		return true
	} else {
		return false
	}
}
func verifyResources(Template string) bool {
	_, err := os.Stat(Template)
	if err == nil {
		return true
	} else {
		return false
	}
}
func verifySolrCore(SolrCore *SolrCore) bool {
	curlResponse, err := exec.Command("curl", SolrCore.Address+"/solr/admin/cores?action=STATUS").Output()
	if err == nil {
		if strings.Contains(string(curlResponse), `<str name="name">`+SolrCore.Name+`</str>`) == true {
			return true
		} else {
			return false
		}
	} else {
		log.Errorln("Solr could not be accessed using CURL:", err.Error())
	}
	return false
}

func NewCore(Address, Name, Template, Path string) SolrCore {
	return SolrCore{Address, Name, Template, Path, false}
}

func (SolrCore *SolrCore) Install() {
	if logSolrInstall() && logResources(SolrCore.Template) {
		log.Infoln("All checks have passed.")
		dataDir := ""
		if SolrCore.Legacy {
			log.Infoln("Installing legacy file system for Solr < 5.0")
			dataDir = SolrCore.Path + "/" + SolrCore.Name + "/conf/"
		} else {
			dataDir = SolrCore.Path + "/data/" + SolrCore.Name + "/conf/"
		}

		// Create data directories
		err := os.MkdirAll(dataDir, 0777)
		if err == nil {
			log.Infoln("Directory has been created.", dataDir)
		} else {
			log.Errorln("Directory has not been created:", err.Error())
		}

		// Sync
		_, err = exec.Command("rsync", "-a", SolrCore.Template+"/", dataDir).Output()
		if err == nil {
			log.Infoln("Configuration has been synced with boilerplate resources.")
		} else {
			log.Errorln("Configuration could not be synced with boilerplate resources:", err.Error())
		}

		_, err = exec.Command("curl", SolrCore.Address+"/solr/admin/cores?action=CREATE&name="+SolrCore.Name+"&instanceDir="+SolrCore.Name+"&dataDir=data&config=solrconfig.xml&schema=schema.xml").Output()
		if err == nil {
			log.Infoln("Core has been successfully installed.")
		} else {
			log.Errorln("Core could not be installed:", err)
		}
	}
	verifySolrCore(SolrCore)
}

func (SolrCore *SolrCore) Uninstall() {
	_, err := exec.Command("curl", SolrCore.Address+"/solr/admin/cores?action=UNLOAD&core="+SolrCore.Name).Output()
	if err == nil {
		log.Infoln("Core has been successfully uninstalled.")
	} else {
		log.Errorln("Core could not be uninstalled:", err)
	}
	err = os.RemoveAll(SolrCore.Path + "/" + SolrCore.Name)
	if err == nil {
		log.Infoln("Core resources have been removed.")
	} else {
		log.Errorln("Core resources could not be removed:", err)
	}
}
<|endoftext|>