<commit_before>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 helper

import (
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/x509"
	"fmt"
	"sort"
	"time"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"

	apiutil "github.com/jetstack/cert-manager/pkg/api/util"
	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
	"github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/pkg/util/pki"
	"github.com/jetstack/cert-manager/test/e2e/framework/log"
)

// WaitForCertificateReady waits for the certificate resource to enter a Ready
// state.
func (h *Helper) WaitForCertificateReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
	var certificate *cmapi.Certificate
	err := wait.PollImmediate(time.Second, timeout,
		func() (bool, error) {
			var err error
			log.Logf("Waiting for Certificate %v to be ready", name)
			certificate, err = h.CMClient.CertmanagerV1alpha2().Certificates(ns).Get(name, metav1.GetOptions{})
			if err != nil {
				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
			}
			isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
				Type:   cmapi.CertificateConditionReady,
				Status: cmmeta.ConditionTrue,
			})
			if !isReady {
				log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
				return false, nil
			}
			return true, nil
		},
	)

	// return certificate even when error to use for debugging
	return certificate, err
}

// WaitForCertificateNotReady waits for the certificate resource to enter a
// non-Ready state.
func (h *Helper) WaitForCertificateNotReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
	var certificate *cmapi.Certificate
	err := wait.PollImmediate(time.Second, timeout,
		func() (bool, error) {
			var err error
			log.Logf("Waiting for Certificate %v to be ready", name)
			certificate, err = h.CMClient.CertmanagerV1alpha2().Certificates(ns).Get(name, metav1.GetOptions{})
			if err != nil {
				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
			}
			isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
				Type:   cmapi.CertificateConditionReady,
				Status: cmmeta.ConditionFalse,
			})
			if !isReady {
				log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
				return false, nil
			}
			return true, nil
		},
	)

	// return certificate even when error to use for debugging
	return certificate, err
}

// ValidateIssuedCertificate will ensure that the given Certificate has a
// certificate issued for it, and that the details on the x509 certificate are
// correct as defined by the Certificate's spec.
func (h *Helper) ValidateIssuedCertificate(certificate *cmapi.Certificate, rootCAPEM []byte) (*x509.Certificate, error) {
	log.Logf("Getting the TLS certificate Secret resource")
	secret, err := h.KubeClient.CoreV1().Secrets(certificate.Namespace).Get(certificate.Spec.SecretName, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
	if !(len(secret.Data) == 2 || len(secret.Data) == 3) {
		return nil, fmt.Errorf("Expected 2 keys in certificate secret, but there was %d", len(secret.Data))
	}

	keyBytes, ok := secret.Data[corev1.TLSPrivateKeyKey]
	if !ok {
		return nil, fmt.Errorf("No private key data found for Certificate %q (secret %q)", certificate.Name, certificate.Spec.SecretName)
	}
	key, err := pki.DecodePrivateKeyBytes(keyBytes)
	if err != nil {
		return nil, err
	}

	// validate private key is of the correct type (rsa or ecdsa)
	switch certificate.Spec.KeyAlgorithm {
	case cmapi.KeyAlgorithm(""),
		cmapi.RSAKeyAlgorithm:
		_, ok := key.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("Expected private key of type RSA, but it was: %T", key)
		}
	case cmapi.ECDSAKeyAlgorithm:
		_, ok := key.(*ecdsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("Expected private key of type ECDSA, but it was: %T", key)
		}
	default:
		return nil, fmt.Errorf("unrecognised requested private key algorithm %q", certificate.Spec.KeyAlgorithm)
	}

	// TODO: validate private key KeySize

	// check the provided certificate is valid
	expectedOrganization := pki.OrganizationForCertificate(certificate)
	expectedDNSNames := certificate.Spec.DNSNames
	uris, err := pki.URIsForCertificate(certificate)
	if err != nil {
		return nil, fmt.Errorf("failed to parse URIs: %s", err)
	}

	expectedURIs := pki.URLsToString(uris)

	certBytes, ok := secret.Data[corev1.TLSCertKey]
	if !ok {
		return nil, fmt.Errorf("No certificate data found for Certificate %q (secret %q)", certificate.Name, certificate.Spec.SecretName)
	}

	cert, err := pki.DecodeX509CertificateBytes(certBytes)
	if err != nil {
		return nil, err
	}

	commonNameCorrect := true
	expectedCN := certificate.Spec.CommonName
	if len(expectedCN) == 0 && len(cert.Subject.CommonName) > 0 {
		if !util.Contains(cert.DNSNames, cert.Subject.CommonName) {
			commonNameCorrect = false
		}
	} else if expectedCN != cert.Subject.CommonName {
		commonNameCorrect = false
	}

	if !commonNameCorrect || !util.Subset(cert.DNSNames, expectedDNSNames) || !util.EqualUnsorted(pki.URLsToString(cert.URIs), expectedURIs) ||
		!(len(cert.Subject.Organization) == 0 || util.EqualUnsorted(cert.Subject.Organization, expectedOrganization)) {
		return nil, fmt.Errorf("Expected certificate valid for CN %q, O %v, dnsNames %v, uriSANs %v,but got a certificate valid for CN %q, O %v, dnsNames %v, uriSANs %v",
			expectedCN, expectedOrganization, expectedDNSNames, expectedURIs, cert.Subject.CommonName, cert.Subject.Organization, cert.DNSNames, cert.URIs)
	}

	if certificate.Status.NotAfter == nil {
		return nil, fmt.Errorf("No certificate expiration found for Certificate %q", certificate.Name)
	}
	if !cert.NotAfter.Equal(certificate.Status.NotAfter.Time) {
		return nil, fmt.Errorf("Expected certificate expiry date to be %v, but got %v", certificate.Status.NotAfter, cert.NotAfter)
	}

	label, ok := secret.Annotations[cmapi.CertificateNameKey]
	if !ok {
		return nil, fmt.Errorf("Expected secret to have certificate-name label, but had none")
	}

	if label != certificate.Name {
		return nil, fmt.Errorf("Expected secret to have certificate-name label with a value of %q, but got %q", certificate.Name, label)
	}

	certificateKeyUsages, certificateExtKeyUsages, err := pki.BuildKeyUsages(certificate.Spec.Usages, certificate.Spec.IsCA)
	if err != nil {
		return nil, fmt.Errorf("failed to build key usages from certificate: %s", err)
	}

	defaultCertKeyUsages, defaultCertExtKeyUsages, err := h.defaultKeyUsagesToAdd(certificate.Namespace, &certificate.Spec.IssuerRef, certificate.Spec.KeyAlgorithm)
	if err != nil {
		return nil, err
	}

	certificateKeyUsages |= defaultCertKeyUsages
	certificateExtKeyUsages = append(certificateExtKeyUsages, defaultCertExtKeyUsages...)

	if !h.keyUsagesMatch(cert.KeyUsage, cert.ExtKeyUsage,
		certificateKeyUsages, certificateExtKeyUsages) {
		return nil, fmt.Errorf("key usages and extended key usages do not match: exp=%s got=%s exp=%s got=%s",
			apiutil.KeyUsageStrings(certificateKeyUsages), apiutil.KeyUsageStrings(cert.KeyUsage),
			apiutil.ExtKeyUsageStrings(certificateExtKeyUsages), apiutil.ExtKeyUsageStrings(cert.ExtKeyUsage))
	}

	var dnsName string
	if len(expectedDNSNames) > 0 {
		dnsName = expectedDNSNames[0]
	}

	// TODO: move this verification step out of this function
	if rootCAPEM != nil {
		rootCertPool := x509.NewCertPool()
		rootCertPool.AppendCertsFromPEM(rootCAPEM)
		intermediateCertPool := x509.NewCertPool()
		intermediateCertPool.AppendCertsFromPEM(certBytes)
		opts := x509.VerifyOptions{
			DNSName:       dnsName,
			Intermediates: intermediateCertPool,
			Roots:         rootCertPool,
		}

		if _, err := cert.Verify(opts); err != nil {
			return nil, err
		}
	}

	return cert, nil
}

func (h *Helper) WaitCertificateIssuedValid(ns, name string, timeout time.Duration) error {
	return h.WaitCertificateIssuedValidTLS(ns, name, timeout, nil)
}

func (h *Helper) defaultKeyUsagesToAdd(ns string, issuerRef *cmmeta.ObjectReference, keyType cmapi.KeyAlgorithm) (x509.KeyUsage, []x509.ExtKeyUsage, error) {
	var issuerSpec *cmapi.IssuerSpec
	switch issuerRef.Kind {
	case "ClusterIssuer":
		issuerObj, err := h.CMClient.CertmanagerV1alpha2().ClusterIssuers().Get(issuerRef.Name, metav1.GetOptions{})
		if err != nil {
			return 0, nil, fmt.Errorf("failed to find referenced ClusterIssuer %v: %s",
				issuerRef, err)
		}

		issuerSpec = &issuerObj.Spec
	default:
		issuerObj, err := h.CMClient.CertmanagerV1alpha2().Issuers(ns).Get(issuerRef.Name, metav1.GetOptions{})
		if err != nil {
			return 0, nil, fmt.Errorf("failed to find referenced Issuer %v: %s",
				issuerRef, err)
		}

		issuerSpec = &issuerObj.Spec
	}

	var keyUsages x509.KeyUsage
	var extKeyUsages []x509.ExtKeyUsage

	// Vault and ACME issuers will add server auth and client auth extended key
	// usages by default so we need to add them to the list of expected usages
	if issuerSpec.ACME != nil || issuerSpec.Vault != nil {
		extKeyUsages = append(extKeyUsages, x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth)
	}

	// Vault issuers will add key agreement key usage
	if issuerSpec.Vault != nil {
		keyUsages |= x509.KeyUsageKeyAgreement
	}

	// Venafi issue adds server auth key usage
	if issuerSpec.Venafi != nil {
		extKeyUsages = append(extKeyUsages, x509.ExtKeyUsageServerAuth)
	}

	// If using DNS01 ACME issuer with ECDSA then remove key encipherment
	if issuerSpec.ACME != nil &&
		issuerSpec.ACME.Solvers[0].DNS01 != nil &&
		(keyType == cmapi.ECDSAKeyAlgorithm || keyType == "") {
		keyUsages &= (x509.KeyUsageKeyEncipherment ^ 1) // remove key encipherment bit if exists
	}

	return keyUsages, extKeyUsages, nil
}

func (h *Helper) keyUsagesMatch(aKU x509.KeyUsage, aEKU []x509.ExtKeyUsage,
	bKU x509.KeyUsage, bEKU []x509.ExtKeyUsage) bool {
	if aKU != bKU {
		return false
	}

	if len(aEKU) != len(bEKU) {
		return false
	}

	sort.SliceStable(aEKU, func(i, j int) bool {
		return aEKU[i] < aEKU[j]
	})

	sort.SliceStable(bEKU, func(i, j int) bool {
		return bEKU[i] < bEKU[j]
	})

	for i := range aEKU {
		if aEKU[i] != bEKU[i] {
			return false
		}
	}

	return true
}

func (h *Helper) WaitCertificateIssuedValidTLS(ns, name string, timeout time.Duration, rootCAPEM []byte) error {
	certificate, err := h.WaitForCertificateReady(ns, name, timeout)
	if err != nil {
		log.Logf("Error waiting for Certificate to become Ready: %v", err)
		h.Kubectl(ns).DescribeResource("certificate", name)
		h.Kubectl(ns).Describe("order", "challenge")
		h.describeCertificateRequestFromCertificate(ns, certificate)
		return err
	}

	_, err = h.ValidateIssuedCertificate(certificate, rootCAPEM)
	if err != nil {
		log.Logf("Error validating issued certificate: %v", err)
		h.Kubectl(ns).DescribeResource("certificate", name)
		h.Kubectl(ns).Describe("order", "challenge")
		h.describeCertificateRequestFromCertificate(ns, certificate)
		return err
	}

	return nil
}

func (h *Helper) describeCertificateRequestFromCertificate(ns string, certificate *cmapi.Certificate) {
	if certificate == nil {
		return
	}

	crName, err := apiutil.ComputeCertificateRequestName(certificate)
	if err != nil {
		log.Logf("Failed to compute CertificateRequest name from certificate: %s", err)
		return
	}
	h.Kubectl(ns).DescribeResource("certificaterequest", crName)
}
<commit_msg>Ensure no ECDSA keys have key enrichment expected for e2e<commit_after>/*
Copyright 2019 The Jetstack cert-manager contributors.

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 helper

import (
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/x509"
	"fmt"
	"sort"
	"time"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"

	apiutil "github.com/jetstack/cert-manager/pkg/api/util"
	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
	"github.com/jetstack/cert-manager/pkg/util"
	"github.com/jetstack/cert-manager/pkg/util/pki"
	"github.com/jetstack/cert-manager/test/e2e/framework/log"
)

// WaitForCertificateReady waits for the certificate resource to enter a Ready
// state.
func (h *Helper) WaitForCertificateReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
	var certificate *cmapi.Certificate
	err := wait.PollImmediate(time.Second, timeout,
		func() (bool, error) {
			var err error
			log.Logf("Waiting for Certificate %v to be ready", name)
			certificate, err = h.CMClient.CertmanagerV1alpha2().Certificates(ns).Get(name, metav1.GetOptions{})
			if err != nil {
				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
			}
			isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
				Type:   cmapi.CertificateConditionReady,
				Status: cmmeta.ConditionTrue,
			})
			if !isReady {
				log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
				return false, nil
			}
			return true, nil
		},
	)

	// return certificate even when error to use for debugging
	return certificate, err
}

// WaitForCertificateNotReady waits for the certificate resource to enter a
// non-Ready state.
func (h *Helper) WaitForCertificateNotReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
	var certificate *cmapi.Certificate
	err := wait.PollImmediate(time.Second, timeout,
		func() (bool, error) {
			var err error
			log.Logf("Waiting for Certificate %v to be ready", name)
			certificate, err = h.CMClient.CertmanagerV1alpha2().Certificates(ns).Get(name, metav1.GetOptions{})
			if err != nil {
				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
			}
			isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
				Type:   cmapi.CertificateConditionReady,
				Status: cmmeta.ConditionFalse,
			})
			if !isReady {
				log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
				return false, nil
			}
			return true, nil
		},
	)

	// return certificate even when error to use for debugging
	return certificate, err
}

// ValidateIssuedCertificate will ensure that the given Certificate has a
// certificate issued for it, and that the details on the x509 certificate are
// correct as defined by the Certificate's spec.
func (h *Helper) ValidateIssuedCertificate(certificate *cmapi.Certificate, rootCAPEM []byte) (*x509.Certificate, error) {
	log.Logf("Getting the TLS certificate Secret resource")
	secret, err := h.KubeClient.CoreV1().Secrets(certificate.Namespace).Get(certificate.Spec.SecretName, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
	if !(len(secret.Data) == 2 || len(secret.Data) == 3) {
		return nil, fmt.Errorf("Expected 2 keys in certificate secret, but there was %d", len(secret.Data))
	}

	keyBytes, ok := secret.Data[corev1.TLSPrivateKeyKey]
	if !ok {
		return nil, fmt.Errorf("No private key data found for Certificate %q (secret %q)", certificate.Name, certificate.Spec.SecretName)
	}
	key, err := pki.DecodePrivateKeyBytes(keyBytes)
	if err != nil {
		return nil, err
	}

	// validate private key is of the correct type (rsa or ecdsa)
	switch certificate.Spec.KeyAlgorithm {
	case cmapi.KeyAlgorithm(""),
		cmapi.RSAKeyAlgorithm:
		_, ok := key.(*rsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("Expected private key of type RSA, but it was: %T", key)
		}
	case cmapi.ECDSAKeyAlgorithm:
		_, ok := key.(*ecdsa.PrivateKey)
		if !ok {
			return nil, fmt.Errorf("Expected private key of type ECDSA, but it was: %T", key)
		}
	default:
		return nil, fmt.Errorf("unrecognised requested private key algorithm %q", certificate.Spec.KeyAlgorithm)
	}

	// TODO: validate private key KeySize

	// check the provided certificate is valid
	expectedOrganization := pki.OrganizationForCertificate(certificate)
	expectedDNSNames := certificate.Spec.DNSNames
	uris, err := pki.URIsForCertificate(certificate)
	if err != nil {
		return nil, fmt.Errorf("failed to parse URIs: %s", err)
	}

	expectedURIs := pki.URLsToString(uris)

	certBytes, ok := secret.Data[corev1.TLSCertKey]
	if !ok {
		return nil, fmt.Errorf("No certificate data found for Certificate %q (secret %q)", certificate.Name, certificate.Spec.SecretName)
	}

	cert, err := pki.DecodeX509CertificateBytes(certBytes)
	if err != nil {
		return nil, err
	}

	commonNameCorrect := true
	expectedCN := certificate.Spec.CommonName
	if len(expectedCN) == 0 && len(cert.Subject.CommonName) > 0 {
		if !util.Contains(cert.DNSNames, cert.Subject.CommonName) {
			commonNameCorrect = false
		}
	} else if expectedCN != cert.Subject.CommonName {
		commonNameCorrect = false
	}

	if !commonNameCorrect || !util.Subset(cert.DNSNames, expectedDNSNames) || !util.EqualUnsorted(pki.URLsToString(cert.URIs), expectedURIs) ||
		!(len(cert.Subject.Organization) == 0 || util.EqualUnsorted(cert.Subject.Organization, expectedOrganization)) {
		return nil, fmt.Errorf("Expected certificate valid for CN %q, O %v, dnsNames %v, uriSANs %v,but got a certificate valid for CN %q, O %v, dnsNames %v, uriSANs %v",
			expectedCN, expectedOrganization, expectedDNSNames, expectedURIs, cert.Subject.CommonName, cert.Subject.Organization, cert.DNSNames, cert.URIs)
	}

	if certificate.Status.NotAfter == nil {
		return nil, fmt.Errorf("No certificate expiration found for Certificate %q", certificate.Name)
	}
	if !cert.NotAfter.Equal(certificate.Status.NotAfter.Time) {
		return nil, fmt.Errorf("Expected certificate expiry date to be %v, but got %v", certificate.Status.NotAfter, cert.NotAfter)
	}

	label, ok := secret.Annotations[cmapi.CertificateNameKey]
	if !ok {
		return nil, fmt.Errorf("Expected secret to have certificate-name label, but had none")
	}

	if label != certificate.Name {
		return nil, fmt.Errorf("Expected secret to have certificate-name label with a value of %q, but got %q", certificate.Name, label)
	}

	certificateKeyUsages, certificateExtKeyUsages, err := pki.BuildKeyUsages(certificate.Spec.Usages, certificate.Spec.IsCA)
	if err != nil {
		return nil, fmt.Errorf("failed to build key usages from certificate: %s", err)
	}

	defaultCertKeyUsages, defaultCertExtKeyUsages, err := h.defaultKeyUsagesToAdd(certificate.Namespace, &certificate.Spec.IssuerRef, certificate.Spec.KeyAlgorithm)
	if err != nil {
		return nil, err
	}

	certificateKeyUsages |= defaultCertKeyUsages
	certificateExtKeyUsages = append(certificateExtKeyUsages, defaultCertExtKeyUsages...)

	if !h.keyUsagesMatch(cert.KeyUsage, cert.ExtKeyUsage,
		certificateKeyUsages, certificateExtKeyUsages) {
		return nil, fmt.Errorf("key usages and extended key usages do not match: exp=%s got=%s exp=%s got=%s",
			apiutil.KeyUsageStrings(certificateKeyUsages), apiutil.KeyUsageStrings(cert.KeyUsage),
			apiutil.ExtKeyUsageStrings(certificateExtKeyUsages), apiutil.ExtKeyUsageStrings(cert.ExtKeyUsage))
	}

	var dnsName string
	if len(expectedDNSNames) > 0 {
		dnsName = expectedDNSNames[0]
	}

	// TODO: move this verification step out of this function
	if rootCAPEM != nil {
		rootCertPool := x509.NewCertPool()
		rootCertPool.AppendCertsFromPEM(rootCAPEM)
		intermediateCertPool := x509.NewCertPool()
		intermediateCertPool.AppendCertsFromPEM(certBytes)
		opts := x509.VerifyOptions{
			DNSName:       dnsName,
			Intermediates: intermediateCertPool,
			Roots:         rootCertPool,
		}

		if _, err := cert.Verify(opts); err != nil {
			return nil, err
		}
	}

	return cert, nil
}

func (h *Helper) WaitCertificateIssuedValid(ns, name string, timeout time.Duration) error {
	return h.WaitCertificateIssuedValidTLS(ns, name, timeout, nil)
}

func (h *Helper) defaultKeyUsagesToAdd(ns string, issuerRef *cmmeta.ObjectReference, keyType cmapi.KeyAlgorithm) (x509.KeyUsage, []x509.ExtKeyUsage, error) {
	var issuerSpec *cmapi.IssuerSpec
	switch issuerRef.Kind {
	case "ClusterIssuer":
		issuerObj, err := h.CMClient.CertmanagerV1alpha2().ClusterIssuers().Get(issuerRef.Name, metav1.GetOptions{})
		if err != nil {
			return 0, nil, fmt.Errorf("failed to find referenced ClusterIssuer %v: %s",
				issuerRef, err)
		}

		issuerSpec = &issuerObj.Spec
	default:
		issuerObj, err := h.CMClient.CertmanagerV1alpha2().Issuers(ns).Get(issuerRef.Name, metav1.GetOptions{})
		if err != nil {
			return 0, nil, fmt.Errorf("failed to find referenced Issuer %v: %s",
				issuerRef, err)
		}

		issuerSpec = &issuerObj.Spec
	}

	var keyUsages x509.KeyUsage
	var extKeyUsages []x509.ExtKeyUsage

	// Vault and ACME issuers will add server auth and client auth extended key
	// usages by default so we need to add them to the list of expected usages
	if issuerSpec.ACME != nil || issuerSpec.Vault != nil {
		extKeyUsages = append(extKeyUsages, x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth)
	}

	// Vault issuers will add key agreement key usage
	if issuerSpec.Vault != nil {
		keyUsages |= x509.KeyUsageKeyAgreement
	}

	// Venafi issue adds server auth key usage
	if issuerSpec.Venafi != nil {
		extKeyUsages = append(extKeyUsages, x509.ExtKeyUsageServerAuth)
	}

	// If using ECDSA then remove key encipherment
	if keyType == cmapi.ECDSAKeyAlgorithm {
		keyUsages &= (x509.KeyUsageKeyEncipherment ^ 1) // remove key encipherment bit if exists
	}

	return keyUsages, extKeyUsages, nil
}

func (h *Helper) keyUsagesMatch(aKU x509.KeyUsage, aEKU []x509.ExtKeyUsage,
	bKU x509.KeyUsage, bEKU []x509.ExtKeyUsage) bool {
	if aKU != bKU {
		return false
	}

	if len(aEKU) != len(bEKU) {
		return false
	}

	sort.SliceStable(aEKU, func(i, j int) bool {
		return aEKU[i] < aEKU[j]
	})

	sort.SliceStable(bEKU, func(i, j int) bool {
		return bEKU[i] < bEKU[j]
	})

	for i := range aEKU {
		if aEKU[i] != bEKU[i] {
			return false
		}
	}

	return true
}

func (h *Helper) WaitCertificateIssuedValidTLS(ns, name string, timeout time.Duration, rootCAPEM []byte) error {
	certificate, err := h.WaitForCertificateReady(ns, name, timeout)
	if err != nil {
		log.Logf("Error waiting for Certificate to become Ready: %v", err)
		h.Kubectl(ns).DescribeResource("certificate", name)
		h.Kubectl(ns).Describe("order", "challenge")
		h.describeCertificateRequestFromCertificate(ns, certificate)
		return err
	}

	_, err = h.ValidateIssuedCertificate(certificate, rootCAPEM)
	if err != nil {
		log.Logf("Error validating issued certificate: %v", err)
		h.Kubectl(ns).DescribeResource("certificate", name)
		h.Kubectl(ns).Describe("order", "challenge")
		h.describeCertificateRequestFromCertificate(ns, certificate)
		return err
	}

	return nil
}

func (h *Helper) describeCertificateRequestFromCertificate(ns string, certificate *cmapi.Certificate) {
	if certificate == nil {
		return
	}

	crName, err := apiutil.ComputeCertificateRequestName(certificate)
	if err != nil {
		log.Logf("Failed to compute CertificateRequest name from certificate: %s", err)
		return
	}
	h.Kubectl(ns).DescribeResource("certificaterequest", crName)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative 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 v1alpha1

import (
	"time"

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

	"github.com/knative/pkg/apis"
	"github.com/knative/pkg/apis/duck"
)

// Conditions is the schema for the conditions portion of the payload
type Conditions []Condition

// ConditionType is a camel-cased condition type.
type ConditionType string

const (
	// ConditionReady specifies that the resource is ready.
	// For long-running resources.
	ConditionReady ConditionType = "Ready"
	// ConditionSucceeded specifies that the resource has finished.
	// For resource which run to completion.
	ConditionSucceeded ConditionType = "Succeeded"
)

// ConditionSeverity expresses the severity of a Condition Type failing.
type ConditionSeverity string

const (
	// ConditionSeverityError specifies that a failure of a condition type
	// should be viewed as an error.  As "Error" is the default for conditions
	// we use the empty string (coupled with omitempty) to avoid confusion in
	// the case where the condition is in state "True" (aka nothing is wrong).
	ConditionSeverityError ConditionSeverity = ""
	// ConditionSeverityWarning specifies that a failure of a condition type
	// should be viewed as a warning, but that things could still work.
	ConditionSeverityWarning ConditionSeverity = "Warning"
	// ConditionSeverityInfo specifies that a failure of a condition type
	// should be viewed as purely informational, and that things could still work.
	ConditionSeverityInfo ConditionSeverity = "Info"
)

// Conditions defines a readiness condition for a Knative resource.
// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties
// +k8s:deepcopy-gen=true
type Condition struct {
	// Type of condition.
	// +required
	Type ConditionType `json:"type" description:"type of status condition"`

	// Status of the condition, one of True, False, Unknown.
	// +required
	Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"`

	// Severity with which to treat failures of this type of condition.
	// When this is not specified, it defaults to Error.
	// +optional
	Severity ConditionSeverity `json:"severity,omitempty" description:"how to interpret failures of this condition, one of Error, Warning, Info"`

	// LastTransitionTime is the last time the condition transitioned from one status to another.
	// We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic
	// differences (all other things held constant).
	// +optional
	LastTransitionTime apis.VolatileTime `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another"`

	// The reason for the condition's last transition.
	// +optional
	Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"`

	// A human readable message indicating details about the transition.
	// +optional
	Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"`
}

// IsTrue is true if the condition is True
func (c *Condition) IsTrue() bool {
	if c == nil {
		return false
	}
	return c.Status == corev1.ConditionTrue
}

// IsFalse is true if the condition is False
func (c *Condition) IsFalse() bool {
	if c == nil {
		return false
	}
	return c.Status == corev1.ConditionFalse
}

// IsUnknown is true if the condition is Unknown
func (c *Condition) IsUnknown() bool {
	if c == nil {
		return true
	}
	return c.Status == corev1.ConditionUnknown
}

// Conditions is an Implementable "duck type".
var _ duck.Implementable = (*Conditions)(nil)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// KResource is a skeleton type wrapping Conditions in the manner we expect
// resource writers defining compatible resources to embed it.  We will
// typically use this type to deserialize Conditions ObjectReferences and
// access the Conditions data.  This is not a real resource.
type KResource struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Status Status `json:"status"`
}

// Status shows how we expect folks to embed Conditions in
// their Status field.
type Status struct {
	// ObservedGeneration is the 'Generation' of the Service that
	// was last processed by the controller.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// +optional
	Conditions Conditions `json:"conditions,omitempty"`
}

// TODO: KResourceStatus is added for backwards compatibility for <= 0.4.0 releases. Remove later.
// KResourceStatus [Deprecated] use Status directly. Will be deleted ~0.6.0 release.
type KResourceStatus Status

// In order for Conditions to be Implementable, KResource must be Populatable.
var _ duck.Populatable = (*KResource)(nil)

// Ensure KResource satisfies apis.Listable
var _ apis.Listable = (*KResource)(nil)

// GetFullType implements duck.Implementable
func (_ *Conditions) GetFullType() duck.Populatable {
	return &KResource{}
}

// Populate implements duck.Populatable
func (t *KResource) Populate() {
	t.Status.ObservedGeneration = 42
	t.Status.Conditions = Conditions{{
		// Populate ALL fields
		Type:               "Birthday",
		Status:             corev1.ConditionTrue,
		LastTransitionTime: apis.VolatileTime{Inner: metav1.NewTime(time.Date(1984, 02, 28, 18, 52, 00, 00, time.UTC))},
		Reason:             "Celebrate",
		Message:            "n3wScott, find your party hat :tada:",
	}}
}

// GetListType implements apis.Listable
func (r *KResource) GetListType() runtime.Object {
	return &KResourceList{}
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// KResourceList is a list of KResource resources
type KResourceList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`

	Items []KResource `json:"items"`
}
<commit_msg>Need to use patch merge for conditions. (#328)<commit_after>/*
Copyright 2018 The Knative 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 v1alpha1

import (
	"time"

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

	"github.com/knative/pkg/apis"
	"github.com/knative/pkg/apis/duck"
)

// Conditions is the schema for the conditions portion of the payload
type Conditions []Condition

// ConditionType is a camel-cased condition type.
type ConditionType string

const (
	// ConditionReady specifies that the resource is ready.
	// For long-running resources.
	ConditionReady ConditionType = "Ready"
	// ConditionSucceeded specifies that the resource has finished.
	// For resource which run to completion.
	ConditionSucceeded ConditionType = "Succeeded"
)

// ConditionSeverity expresses the severity of a Condition Type failing.
type ConditionSeverity string

const (
	// ConditionSeverityError specifies that a failure of a condition type
	// should be viewed as an error.  As "Error" is the default for conditions
	// we use the empty string (coupled with omitempty) to avoid confusion in
	// the case where the condition is in state "True" (aka nothing is wrong).
	ConditionSeverityError ConditionSeverity = ""
	// ConditionSeverityWarning specifies that a failure of a condition type
	// should be viewed as a warning, but that things could still work.
	ConditionSeverityWarning ConditionSeverity = "Warning"
	// ConditionSeverityInfo specifies that a failure of a condition type
	// should be viewed as purely informational, and that things could still work.
	ConditionSeverityInfo ConditionSeverity = "Info"
)

// Conditions defines a readiness condition for a Knative resource.
// See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties
// +k8s:deepcopy-gen=true
type Condition struct {
	// Type of condition.
	// +required
	Type ConditionType `json:"type" description:"type of status condition"`

	// Status of the condition, one of True, False, Unknown.
	// +required
	Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"`

	// Severity with which to treat failures of this type of condition.
	// When this is not specified, it defaults to Error.
	// +optional
	Severity ConditionSeverity `json:"severity,omitempty" description:"how to interpret failures of this condition, one of Error, Warning, Info"`

	// LastTransitionTime is the last time the condition transitioned from one status to another.
	// We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic
	// differences (all other things held constant).
	// +optional
	LastTransitionTime apis.VolatileTime `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another"`

	// The reason for the condition's last transition.
	// +optional
	Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"`

	// A human readable message indicating details about the transition.
	// +optional
	Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"`
}

// IsTrue is true if the condition is True
func (c *Condition) IsTrue() bool {
	if c == nil {
		return false
	}
	return c.Status == corev1.ConditionTrue
}

// IsFalse is true if the condition is False
func (c *Condition) IsFalse() bool {
	if c == nil {
		return false
	}
	return c.Status == corev1.ConditionFalse
}

// IsUnknown is true if the condition is Unknown
func (c *Condition) IsUnknown() bool {
	if c == nil {
		return true
	}
	return c.Status == corev1.ConditionUnknown
}

// Conditions is an Implementable "duck type".
var _ duck.Implementable = (*Conditions)(nil)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// KResource is a skeleton type wrapping Conditions in the manner we expect
// resource writers defining compatible resources to embed it.  We will
// typically use this type to deserialize Conditions ObjectReferences and
// access the Conditions data.  This is not a real resource.
type KResource struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Status Status `json:"status"`
}

// Status shows how we expect folks to embed Conditions in
// their Status field.
// WARNING: Adding fields to this struct will add them to all Knative resources.
type Status struct {
	// ObservedGeneration is the 'Generation' of the Service that
	// was last processed by the controller.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// Conditions the latest available observations of a resource's current state.
	// +optional
	// +patchMergeKey=type
	// +patchStrategy=merge
	Conditions Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

// TODO: KResourceStatus is added for backwards compatibility for <= 0.4.0 releases. Remove later.
// KResourceStatus [Deprecated] use Status directly. Will be deleted ~0.6.0 release.
type KResourceStatus Status

// In order for Conditions to be Implementable, KResource must be Populatable.
var _ duck.Populatable = (*KResource)(nil)

// Ensure KResource satisfies apis.Listable
var _ apis.Listable = (*KResource)(nil)

// GetFullType implements duck.Implementable
func (_ *Conditions) GetFullType() duck.Populatable {
	return &KResource{}
}

// Populate implements duck.Populatable
func (t *KResource) Populate() {
	t.Status.ObservedGeneration = 42
	t.Status.Conditions = Conditions{{
		// Populate ALL fields
		Type:               "Birthday",
		Status:             corev1.ConditionTrue,
		LastTransitionTime: apis.VolatileTime{Inner: metav1.NewTime(time.Date(1984, 02, 28, 18, 52, 00, 00, time.UTC))},
		Reason:             "Celebrate",
		Message:            "n3wScott, find your party hat :tada:",
	}}
}

// GetListType implements apis.Listable
func (r *KResource) GetListType() runtime.Object {
	return &KResourceList{}
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// KResourceList is a list of KResource resources
type KResourceList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`

	Items []KResource `json:"items"`
}
<|endoftext|>


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

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

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

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

package integration

import (
	"context"
	"encoding/json"
	"os/exec"
	"testing"

	"k8s.io/minikube/pkg/minikube/config"
)

// profileJSON is the output of `minikube profile list -ojson`
type profileJSON struct {
	Valid   []config.Profile `json:"valid"`
	Invalid []config.Profile `json:"invalid"`
}

func TestMinikubeProfile(t *testing.T) {
	// 1. Setup two minikube cluster profiles
	profiles := [2]string{UniqueProfileName("first"), UniqueProfileName("second")}
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(10))
	// TODO(@vharsh): Figure out why go vet complains when this is moved into a loop
	defer CleanupWithLogs(t, profiles[0], cancel)
	defer CleanupWithLogs(t, profiles[1], cancel)
	for _, p := range profiles {
		rr, err := Run(t, exec.CommandContext(ctx, Target(), "start", "-p", p))
		if err != nil {
			t.Fatalf("test pre-condition failed. args %q: %v", rr.Command(), err)
		}
	}
	// 2. Change minikube profile
	for _, p := range profiles {
		rr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", p))
		if err != nil {
			t.Fatalf("cmd: %s failed with error: %v\n", rr.Command(), err)
		}
		r, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list", "-ojson"))
		if err != nil {
			t.Fatalf("cmd: %s failed with error: %v\n", r.Command(), err)
		}
		var profile profileJSON
		err = json.NewDecoder(r.Stdout).Decode(&profile)
		if err != nil {
			t.Fatalf("unmarshalling %s cmd output failed with error: %v\n", r.Command(), err)
		}
		// 3. Assert minikube profile is set to the correct profile in JSON
		for _, s := range profile.Valid {
			if s.Name == p && !s.Active {
				t.Errorf("minikube profile %s is not active\n", p)
			} else if s.Name != p && s.Active {
				t.Errorf("minikube profile %s should not have been active but is active\n", p)
			}
		}
	}
}
<commit_msg>add the StartArgs() suffix as supplied by test suite<commit_after>/*
Copyright 2022 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"context"
	"encoding/json"
	"os/exec"
	"testing"

	"k8s.io/minikube/pkg/minikube/config"
)

// profileJSON is the output of `minikube profile list -ojson`
type profileJSON struct {
	Valid   []config.Profile `json:"valid"`
	Invalid []config.Profile `json:"invalid"`
}

func TestMinikubeProfile(t *testing.T) {
	// 1. Setup two minikube cluster profiles
	profiles := [2]string{UniqueProfileName("first"), UniqueProfileName("second")}
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(10))
	// TODO(@vharsh): Figure out why go vet complains when this is moved into a loop
	defer CleanupWithLogs(t, profiles[0], cancel)
	defer CleanupWithLogs(t, profiles[1], cancel)
	for _, p := range profiles {
		c := []string{"start", "-p", p}
		c = append(c, StartArgs()...)
		rr, err := Run(t, exec.CommandContext(ctx, Target(), c...))
		if err != nil {
			t.Fatalf("test pre-condition failed. args %q: %v", rr.Command(), err)
		}
	}
	// 2. Change minikube profile
	for _, p := range profiles {
		rr, err := Run(t, exec.CommandContext(ctx, Target(), "profile", p))
		if err != nil {
			t.Fatalf("cmd: %s failed with error: %v\n", rr.Command(), err)
		}
		r, err := Run(t, exec.CommandContext(ctx, Target(), "profile", "list", "-ojson"))
		if err != nil {
			t.Fatalf("cmd: %s failed with error: %v\n", r.Command(), err)
		}
		var profile profileJSON
		err = json.NewDecoder(r.Stdout).Decode(&profile)
		if err != nil {
			t.Fatalf("unmarshalling %s cmd output failed with error: %v\n", r.Command(), err)
		}
		// 3. Assert minikube profile is set to the correct profile in JSON
		for _, s := range profile.Valid {
			if s.Name == p && !s.Active {
				t.Errorf("minikube profile %s is not active\n", p)
			} else if s.Name != p && s.Active {
				t.Errorf("minikube profile %s should not have been active but is active\n", p)
			}
		}
	}
}
<|endoftext|>


<commit_before>package netsync

import (
	"math/rand"

	log "github.com/sirupsen/logrus"

	"github.com/bytom/protocol/bc/types"
)

const (
	// This is the target size for the packs of transactions sent by txSyncLoop.
	// A pack can get larger than this if a single transactions exceeds this size.
	txSyncPackSize = 100 * 1024
)

type txSyncMsg struct {
	peerID string
	txs    []*types.Tx
}

func (sm *SyncManager) syncTransactions(peerID string) {
	pending := sm.txPool.GetTransactions()
	if len(pending) == 0 {
		return
	}

	txs := make([]*types.Tx, len(pending))
	for i, batch := range pending {
		txs[i] = batch.Tx
	}
	sm.txSyncCh <- &txSyncMsg{peerID, txs}
}

func (sm *SyncManager) txBroadcastLoop() {
	for {
		select {
		case newTx := <-sm.newTxCh:
			if err := sm.peers.broadcastTx(newTx); err != nil {
				log.Errorf("Broadcast new tx error. %v", err)
				return
			}
		case <-sm.quitSync:
			return
		}
	}
}

// txSyncLoop takes care of the initial transaction sync for each new
// connection. When a new peer appears, we relay all currently pending
// transactions. In order to minimise egress bandwidth usage, we send
// the transactions in small packs to one peer at a time.
func (sm *SyncManager) txSyncLoop() {
	pending := make(map[string]*txSyncMsg)
	sending := false            // whether a send is active
	done := make(chan error, 1) // result of the send

	// send starts a sending a pack of transactions from the sync.
	send := func(msg *txSyncMsg) {
		peer := sm.peers.getPeer(msg.peerID)
		if peer == nil {
			delete(pending, msg.peerID)
		}

		totalSize := uint64(0)
		sendTxs := []*types.Tx{}
		for i := 0; i < len(msg.txs) && totalSize < txSyncPackSize; i++ {
			sendTxs = append(sendTxs, msg.txs[i])
			totalSize += msg.txs[i].SerializedSize
		}

		copy(msg.txs, msg.txs[len(sendTxs):])
		if len(msg.txs) == 0 {
			delete(pending, msg.peerID)
		}

		// Send the pack in the background.
		log.WithFields(log.Fields{
			"count": len(sendTxs),
			"bytes": totalSize,
			"peer":  msg.peerID,
		}).Debug("txSyncLoop sending transactions")
		sending = true
		go func() {
			ok, err := peer.sendTransactions(sendTxs)
			if !ok {
				sm.peers.removePeer(msg.peerID)
			}
			done <- err
		}()
	}

	// pick chooses the next pending sync.
	pick := func() *txSyncMsg {
		if len(pending) == 0 {
			return nil
		}

		n := rand.Intn(len(pending)) + 1
		for _, s := range pending {
			if n--; n == 0 {
				return s
			}
		}
		return nil
	}

	for {
		select {
		case msg := <-sm.txSyncCh:
			pending[msg.peerID] = msg
			if !sending {
				send(msg)
			}

		case err := <-done:
			sending = false
			if err != nil {
				log.WithField("err", err).Warning("fail on txSyncLoop sending")
			}

			if s := pick(); s != nil {
				send(s)
			}
		}
	}
}
<commit_msg>Fix txSyncLoop null pointer error (#1150)<commit_after>package netsync

import (
	"math/rand"

	log "github.com/sirupsen/logrus"

	"github.com/bytom/protocol/bc/types"
)

const (
	// This is the target size for the packs of transactions sent by txSyncLoop.
	// A pack can get larger than this if a single transactions exceeds this size.
	txSyncPackSize = 100 * 1024
)

type txSyncMsg struct {
	peerID string
	txs    []*types.Tx
}

func (sm *SyncManager) syncTransactions(peerID string) {
	pending := sm.txPool.GetTransactions()
	if len(pending) == 0 {
		return
	}

	txs := make([]*types.Tx, len(pending))
	for i, batch := range pending {
		txs[i] = batch.Tx
	}
	sm.txSyncCh <- &txSyncMsg{peerID, txs}
}

func (sm *SyncManager) txBroadcastLoop() {
	for {
		select {
		case newTx := <-sm.newTxCh:
			if err := sm.peers.broadcastTx(newTx); err != nil {
				log.Errorf("Broadcast new tx error. %v", err)
				return
			}
		case <-sm.quitSync:
			return
		}
	}
}

// txSyncLoop takes care of the initial transaction sync for each new
// connection. When a new peer appears, we relay all currently pending
// transactions. In order to minimise egress bandwidth usage, we send
// the transactions in small packs to one peer at a time.
func (sm *SyncManager) txSyncLoop() {
	pending := make(map[string]*txSyncMsg)
	sending := false            // whether a send is active
	done := make(chan error, 1) // result of the send

	// send starts a sending a pack of transactions from the sync.
	send := func(msg *txSyncMsg) {
		peer := sm.peers.getPeer(msg.peerID)
		if peer == nil {
			delete(pending, msg.peerID)
			return
		}

		totalSize := uint64(0)
		sendTxs := []*types.Tx{}
		for i := 0; i < len(msg.txs) && totalSize < txSyncPackSize; i++ {
			sendTxs = append(sendTxs, msg.txs[i])
			totalSize += msg.txs[i].SerializedSize
		}

		if len(msg.txs) == len(sendTxs) {
			delete(pending, msg.peerID)
		} else {
			msg.txs = msg.txs[len(sendTxs):]
		}

		// Send the pack in the background.
		log.WithFields(log.Fields{
			"count": len(sendTxs),
			"bytes": totalSize,
			"peer":  msg.peerID,
		}).Debug("txSyncLoop sending transactions")
		sending = true
		go func() {
			ok, err := peer.sendTransactions(sendTxs)
			if !ok {
				sm.peers.removePeer(msg.peerID)
			}
			done <- err
		}()
	}

	// pick chooses the next pending sync.
	pick := func() *txSyncMsg {
		if len(pending) == 0 {
			return nil
		}

		n := rand.Intn(len(pending)) + 1
		for _, s := range pending {
			if n--; n == 0 {
				return s
			}
		}
		return nil
	}

	for {
		select {
		case msg := <-sm.txSyncCh:
			pending[msg.peerID] = msg
			if !sending {
				send(msg)
			}

		case err := <-done:
			sending = false
			if err != nil {
				log.WithField("err", err).Warning("fail on txSyncLoop sending")
			}

			if s := pick(); s != nil {
				send(s)
			}
		}
	}
}
<|endoftext|>


<commit_before>package model

import (
	"fmt"
	"github.com/lunixbochs/vtclean"
	"github.com/viant/endly"
	"github.com/viant/toolbox/data"
	"regexp"
	"strings"
)

//Extracts represents an expected data collection
type Extracts []*Extract

//Extracts extract data from provided inputs, the result is placed to expected map, or error
func (d *Extracts) Extract(context *endly.Context, extracted map[string]interface{}, inputs ...string) error {
	if len(*d) == 0 || len(inputs) == 0 {
		return nil
	}
	for _, extract := range *d {
		if extract.Reset {
			delete(extracted, extract.Key)
		}
	}

	cleanedInputs := make([]string, 0)
	for _, line := range inputs {
		cleanedInputs = append(cleanedInputs, vtclean.Clean(line, false))
	}

	cleanMultiLines := strings.Join(cleanedInputs, "\n")
	multiLines := strings.Join(inputs, "\n")

	for _, extract := range *d {
		compiledExpression, err := regexp.Compile(extract.RegExpr)
		if err != nil {
			return fmt.Errorf("failed to extract data - invlid regexpr: %v,  %v", extract.RegExpr, err)
		}
		if !matchExpression(compiledExpression, multiLines, extract, context, extracted) {
			if matchExpression(compiledExpression, cleanMultiLines, extract, context, extracted) {
				continue
			}
		}
    matched := false
		for _, line := range inputs {
			if len(line) == 0 {
				continue
			}
			if matchExpression(compiledExpression, line, extract, context, extracted) {
				matched = true
				continue
			}
			cleanedLine := vtclean.Clean(line, false)
			if(matchExpression(compiledExpression, cleanedLine, extract, context, extracted)) {
				matched = true
			}
		}
		if extract.Required && !matched {
			return fmt.Errorf("failed to extract required data - no match found for regexpr: %v,  %v", extract.RegExpr, multiLines)
		}
	}
	return nil
}

//Reset removes key from supplied state map.
func (d *Extracts) Reset(state data.Map) {
	for _, extract := range *d {
		if extract.Reset {
			delete(state, extract.Key)
		}
	}
}

//NewExtracts creates a new NewExtracts
func NewExtracts() Extracts {
	return make([]*Extract, 0)
}

//Extract represents a data extraction
type Extract struct {
	RegExpr  string `description:"regular expression with oval bracket to extract match pattern"`            //regular expression
	Key      string `description:"state key to store a match"`                                               //state key to store a match
	Reset    bool   `description:"reset the key in the context before evaluating this data extraction rule"` //reset the key in the context before evaluating this data extraction rule
  Required bool   `description:"require that at least one pattern match is returned"`                      //require that at least one pattern match is returned
}

//NewExtract creates a new data extraction
func NewExtract(key, regExpr string, reset bool, required bool) *Extract {
	return &Extract{
		RegExpr: regExpr,
		Key:     key,
		Reset:   reset,
    Required: required,
	}
}

//ExtractEvent  represents data extraction event
type ExtractEvent struct {
	Output           string
	StructuredOutput interface{}
	Data             interface{}
}

//NewExtractEvent creates a new event.
func NewExtractEvent(output string, structuredOutput, extracted interface{}) *ExtractEvent {
	return &ExtractEvent{
		Output:           output,
		StructuredOutput: structuredOutput,
		Data:             extracted,
	}
}

func matchExpression(compiledExpression *regexp.Regexp, line string, extract *Extract, context *endly.Context, extracted map[string]interface{}) bool {
	if compiledExpression.MatchString(line) {
		matched := compiledExpression.FindStringSubmatch(line)
		if extract.Key != "" {
			var state = context.State()
			var keyFragments = strings.Split(extract.Key, ".")
			for i, keyFragment := range keyFragments {
				if i+1 == len(keyFragments) {
					state.Put(extract.Key, matched[1])
					continue
				}
				if !state.Has(keyFragment) {
					state.Put(keyFragment, data.NewMap())
				}
				state = state.GetMap(keyFragment)

			}
		}
		extracted[extract.Key] = matched[1]
		return true
	}
	return false
}
<commit_msg>fixed formatting<commit_after>package model

import (
	"fmt"
	"github.com/lunixbochs/vtclean"
	"github.com/viant/endly"
	"github.com/viant/toolbox/data"
	"regexp"
	"strings"
)

//Extracts represents an expected data collection
type Extracts []*Extract

//Extracts extract data from provided inputs, the result is placed to expected map, or error
func (d *Extracts) Extract(context *endly.Context, extracted map[string]interface{}, inputs ...string) error {
	if len(*d) == 0 || len(inputs) == 0 {
		return nil
	}
	for _, extract := range *d {
		if extract.Reset {
			delete(extracted, extract.Key)
		}
	}

	cleanedInputs := make([]string, 0)
	for _, line := range inputs {
		cleanedInputs = append(cleanedInputs, vtclean.Clean(line, false))
	}

	cleanMultiLines := strings.Join(cleanedInputs, "\n")
	multiLines := strings.Join(inputs, "\n")

	for _, extract := range *d {
		compiledExpression, err := regexp.Compile(extract.RegExpr)
		if err != nil {
			return fmt.Errorf("failed to extract data - invlid regexpr: %v,  %v", extract.RegExpr, err)
		}
		if !matchExpression(compiledExpression, multiLines, extract, context, extracted) {
			if matchExpression(compiledExpression, cleanMultiLines, extract, context, extracted) {
				continue
			}
		}
    matched := false
		for _, line := range inputs {
			if len(line) == 0 {
				continue
			}
			if matchExpression(compiledExpression, line, extract, context, extracted) {
				matched = true
				continue
			}
			cleanedLine := vtclean.Clean(line, false)
			if(matchExpression(compiledExpression, cleanedLine, extract, context, extracted)) {
				matched = true
			}
		}
		if extract.Required && !matched {
			return fmt.Errorf("failed to extract required data - no match found for regexpr: %v,  %v", extract.RegExpr, multiLines)
		}
	}
	return nil
}

//Reset removes key from supplied state map.
func (d *Extracts) Reset(state data.Map) {
	for _, extract := range *d {
		if extract.Reset {
			delete(state, extract.Key)
		}
	}
}

//NewExtracts creates a new NewExtracts
func NewExtracts() Extracts {
	return make([]*Extract, 0)
}

//Extract represents a data extraction
type Extract struct {
	RegExpr  string `description:"regular expression with oval bracket to extract match pattern"`            //regular expression
	Key      string `description:"state key to store a match"`                                               //state key to store a match
	Reset    bool   `description:"reset the key in the context before evaluating this data extraction rule"` //reset the key in the context before evaluating this data extraction rule
	Required bool   `description:"require that at least one pattern match is returned"`                      //require that at least one pattern match is returned
}

//NewExtract creates a new data extraction
func NewExtract(key, regExpr string, reset bool, required bool) *Extract {
	return &Extract{
		RegExpr: regExpr,
		Key:     key,
		Reset:   reset,
    Required: required,
	}
}

//ExtractEvent  represents data extraction event
type ExtractEvent struct {
	Output           string
	StructuredOutput interface{}
	Data             interface{}
}

//NewExtractEvent creates a new event.
func NewExtractEvent(output string, structuredOutput, extracted interface{}) *ExtractEvent {
	return &ExtractEvent{
		Output:           output,
		StructuredOutput: structuredOutput,
		Data:             extracted,
	}
}

func matchExpression(compiledExpression *regexp.Regexp, line string, extract *Extract, context *endly.Context, extracted map[string]interface{}) bool {
	if compiledExpression.MatchString(line) {
		matched := compiledExpression.FindStringSubmatch(line)
		if extract.Key != "" {
			var state = context.State()
			var keyFragments = strings.Split(extract.Key, ".")
			for i, keyFragment := range keyFragments {
				if i+1 == len(keyFragments) {
					state.Put(extract.Key, matched[1])
					continue
				}
				if !state.Has(keyFragment) {
					state.Put(keyFragment, data.NewMap())
				}
				state = state.GetMap(keyFragment)

			}
		}
		extracted[extract.Key] = matched[1]
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os/exec"
	"path"
	"strings"

	"rollcage/core"

	"github.com/cactus/cobra"
	"github.com/cactus/gologit"
)

func umountCmd(args ...string) {
	cmd := exec.Command("/sbin/umount", args...)
	gologit.Debugln(append([]string{"/sbin/umount"}, args...))
	out, err := cmd.CombinedOutput()
	for _, line := range strings.Split(string(out), "\n") {
		if line != "" {
			gologit.Debugln(line)
		}
	}
	if err != nil {
		// some mounts are not present, so just fail
		// do not log exit status 1 unless debug logging
		gologit.Debugf("%s\n", err)
	}
}

func removeDash(s string) string {
	if s == "-" {
		return ""
	}
	return s
}

func stopCmdRun(cmd *cobra.Command, args []string) {
	// requires root
	if !core.IsRoot() {
		gologit.Fatalf("Must be root to stop\n")
	}

	jail, err := core.FindJail(args[0])
	if err != nil {
		gologit.Fatalf("No jail found by '%s'\n", args[0])
	}

	if !jail.IsRunning() {
		gologit.Fatalf("Jail is not running!\n")
	}

	props := jail.GetProperties()

	// set a default path
	/*
		environ := []string{
			"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
		}
	*/

	fmt.Printf("* Stopping %s (%s)\n", jail.HostUUID, jail.Tag)
	fmt.Printf("  + Removing jail process\n")
	jrexec := []string{"/usr/sbin/jail", "-r", fmt.Sprintf("ioc-%s", jail.HostUUID)}
	out, err = exec.Command(jrexec[0], jrexec[1:]...).CombinedOutput()
	if err != nil {
		gologit.Printf("%s\n", err)
	}

	if props.GetIOC("vnet") == "on" {
		fmt.Printf("  + Tearing down VNET\n")
		// stop VNET networking
	} else if props.GetIOC("ip4") != "inherit" {
		// stop standard networking (legacy?)
		lines := core.SplitOutput(core.ZFSMust(
			fmt.Errorf("Error listing jails"),
			"list", "-H", "-o", "org.freebsd.iocage:ip4_addr,org.freebsd.iocage:ip6_addr", jail.Path))
		for _, ip_config := range lines[0] {
			if ip_config == "none" {
				continue
			}
			for _, addr := range strings.Split(ip_config, ",") {
				item := strings.Split(addr, "|")
				gologit.Debugln("/sbin/ifconfig", item[0], item[1], "-alias")
				out, err := exec.Command("/sbin/ifconfig",
					item[0], item[1], "-alias").CombinedOutput()
				gologit.Debugln(string(out))
				if err != nil {
					gologit.Printf("%s\n", err)
				}
			}
		}
	}

	fmt.Printf("  + Tearing down mounts\n")
	umountCmd("-afvF", path.Join(jail.Mountpoint, "fstab"))
	umountCmd(path.Join(jail.Mountpoint, "root/dev/fd"))
	umountCmd(path.Join(jail.Mountpoint, "root/dev"))
	umountCmd(path.Join(jail.Mountpoint, "root/proc"))

	// TODO: basejail here?
	// TODO: rctl stuff here...
}

func init() {
	RootCmd.AddCommand(&cobra.Command{
		Use:   "stop UUID|TAG",
		Short: "stop jail",
		Long:  "Stop jail identified by UUID or TAG.",
		Run:   stopCmdRun,
		PreRun: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				gologit.Fatalln("Required UUID|TAG not provided")
			}
		},
	})
}
<commit_msg>refactor stopping<commit_after>package commands

import (
	"fmt"
	"os/exec"
	"path"
	"strings"

	"rollcage/core"

	"github.com/cactus/cobra"
	"github.com/cactus/gologit"
)

func umountCmd(args ...string) {
	cmd := exec.Command("/sbin/umount", args...)
	gologit.Debugln(append([]string{"/sbin/umount"}, args...))
	out, err := cmd.CombinedOutput()
	for _, line := range strings.Split(string(out), "\n") {
		if line != "" {
			gologit.Debugln(line)
		}
	}
	if err != nil {
		// some mounts are not present, so just fail
		// do not log exit status 1 unless debug logging
		gologit.Debugf("%s\n", err)
	}
}

func removeDash(s string) string {
	if s == "-" {
		return ""
	}
	return s
}

func stopCmdRun(cmd *cobra.Command, args []string) {
	// requires root
	if !core.IsRoot() {
		gologit.Fatalf("Must be root to stop\n")
	}

	jail, err := core.FindJail(args[0])
	if err != nil {
		gologit.Fatalf("No jail found by '%s'\n", args[0])
	}

	if !jail.IsRunning() {
		gologit.Fatalf("Jail is not running!\n")
	}

	props := jail.GetProperties()

	fmt.Printf("* Stopping %s (%s)\n", jail.HostUUID, jail.Tag)
	fmt.Printf("  + Removing jail process\n")
	jrexec := []string{"/usr/sbin/jail", "-r", fmt.Sprintf("ioc-%s", jail.HostUUID)}
	out, err := exec.Command(jrexec[0], jrexec[1:]...).CombinedOutput()
	if err != nil {
		gologit.Printf("%s\n", err)
	}

	if props.GetIOC("vnet") == "on" {
		fmt.Printf("  + Tearing down VNET\n")
		// stop VNET networking
	} else if props.GetIOC("ip4") != "inherit" {
		// stop standard networking (legacy?)
		lines := core.SplitOutput(core.ZFSMust(
			fmt.Errorf("Error listing jails"),
			"list", "-H", "-o", "org.freebsd.iocage:ip4_addr,org.freebsd.iocage:ip6_addr", jail.Path))
		for _, ip_config := range lines[0] {
			if ip_config == "none" {
				continue
			}
			for _, addr := range strings.Split(ip_config, ",") {
				item := strings.Split(addr, "|")
				gologit.Debugln("/sbin/ifconfig", item[0], item[1], "-alias")
				out, err := exec.Command("/sbin/ifconfig",
					item[0], item[1], "-alias").CombinedOutput()
				gologit.Debugln(string(out))
				if err != nil {
					gologit.Printf("%s\n", err)
				}
			}
		}
	}

	fmt.Printf("  + Tearing down mounts\n")
	umountCmd("-afvF", path.Join(jail.Mountpoint, "fstab"))
	umountCmd(path.Join(jail.Mountpoint, "root/dev/fd"))
	umountCmd(path.Join(jail.Mountpoint, "root/dev"))
	umountCmd(path.Join(jail.Mountpoint, "root/proc"))

	// TODO: basejail here?
	// TODO: rctl stuff here...
}

func init() {
	RootCmd.AddCommand(&cobra.Command{
		Use:   "stop UUID|TAG",
		Short: "stop jail",
		Long:  "Stop jail identified by UUID or TAG.",
		Run:   stopCmdRun,
		PreRun: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				gologit.Fatalln("Required UUID|TAG not provided")
			}
		},
	})
}
<|endoftext|>


<commit_before>// Copyright 2017 Prometheus Team
// 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 nflogpb

// IsFiringSubset returns whether the given subset is a subset of the alerts
// that were firing at the time of the last notification.
func (m *Entry) IsFiringSubset(subset map[uint64]struct{}) bool {
	set := map[uint64]struct{}{}
	for i := range m.FiringAlerts {
		set[m.FiringAlerts[i]] = struct{}{}
	}

	return isSubset(set, subset)
}

// IsFiringSubset returns whether the given subset is a subset of the alerts
// that were resolved at the time of the last notification.
func (m *Entry) IsResolvedSubset(subset map[uint64]struct{}) bool {
	set := map[uint64]struct{}{}
	for i := range m.ResolvedAlerts {
		set[m.ResolvedAlerts[i]] = struct{}{}
	}

	return isSubset(set, subset)
}

func isSubset(set, subset map[uint64]struct{}) bool {
	for k, _ := range subset {
		_, exists := set[k]
		if !exists {
			return false
		}
	}

	return true
}
<commit_msg>Fix documentation (#1065)<commit_after>// Copyright 2017 Prometheus Team
// 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 nflogpb

// IsFiringSubset returns whether the given subset is a subset of the alerts
// that were firing at the time of the last notification.
func (m *Entry) IsFiringSubset(subset map[uint64]struct{}) bool {
	set := map[uint64]struct{}{}
	for i := range m.FiringAlerts {
		set[m.FiringAlerts[i]] = struct{}{}
	}

	return isSubset(set, subset)
}

// IsResolvedSubset returns whether the given subset is a subset of the alerts
// that were resolved at the time of the last notification.
func (m *Entry) IsResolvedSubset(subset map[uint64]struct{}) bool {
	set := map[uint64]struct{}{}
	for i := range m.ResolvedAlerts {
		set[m.ResolvedAlerts[i]] = struct{}{}
	}

	return isSubset(set, subset)
}

func isSubset(set, subset map[uint64]struct{}) bool {
	for k, _ := range subset {
		_, exists := set[k]
		if !exists {
			return false
		}
	}

	return true
}
<|endoftext|>


<commit_before>package global

import (
	"regexp"
	"time"

	"code.cloudfoundry.org/cli/integration/helpers"

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

	"testing"
)

const (
	CFEventuallyTimeout   = 30 * time.Second
	CFConsistentlyTimeout = 500 * time.Millisecond
)

var (
	// Per Test Level
	homeDir       string
	ReadOnlyOrg   string
	ReadOnlySpace string
)

func TestGlobal(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Global Suite")
}

var _ = SynchronizedBeforeSuite(func() []byte {
	// Ginkgo Globals
	SetDefaultEventuallyTimeout(CFEventuallyTimeout)
	SetDefaultConsistentlyDuration(CFConsistentlyTimeout)

	// Setup common environment variables
	helpers.TurnOffColors()

	helpers.SetupSynchronizedSuite(func() {
		helpers.EnableFeatureFlag("diego_docker")
		helpers.EnableFeatureFlag("service_instance_sharing")
	})

	ReadOnlyOrg, ReadOnlySpace = helpers.SetupReadOnlyOrgAndSpace()

	return nil
}, func(_ []byte) {
	if GinkgoParallelNode() != 1 {
		Fail("Test suite cannot run in parallel")
	}
})

var _ = BeforeEach(func() {
	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
})

var _ = AfterEach(func() {
	GinkgoWriter.Write([]byte("==============================Global After Each=============================="))
	helpers.DestroyHomeDir(homeDir)
})

var foundDefaultDomain string

func defaultSharedDomain() string {
	// TODO: Move this into helpers when other packages need it, figure out how
	// to cache cuz this is a wacky call otherwise
	if foundDefaultDomain == "" {
		session := helpers.CF("domains")
		Eventually(session).Should(Exit(0))

		regex, err := regexp.Compile(`(.+?)\s+shared`)
		Expect(err).ToNot(HaveOccurred())

		matches := regex.FindStringSubmatch(string(session.Out.Contents()))
		Expect(matches).To(HaveLen(2))

		foundDefaultDomain = matches[1]
	}
	return foundDefaultDomain
}

func setupCF(org string, space string) {
	helpers.LoginCF()
	if org != ReadOnlyOrg && space != ReadOnlySpace {
		helpers.CreateOrgAndSpace(org, space)
	}
	helpers.TargetOrgAndSpace(org, space)
}
<commit_msg>increased the eventually timeout for the global integration suite<commit_after>package global

import (
	"regexp"
	"time"

	"code.cloudfoundry.org/cli/integration/helpers"

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

	"testing"
)

const (
	CFEventuallyTimeout   = 300 * time.Second
	CFConsistentlyTimeout = 500 * time.Millisecond
)

var (
	// Per Test Level
	homeDir       string
	ReadOnlyOrg   string
	ReadOnlySpace string
)

func TestGlobal(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Global Suite")
}

var _ = SynchronizedBeforeSuite(func() []byte {
	// Ginkgo Globals
	SetDefaultEventuallyTimeout(CFEventuallyTimeout)
	SetDefaultConsistentlyDuration(CFConsistentlyTimeout)

	// Setup common environment variables
	helpers.TurnOffColors()

	helpers.SetupSynchronizedSuite(func() {
		helpers.EnableFeatureFlag("diego_docker")
		helpers.EnableFeatureFlag("service_instance_sharing")
	})

	ReadOnlyOrg, ReadOnlySpace = helpers.SetupReadOnlyOrgAndSpace()

	return nil
}, func(_ []byte) {
	if GinkgoParallelNode() != 1 {
		Fail("Test suite cannot run in parallel")
	}
})

var _ = BeforeEach(func() {
	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
})

var _ = AfterEach(func() {
	GinkgoWriter.Write([]byte("==============================Global After Each=============================="))
	helpers.DestroyHomeDir(homeDir)
})

var foundDefaultDomain string

func defaultSharedDomain() string {
	// TODO: Move this into helpers when other packages need it, figure out how
	// to cache cuz this is a wacky call otherwise
	if foundDefaultDomain == "" {
		session := helpers.CF("domains")
		Eventually(session).Should(Exit(0))

		regex, err := regexp.Compile(`(.+?)\s+shared`)
		Expect(err).ToNot(HaveOccurred())

		matches := regex.FindStringSubmatch(string(session.Out.Contents()))
		Expect(matches).To(HaveLen(2))

		foundDefaultDomain = matches[1]
	}
	return foundDefaultDomain
}

func setupCF(org string, space string) {
	helpers.LoginCF()
	if org != ReadOnlyOrg && space != ReadOnlySpace {
		helpers.CreateOrgAndSpace(org, space)
	}
	helpers.TargetOrgAndSpace(org, space)
}
<|endoftext|>


<commit_before>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
	m.{{ $bt}}ID=int(ctx.{{ demodel $bt}}ID){{end}}{{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}

func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $tablename := index .Metadata "github.com/bketelsen/gorma#tablename" }}
{{ if ne $tablename "" }}
func (m {{$typeName}}) TableName() string {
	return "{{ $tablename }}"
}
{{ end }}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx context.Context) []{{$typeName}}
	One(ctx context.Context, id int) ({{$typeName}}, error)
	Add(ctx context.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx context.Context, o {{$typeName}}) (error)
	Delete(ctx context.Context, id int) (error)
	{{ storagedef . }}
}
{{ $cached := index .Metadata "github.com/bketelsen/gorma#cached" }}
type {{$typeName}}DB struct {
	DB gorm.DB
	{{ if ne $cached "" }}cache *cache.Cache{{end}}
}
{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}FilterBy{{$bt}}(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}

func (m *{{$typeName}}DB) ListBy{{$bt}}(ctx context.Context, parentid int) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Scopes({{$typeName}}FilterBy{{$bt}}(parentid, *m.DB)).Find(&objs)
	return objs
}

{{end}}{{end}}

func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	{{ if ne $cached "" }}
	return &{{$typeName}}DB{
		DB: db,
		cache: cache.New(5*time.Minute, 30*time.Second),
	}
	{{ else  }}
	return &{{$typeName}}DB{DB: db}

	{{ end  }}
}

func (m *{{$typeName}}DB) List(ctx context.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) One(ctx context.Context, id int) ({{$typeName}}, error) {
	{{ if ne $cached "" }}//first attempt to retrieve from cache
	o,found := m.cache.Get(strconv.Itoa(id))
	if found {
		return o.({{$typeName}}), nil
	}
	// fallback to database if not found{{ end }}
	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	{{ if ne $cached "" }} go m.cache.Set(strconv.Itoa(id), obj, cache.DefaultExpiration) {{ end }}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx context.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	{{ if ne $cached "" }} go m.cache.Set(strconv.Itoa(model.ID), model, cache.DefaultExpiration) {{ end }}
	return model, err
}

func (m *{{$typeName}}DB) Update(ctx context.Context, model {{$typeName}}) error {
	obj, err := m.One(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	{{ if ne $cached "" }}
	go func(){
	obj, err := m.One(ctx, model.ID)
	if err == nil {
		m.cache.Set(strconv.Itoa(model.ID), obj, cache.DefaultExpiration)
	}
	}()
	{{ end }}

	return err
}

func (m *{{$typeName}}DB) Delete(ctx context.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		return  err
	}
	{{ if ne $cached "" }} go m.cache.Delete(strconv.Itoa(id)) {{ end }}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx context.Context,{{lower $typeName}}ID,  {{$lower}}ID int)  error {
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx context.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var {{lower $typeName}} {{$typeName}}
	{{lower $typeName}}.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{lower $typeName}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx context.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list)
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<commit_msg>add filterby for lists<commit_after>package gorma

const modelTmpl = `// {{if .Description}}{{.Description}}{{else}}app.{{gotypename . 0}} storage type{{end}}
// Identifier: {{ $typeName :=  gotypename . 0}}{{$typeName := demodel $typeName}}
{{$td := gotypedef . 0 true false}}type {{$typeName}} {{modeldef $td .}}
{{ $belongsto := index .Metadata "github.com/bketelsen/gorma#belongsto" }}
{{ $m2m := index .Metadata "github.com/bketelsen/gorma#many2many" }}
func {{$typeName}}FromCreatePayload(ctx *app.Create{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
	m.{{ $bt}}ID=int(ctx.{{ demodel $bt}}ID){{end}}{{end}}
	return m
}

func {{$typeName}}FromUpdatePayload(ctx *app.Update{{demodel $typeName}}Context) {{$typeName}} {
	payload := ctx.Payload
	m := {{$typeName}}{}
	copier.Copy(&m, payload)
	return m
}

func (m {{$typeName}}) ToApp() *app.{{demodel $typeName}} {
	target := app.{{demodel $typeName}}{}
	copier.Copy(&target, &m)
	return &target
}
{{ $tablename := index .Metadata "github.com/bketelsen/gorma#tablename" }}
{{ if ne $tablename "" }}
func (m {{$typeName}}) TableName() string {
	return "{{ $tablename }}"
}
{{ end }}
{{ $roler := index .Metadata "github.com/bketelsen/gorma#roler" }}
{{ if ne $roler "" }}
func (m {{$typeName}}) GetRole() string {
	return m.Role
}
{{end}}

type {{$typeName}}Storage interface {
	List(ctx context.Context) []{{$typeName}}
	One(ctx context.Context, id int) ({{$typeName}}, error)
	Add(ctx context.Context, o {{$typeName}}) ({{$typeName}}, error)
	Update(ctx context.Context, o {{$typeName}}) (error)
	Delete(ctx context.Context, id int) (error)
	{{ storagedef . }}
}
{{ $cached := index .Metadata "github.com/bketelsen/gorma#cached" }}
type {{$typeName}}DB struct {
	DB gorm.DB
	{{ if ne $cached "" }}cache *cache.Cache{{end}}
}
{{ if ne $belongsto "" }}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
// would prefer to just pass a context in here, but they're all different, so can't
func {{$typeName}}FilterBy{{$bt}}(parentid int, originaldb *gorm.DB) func(db *gorm.DB) *gorm.DB {
	if parentid > 0 {
		return func(db *gorm.DB) *gorm.DB {
			return db.Where("{{ snake $bt }}_id = ?", parentid)
		}
	} else {
		return func(db *gorm.DB) *gorm.DB {
			return db
		}
	}
}

func (m *{{$typeName}}DB) ListBy{{$bt}}(ctx context.Context, parentid int) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Scopes({{$typeName}}FilterBy{{$bt}}(parentid, &m.DB)).Find(&objs)
	return objs
}

{{end}}{{end}}

func New{{$typeName}}DB(db gorm.DB) *{{$typeName}}DB {
	{{ if ne $cached "" }}
	return &{{$typeName}}DB{
		DB: db,
		cache: cache.New(5*time.Minute, 30*time.Second),
	}
	{{ else  }}
	return &{{$typeName}}DB{DB: db}

	{{ end  }}
}

func (m *{{$typeName}}DB) List(ctx context.Context) []{{$typeName}} {

	var objs []{{$typeName}}
    m.DB.Find(&objs)
	return objs
}

func (m *{{$typeName}}DB) One(ctx context.Context, id int) ({{$typeName}}, error) {
	{{ if ne $cached "" }}//first attempt to retrieve from cache
	o,found := m.cache.Get(strconv.Itoa(id))
	if found {
		return o.({{$typeName}}), nil
	}
	// fallback to database if not found{{ end }}
	var obj {{$typeName}}

	err := m.DB.Find(&obj, id).Error
	{{ if ne $cached "" }} go m.cache.Set(strconv.Itoa(id), obj, cache.DefaultExpiration) {{ end }}
	return obj, err
}

func (m *{{$typeName}}DB) Add(ctx context.Context, model {{$typeName}}) ({{$typeName}}, error) {
	err := m.DB.Create(&model).Error
	{{ if ne $cached "" }} go m.cache.Set(strconv.Itoa(model.ID), model, cache.DefaultExpiration) {{ end }}
	return model, err
}

func (m *{{$typeName}}DB) Update(ctx context.Context, model {{$typeName}}) error {
	obj, err := m.One(ctx, model.ID)
	if err != nil {
		return  err
	}
	err = m.DB.Model(&obj).Updates(model).Error
	{{ if ne $cached "" }}
	go func(){
	obj, err := m.One(ctx, model.ID)
	if err == nil {
		m.cache.Set(strconv.Itoa(model.ID), obj, cache.DefaultExpiration)
	}
	}()
	{{ end }}

	return err
}

func (m *{{$typeName}}DB) Delete(ctx context.Context, id int)  error {
	var obj {{$typeName}}
	err := m.DB.Delete(&obj, id).Error
	if err != nil {
		return  err
	}
	{{ if ne $cached "" }} go m.cache.Delete(strconv.Itoa(id)) {{ end }}
	return  nil
}

{{ if ne $m2m "" }}{{$barray := split $m2m ","}}{{ range $idx, $bt := $barray}}
{{ $pieces := split $bt ":" }} {{ $lowertype := index $pieces 1  }} {{ $lower := lower $lowertype }}  {{ $lowerplural := index $pieces 0  }} {{ $lowerplural := lower $lowerplural}}
func (m *{{$typeName}}DB) Delete{{index $pieces 1}}(ctx context.Context,{{lower $typeName}}ID,  {{$lower}}ID int)  error {
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	var err error
	assoc.ID = {{$lower}}ID
	if err != nil {
		return err
	}
	err = m.DB.Model(&obj).Association("{{index $pieces 0}}").Delete(assoc).Error
	if err != nil {
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) Add{{index $pieces 1}}(ctx context.Context, {{lower $typeName}}ID, {{$lower}}ID int) error {
	var {{lower $typeName}} {{$typeName}}
	{{lower $typeName}}.ID = {{lower $typeName}}ID
	var assoc {{index $pieces 1}}
	assoc.ID = {{$lower}}ID
	err := m.DB.Model(&{{lower $typeName}}).Association("{{index $pieces 0}}").Append(assoc).Error
	if err != nil {
		return  err
	}
	return  nil
}
func (m *{{$typeName}}DB) List{{index $pieces 0}}(ctx context.Context, {{lower $typeName}}ID int)  []{{index $pieces 1}} {
	list := make([]{{index $pieces 1}}, 0)
	var obj {{$typeName}}
	obj.ID = {{lower $typeName}}ID
	m.DB.Model(&obj).Association("{{index $pieces 0}}").Find(&list)
	return  nil
}
{{end}}{{end}}
{{if ne $belongsto ""}}{{$barray := split $belongsto ","}}{{ range $idx, $bt := $barray}}
func Filter{{$typeName}}By{{$bt}}(parent int, list []{{$typeName}}) []{{$typeName}} {
	filtered := make([]{{$typeName}},0)
	for _,o := range list {
		if o.{{$bt}}ID == int(parent) {
			filtered = append(filtered,o)
		}
	}
	return filtered
}
{{end}}{{end}}
`
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/boltdb/bolt"
	"github.com/brutella/hc/hap"
	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
	"github.com/cswank/gogadgets"
)

var (
	user = os.Getenv("QUIMBY_USER")
)

type HomeKit struct {
	db          *bolt.DB
	id          string
	switches    map[string]model.Switch
	accessories []*accessory.Accessory
	key         string
	cmds        []cmd
}

func NewHomeKit(key string, db *bolt.DB) *HomeKit {
	return &HomeKit{
		id:  "homekit",
		key: key,
		db:  db,
	}
}

func (h *HomeKit) Start() {
	if user == "" {
		LG.Println("didn't set QUIMBY_USER, homekit exiting")
		return
	}
	h.getSwitches()
	var t hap.Transport
	var err error
	fmt.Println("accesories", len(h.accessories))
	if len(h.accessories) == 1 {
		t, err = hap.NewIPTransport(h.key, h.accessories[0])
	} else if len(h.accessories) > 1 {
		t, err = hap.NewIPTransport(h.key, h.accessories[0], h.accessories[1:]...)
	} else {
		return
	}
	if err != nil {
		log.Fatal(err)
	}
	t.Start()
}

func (h *HomeKit) getSwitches() {
	h.cmds = []cmd{}
	gadgets, err := GetGadgets(h.db)
	if err != nil {
		log.Fatal(err)
	}
	h.switches = map[string]model.Switch{}
	h.cmds = []cmd{}
	h.accessories = []*accessory.Accessory{}
	for _, g := range gadgets {
		h.register(g) //TODO register all gadgets somewhere else
		if err := g.Fetch(); err != nil {
			log.Println("not adding %s to homekit: %s", g.Name, err)
			continue
		}
		devices, err := g.Status()
		if err != nil {
			log.Println("not adding %s to homekit: %s", g.Name, err)
			continue
		}
		for name, dev := range devices {
			if dev.Info.Direction == "output" {
				info := model.Info{
					Name:         name,
					Manufacturer: "gogadgets",
				}
				s := accessory.NewSwitch(info)

				h.switches[name] = s
				h.cmds = append(h.cmds, newCMD(s, g, name))
				h.accessories = append(h.accessories, s.Accessory)
			}
		}
	}
}

func (h *HomeKit) register(g Gadget) error {
	token, err := GenerateToken(user, time.Duration(24*365*time.Hour))
	if err != nil {
		return err
	}
	_, err = g.Register(GetAddr(), token)
	return err
}

type cmd struct {
	s   model.Switch
	g   Gadget
	k   string
	on  string
	off string
	ch  chan gogadgets.Message
}

func newCMD(s model.Switch, g Gadget, k string) cmd {
	c := cmd{
		s:   s,
		g:   g,
		k:   k,
		on:  fmt.Sprintf("turn on %s", k),
		off: fmt.Sprintf("turn off %s", k),
	}
	c.s.OnStateChanged(func(on bool) {
		if on == true {
			c.g.SendCommand(c.on)
		} else {
			c.g.SendCommand(c.off)
		}
	})
	c.ch = make(chan gogadgets.Message)
	uuid := gogadgets.GetUUID()
	Clients.Add(g.Host, uuid, c.ch)
	go c.listen()
	return c
}

func (c *cmd) listen() {
	for {
		msg := <-c.ch
		key := fmt.Sprintf("%s %s", msg.Location, msg.Name)
		if key == c.k {
			c.s.SetOn(msg.Value.Value.(bool))
		}
	}
}
<commit_msg>got rid of print<commit_after>package models

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/boltdb/bolt"
	"github.com/brutella/hc/hap"
	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
	"github.com/cswank/gogadgets"
)

var (
	user = os.Getenv("QUIMBY_USER")
)

type HomeKit struct {
	db          *bolt.DB
	id          string
	switches    map[string]model.Switch
	accessories []*accessory.Accessory
	key         string
	cmds        []cmd
}

func NewHomeKit(key string, db *bolt.DB) *HomeKit {
	return &HomeKit{
		id:  "homekit",
		key: key,
		db:  db,
	}
}

func (h *HomeKit) Start() {
	if user == "" {
		LG.Println("didn't set QUIMBY_USER, homekit exiting")
		return
	}
	h.getSwitches()
	var t hap.Transport
	var err error
	if len(h.accessories) == 1 {
		t, err = hap.NewIPTransport(h.key, h.accessories[0])
	} else if len(h.accessories) > 1 {
		t, err = hap.NewIPTransport(h.key, h.accessories[0], h.accessories[1:]...)
	} else {
		return
	}
	if err != nil {
		log.Fatal(err)
	}
	t.Start()
}

func (h *HomeKit) getSwitches() {
	h.cmds = []cmd{}
	gadgets, err := GetGadgets(h.db)
	if err != nil {
		log.Fatal(err)
	}
	h.switches = map[string]model.Switch{}
	h.cmds = []cmd{}
	h.accessories = []*accessory.Accessory{}
	for _, g := range gadgets {
		h.register(g) //TODO register all gadgets somewhere else
		if err := g.Fetch(); err != nil {
			log.Println("not adding %s to homekit: %s", g.Name, err)
			continue
		}
		devices, err := g.Status()
		if err != nil {
			log.Println("not adding %s to homekit: %s", g.Name, err)
			continue
		}
		for name, dev := range devices {
			if dev.Info.Direction == "output" {
				info := model.Info{
					Name:         name,
					Manufacturer: "gogadgets",
				}
				s := accessory.NewSwitch(info)

				h.switches[name] = s
				h.cmds = append(h.cmds, newCMD(s, g, name))
				h.accessories = append(h.accessories, s.Accessory)
			}
		}
	}
}

func (h *HomeKit) register(g Gadget) error {
	token, err := GenerateToken(user, time.Duration(24*365*time.Hour))
	if err != nil {
		return err
	}
	_, err = g.Register(GetAddr(), token)
	return err
}

type cmd struct {
	s   model.Switch
	g   Gadget
	k   string
	on  string
	off string
	ch  chan gogadgets.Message
}

func newCMD(s model.Switch, g Gadget, k string) cmd {
	c := cmd{
		s:   s,
		g:   g,
		k:   k,
		on:  fmt.Sprintf("turn on %s", k),
		off: fmt.Sprintf("turn off %s", k),
	}
	c.s.OnStateChanged(func(on bool) {
		if on == true {
			c.g.SendCommand(c.on)
		} else {
			c.g.SendCommand(c.off)
		}
	})
	c.ch = make(chan gogadgets.Message)
	uuid := gogadgets.GetUUID()
	Clients.Add(g.Host, uuid, c.ch)
	go c.listen()
	return c
}

func (c *cmd) listen() {
	for {
		msg := <-c.ch
		key := fmt.Sprintf("%s %s", msg.Location, msg.Name)
		if key == c.k {
			c.s.SetOn(msg.Value.Value.(bool))
		}
	}
}
<|endoftext|>


<commit_before>package messagebirdtest

import (
	"crypto/tls"
	"log"
	"net"
	"net/http"
	"testing"

	messagebird "github.com/messagebird/go-rest-api"
)

// testWriter can be used to have the client write to the tests's error log.
type testWriter struct {
	t *testing.T
}

// Write logs the provided buffer to the current test's error log.
func (w testWriter) Write(p []byte) (int, error) {
	w.t.Log(p)

	return len(p), nil
}

// Client initializes a new MessageBird client that uses the
func Client(t *testing.T) *messagebird.Client {
	return client(t, "test_gshuPaZoeEG6ovbc8M79w0QyM")
}

func client(t *testing.T, accessKey string) *messagebird.Client {
	transport := &http.Transport{
		DialTLS: func(network, _ string) (net.Conn, error) {
			addr := server.Listener.Addr().String()
			return tls.Dial(network, addr, &tls.Config{
				InsecureSkipVerify: true,
			})
		},
	}

	return &messagebird.Client{
		AccessKey: accessKey,
		HTTPClient: &http.Client{
			Transport: transport,
		},
		DebugLog: log.New(testWriter{t: t}, "", 0),
	}
}

func testLogger(t *testing.T) *log.Logger {
	return log.New(testWriter{t: t}, "", 0)
}
<commit_msg>Fix test logging: writer proper strings rather than raw bytes<commit_after>package messagebirdtest

import (
	"crypto/tls"
	"log"
	"net"
	"net/http"
	"testing"

	messagebird "github.com/messagebird/go-rest-api"
)

// testWriter can be used to have the client write to the tests's error log.
type testWriter struct {
	t *testing.T
}

// Write logs the provided buffer to the current test's error log.
func (w testWriter) Write(p []byte) (int, error) {
	w.t.Logf("%s", p)

	return len(p), nil
}

// Client initializes a new MessageBird client that uses the
func Client(t *testing.T) *messagebird.Client {
	return client(t, "test_gshuPaZoeEG6ovbc8M79w0QyM")
}

func client(t *testing.T, accessKey string) *messagebird.Client {
	transport := &http.Transport{
		DialTLS: func(network, _ string) (net.Conn, error) {
			addr := server.Listener.Addr().String()
			return tls.Dial(network, addr, &tls.Config{
				InsecureSkipVerify: true,
			})
		},
	}

	return &messagebird.Client{
		AccessKey: accessKey,
		HTTPClient: &http.Client{
			Transport: transport,
		},
		DebugLog: log.New(testWriter{t: t}, "", 0),
	}
}

func testLogger(t *testing.T) *log.Logger {
	return log.New(testWriter{t: t}, "", 0)
}
<|endoftext|>


<commit_before>// Package etwlogs provides a log driver for forwarding container logs
// as ETW events.(ETW stands for Event Tracing for Windows)
// A client can then create an ETW listener to listen for events that are sent
// by the ETW provider that we register, using the provider's GUID "a3693192-9ed6-46d2-a981-f8226c8363bd".
// Here is an example of how to do this using the logman utility:
// 1. logman start -ets DockerContainerLogs -p {a3693192-9ed6-46d2-a981-f8226c8363bd} 0 0 -o trace.etl
// 2. Run container(s) and generate log messages
// 3. logman stop -ets DockerContainerLogs
// 4. You can then convert the etl log file to XML using: tracerpt -y trace.etl
//
// Each container log message generates an ETW event that also contains:
// the container name and ID, the timestamp, and the stream type.
package etwlogs

import (
	"errors"
	"fmt"
	"sync"
	"syscall"
	"unsafe"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/logger"
	"golang.org/x/sys/windows"
)

type etwLogs struct {
	containerName string
	imageName     string
	containerID   string
	imageID       string
}

const (
	name             = "etwlogs"
	win32CallSuccess = 0
)

var (
	modAdvapi32          = windows.NewLazySystemDLL("Advapi32.dll")
	procEventRegister    = modAdvapi32.NewProc("EventRegister")
	procEventWriteString = modAdvapi32.NewProc("EventWriteString")
	procEventUnregister  = modAdvapi32.NewProc("EventUnregister")
)
var providerHandle syscall.Handle
var refCount int
var mu sync.Mutex

func init() {
	providerHandle = syscall.InvalidHandle
	if err := logger.RegisterLogDriver(name, New); err != nil {
		logrus.Fatal(err)
	}
}

// New creates a new etwLogs logger for the given container and registers the EWT provider.
func New(info logger.Info) (logger.Logger, error) {
	if err := registerETWProvider(); err != nil {
		return nil, err
	}
	logrus.Debugf("logging driver etwLogs configured for container: %s.", info.ContainerID)

	return &etwLogs{
		containerName: info.Name(),
		imageName:     info.ContainerImageName,
		containerID:   info.ContainerID,
		imageID:       info.ContainerImageID,
	}, nil
}

// Log logs the message to the ETW stream.
func (etwLogger *etwLogs) Log(msg *logger.Message) error {
	if providerHandle == syscall.InvalidHandle {
		// This should never be hit, if it is, it indicates a programming error.
		errorMessage := "ETWLogs cannot log the message, because the event provider has not been registered."
		logrus.Error(errorMessage)
		return errors.New(errorMessage)
	}
	return callEventWriteString(createLogMessage(etwLogger, msg))
}

// Close closes the logger by unregistering the ETW provider.
func (etwLogger *etwLogs) Close() error {
	unregisterETWProvider()
	return nil
}

func (etwLogger *etwLogs) Name() string {
	return name
}

func createLogMessage(etwLogger *etwLogs, msg *logger.Message) string {
	return fmt.Sprintf("container_name: %s, image_name: %s, container_id: %s, image_id: %s, source: %s, log: %s",
		etwLogger.containerName,
		etwLogger.imageName,
		etwLogger.containerID,
		etwLogger.imageID,
		msg.Source,
		msg.Line)
}

func registerETWProvider() error {
	mu.Lock()
	defer mu.Unlock()
	if refCount == 0 {
		var err error
		if err = callEventRegister(); err != nil {
			return err
		}
	}

	refCount++
	return nil
}

func unregisterETWProvider() {
	mu.Lock()
	defer mu.Unlock()
	if refCount == 1 {
		if callEventUnregister() {
			refCount--
			providerHandle = syscall.InvalidHandle
		}
		// Not returning an error if EventUnregister fails, because etwLogs will continue to work
	} else {
		refCount--
	}
}

func callEventRegister() error {
	// The provider's GUID is {a3693192-9ed6-46d2-a981-f8226c8363bd}
	guid := syscall.GUID{
		0xa3693192, 0x9ed6, 0x46d2,
		[8]byte{0xa9, 0x81, 0xf8, 0x22, 0x6c, 0x83, 0x63, 0xbd},
	}

	ret, _, _ := procEventRegister.Call(uintptr(unsafe.Pointer(&guid)), 0, 0, uintptr(unsafe.Pointer(&providerHandle)))
	if ret != win32CallSuccess {
		errorMessage := fmt.Sprintf("Failed to register ETW provider. Error: %d", ret)
		logrus.Error(errorMessage)
		return errors.New(errorMessage)
	}
	return nil
}

func callEventWriteString(message string) error {
	ret, _, _ := procEventWriteString.Call(uintptr(providerHandle), 0, 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(message))))
	if ret != win32CallSuccess {
		errorMessage := fmt.Sprintf("ETWLogs provider failed to log message. Error: %d", ret)
		logrus.Error(errorMessage)
		return errors.New(errorMessage)
	}
	return nil
}

func callEventUnregister() bool {
	ret, _, _ := procEventUnregister.Call(uintptr(providerHandle))
	return ret == win32CallSuccess
}
<commit_msg>fix syscall.GUID composite literal uses unkeyed fields<commit_after>// Package etwlogs provides a log driver for forwarding container logs
// as ETW events.(ETW stands for Event Tracing for Windows)
// A client can then create an ETW listener to listen for events that are sent
// by the ETW provider that we register, using the provider's GUID "a3693192-9ed6-46d2-a981-f8226c8363bd".
// Here is an example of how to do this using the logman utility:
// 1. logman start -ets DockerContainerLogs -p {a3693192-9ed6-46d2-a981-f8226c8363bd} 0 0 -o trace.etl
// 2. Run container(s) and generate log messages
// 3. logman stop -ets DockerContainerLogs
// 4. You can then convert the etl log file to XML using: tracerpt -y trace.etl
//
// Each container log message generates an ETW event that also contains:
// the container name and ID, the timestamp, and the stream type.
package etwlogs

import (
	"errors"
	"fmt"
	"sync"
	"syscall"
	"unsafe"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/logger"
	"golang.org/x/sys/windows"
)

type etwLogs struct {
	containerName string
	imageName     string
	containerID   string
	imageID       string
}

const (
	name             = "etwlogs"
	win32CallSuccess = 0
)

var (
	modAdvapi32          = windows.NewLazySystemDLL("Advapi32.dll")
	procEventRegister    = modAdvapi32.NewProc("EventRegister")
	procEventWriteString = modAdvapi32.NewProc("EventWriteString")
	procEventUnregister  = modAdvapi32.NewProc("EventUnregister")
)
var providerHandle syscall.Handle
var refCount int
var mu sync.Mutex

func init() {
	providerHandle = syscall.InvalidHandle
	if err := logger.RegisterLogDriver(name, New); err != nil {
		logrus.Fatal(err)
	}
}

// New creates a new etwLogs logger for the given container and registers the EWT provider.
func New(info logger.Info) (logger.Logger, error) {
	if err := registerETWProvider(); err != nil {
		return nil, err
	}
	logrus.Debugf("logging driver etwLogs configured for container: %s.", info.ContainerID)

	return &etwLogs{
		containerName: info.Name(),
		imageName:     info.ContainerImageName,
		containerID:   info.ContainerID,
		imageID:       info.ContainerImageID,
	}, nil
}

// Log logs the message to the ETW stream.
func (etwLogger *etwLogs) Log(msg *logger.Message) error {
	if providerHandle == syscall.InvalidHandle {
		// This should never be hit, if it is, it indicates a programming error.
		errorMessage := "ETWLogs cannot log the message, because the event provider has not been registered."
		logrus.Error(errorMessage)
		return errors.New(errorMessage)
	}
	return callEventWriteString(createLogMessage(etwLogger, msg))
}

// Close closes the logger by unregistering the ETW provider.
func (etwLogger *etwLogs) Close() error {
	unregisterETWProvider()
	return nil
}

func (etwLogger *etwLogs) Name() string {
	return name
}

func createLogMessage(etwLogger *etwLogs, msg *logger.Message) string {
	return fmt.Sprintf("container_name: %s, image_name: %s, container_id: %s, image_id: %s, source: %s, log: %s",
		etwLogger.containerName,
		etwLogger.imageName,
		etwLogger.containerID,
		etwLogger.imageID,
		msg.Source,
		msg.Line)
}

func registerETWProvider() error {
	mu.Lock()
	defer mu.Unlock()
	if refCount == 0 {
		var err error
		if err = callEventRegister(); err != nil {
			return err
		}
	}

	refCount++
	return nil
}

func unregisterETWProvider() {
	mu.Lock()
	defer mu.Unlock()
	if refCount == 1 {
		if callEventUnregister() {
			refCount--
			providerHandle = syscall.InvalidHandle
		}
		// Not returning an error if EventUnregister fails, because etwLogs will continue to work
	} else {
		refCount--
	}
}

func callEventRegister() error {
	// The provider's GUID is {a3693192-9ed6-46d2-a981-f8226c8363bd}
	guid := syscall.GUID{
		Data1: 0xa3693192,
		Data2: 0x9ed6,
		Data3: 0x46d2,
		Data4: [8]byte{0xa9, 0x81, 0xf8, 0x22, 0x6c, 0x83, 0x63, 0xbd},
	}

	ret, _, _ := procEventRegister.Call(uintptr(unsafe.Pointer(&guid)), 0, 0, uintptr(unsafe.Pointer(&providerHandle)))
	if ret != win32CallSuccess {
		errorMessage := fmt.Sprintf("Failed to register ETW provider. Error: %d", ret)
		logrus.Error(errorMessage)
		return errors.New(errorMessage)
	}
	return nil
}

func callEventWriteString(message string) error {
	ret, _, _ := procEventWriteString.Call(uintptr(providerHandle), 0, 0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(message))))
	if ret != win32CallSuccess {
		errorMessage := fmt.Sprintf("ETWLogs provider failed to log message. Error: %d", ret)
		logrus.Error(errorMessage)
		return errors.New(errorMessage)
	}
	return nil
}

func callEventUnregister() bool {
	ret, _, _ := procEventUnregister.Call(uintptr(providerHandle))
	return ret == win32CallSuccess
}
<|endoftext|>