<commit_before>package brats_test

import (
	"fmt"
	"strings"

	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/ginkgo/extensions/table"
)

var _ = Describe("Director external database TLS connections", func() {
	AfterEach(func() {
		stopInnerBosh()
	})

	testDBConnectionOverTLS := func(databaseType string, mutualTLSEnabled bool, useIncorrectCA bool) {
		external_db_host := assertEnvExists(fmt.Sprintf("%s_EXTERNAL_DB_HOST", strings.ToUpper(databaseType)))
		external_db_user := assertEnvExists(fmt.Sprintf("%s_EXTERNAL_DB_USER", strings.ToUpper(databaseType)))
		external_db_password := assertEnvExists(fmt.Sprintf("%s_EXTERNAL_DB_PASSWORD", strings.ToUpper(databaseType)))
		external_db_name := assertEnvExists(fmt.Sprintf("%s_EXTERNAL_DB_NAME", strings.ToUpper(databaseType)))

		connectionOptions := fmt.Sprintf("external_db/%s_connection_options.yml", databaseType)
		connectionVarFile := fmt.Sprintf("external_db/%s.yml", databaseType)

		if useIncorrectCA {
			connectionVarFile = fmt.Sprintf("external_db/%s_invalid_ca.yml", databaseType)
		}

		startInnerBoshArgs := []string{
			fmt.Sprintf("-o %s", boshDeploymentAssetPath("misc/external-db.yml")),
			fmt.Sprintf("-o %s", boshDeploymentAssetPath("experimental/db-enable-tls.yml")),
			fmt.Sprintf("-o %s", assetPath(connectionOptions)),
			fmt.Sprintf("--vars-file %s", assetPath(connectionVarFile)),
			fmt.Sprintf("-v external_db_host=%s", external_db_host),
			fmt.Sprintf("-v external_db_user=%s", external_db_user),
			fmt.Sprintf("-v external_db_password=%s", external_db_password),
			fmt.Sprintf("-v external_db_name=%s", external_db_name),
		}

		if mutualTLSEnabled {
			external_db_client_certificate := assertEnvExists(fmt.Sprintf("%s_EXTERNAL_DB_CLIENT_CERTIFICATE", strings.ToUpper(databaseType)))
			external_db_client_private_key := assertEnvExists(fmt.Sprintf("%s_EXTERNAL_DB_CLIENT_PRIVATE_KEY", strings.ToUpper(databaseType)))

			tempDir, err := ioutil.TempDir("", "bosh_db_tls")
			if err != nil {
				log.Fatal(err)
			}

			defer os.RemoveAll(tempDir)

			external_db_client_certificate_file := filepath.Join(tempDir, "external_db_client_certificate")
			if err := ioutil.WriteFile(external_db_client_certificate_file, []byte(external_db_client_certificate), 0666); err != nil {
				log.Fatal(err)
			}

			external_db_client_private_key_file := filepath.Join(tempDir, "external_db_client_private_key")
			if err := ioutil.WriteFile(external_db_client_private_key_file, []byte(external_db_client_private_key), 0666); err != nil {
				log.Fatal(err)
			}

			mutualTLSArgs := []string{
				fmt.Sprintf("-o %s", boshDeploymentAssetPath("experimental/db-enable-mutual-tls.yml")),
				fmt.Sprintf("--var-file=db_client_certificate=%s", external_db_client_certificate_file),
				fmt.Sprintf("--var-file=db_client_private_key=%s", external_db_client_private_key_file),
			}

			startInnerBoshArgs = append(startInnerBoshArgs, mutualTLSArgs...)
		}

		if useIncorrectCA {
			startInnerBoshWithExpectation(true, "Error: 'bosh/[0-9a-f]{8}-[0-9a-f-]{27} \\(0\\)' is not running after update", startInnerBoshArgs...)
		} else {
			startInnerBosh(startInnerBoshArgs...)
			uploadRelease("https://bosh.io/d/github.com/cloudfoundry/syslog-release?v=11")
		}
	}

	Context("RDS", func() {
		var mutualTLSEnabled = false
		var useIncorrectCA = false

		DescribeTable("Regular TLS", testDBConnectionOverTLS,
			Entry("allows TLS connections to POSTGRES", "rds_postgres", mutualTLSEnabled, useIncorrectCA),

			// Pending. Check https://www.pivotaltracker.com/story/show/154143917 and https://www.pivotaltracker.com/story/show/153785594/comments/184377346
			PEntry("allows TLS connections to MYSQL, refer to https://www.pivotaltracker.com/story/show/154143917", "rds_mysql", false),
		)
	})

	Context("GCP", func() {
		Context("Regular TLS", func() {
			Context("With valid CA", func() {
				var mutualTLSEnabled = false
				var useIncorrectCA = false

				DescribeTable("DB Connections", testDBConnectionOverTLS,
					Entry("allows TLS connections to MYSQL", "gcp_mysql", mutualTLSEnabled, useIncorrectCA),
					Entry("allows TLS connections to POSTGRES", "gcp_postgres", mutualTLSEnabled, useIncorrectCA),
				)
			})

			Context("With Incorrect CA", func() {
				var mutualTLSEnabled = false
				var useIncorrectCA = true

				DescribeTable("DB Connections", testDBConnectionOverTLS,
					// Pending https://www.pivotaltracker.com/story/show/153421636/comments/185372185
					PEntry("fails to connect to MYSQL refer to https://www.pivotaltracker.com/story/show/153421636/comments/185372185", "gcp_mysql", mutualTLSEnabled, useIncorrectCA),
					Entry("fails to connect to POSTGRES", "gcp_postgres", mutualTLSEnabled, useIncorrectCA),
				)
			})
		})

		Context("Mutual TLS", func() {
			var mutualTLSEnabled = true
			var useIncorrectCA = false

			DescribeTable("DB Connections", testDBConnectionOverTLS,
				Entry("allows TLS connections to MYSQL", "gcp_mysql", mutualTLSEnabled, useIncorrectCA),
				Entry("allows TLS connections to POSTGRES", "gcp_postgres", mutualTLSEnabled, useIncorrectCA),
			)
		})
	})
})
<commit_msg>Use external_db helper methods in brats tests<commit_after>package brats_test

import (
	"fmt"
	"os"

	"io/ioutil"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"
)

var _ = Describe("Director external database TLS connections", func() {
	AfterEach(func() {
		stopInnerBosh()
	})

	testDBConnectionOverTLS := func(databaseType string, mutualTLSEnabled bool, useIncorrectCA bool) {
		tmpCertDir, err := ioutil.TempDir("", "db_tls")
		Expect(err).ToNot(HaveOccurred())

		defer os.RemoveAll(tmpCertDir)

		config := loadExternalDBConfig(databaseType, mutualTLSEnabled, tmpCertDir)

		if useIncorrectCA {
			config.ConnectionVarFile = fmt.Sprintf("external_db/%s_invalid_ca.yml", databaseType)
		}

		startInnerBoshArgs := innerBoshWithExternalDBOptions(config)

		if useIncorrectCA {
			startInnerBoshWithExpectation(true, "Error: 'bosh/[0-9a-f]{8}-[0-9a-f-]{27} \\(0\\)' is not running after update", startInnerBoshArgs...)
		} else {
			startInnerBosh(startInnerBoshArgs...)
			uploadRelease("https://bosh.io/d/github.com/cloudfoundry/syslog-release?v=11")
		}
	}

	Context("RDS", func() {
		var mutualTLSEnabled = false
		var useIncorrectCA = false

		DescribeTable("Regular TLS", testDBConnectionOverTLS,
			Entry("allows TLS connections to POSTGRES", "rds_postgres", mutualTLSEnabled, useIncorrectCA),

			// Pending. Check https://www.pivotaltracker.com/story/show/154143917 and https://www.pivotaltracker.com/story/show/153785594/comments/184377346
			PEntry("allows TLS connections to MYSQL, refer to https://www.pivotaltracker.com/story/show/154143917", "rds_mysql", false),
		)
	})

	Context("GCP", func() {
		Context("Regular TLS", func() {
			Context("With valid CA", func() {
				var mutualTLSEnabled = false
				var useIncorrectCA = false

				DescribeTable("DB Connections", testDBConnectionOverTLS,
					Entry("allows TLS connections to MYSQL", "gcp_mysql", mutualTLSEnabled, useIncorrectCA),
					Entry("allows TLS connections to POSTGRES", "gcp_postgres", mutualTLSEnabled, useIncorrectCA),
				)
			})

			Context("With Incorrect CA", func() {
				var mutualTLSEnabled = false
				var useIncorrectCA = true

				DescribeTable("DB Connections", testDBConnectionOverTLS,
					// Pending https://www.pivotaltracker.com/story/show/153421636/comments/185372185
					PEntry("fails to connect to MYSQL refer to https://www.pivotaltracker.com/story/show/153421636/comments/185372185", "gcp_mysql", mutualTLSEnabled, useIncorrectCA),
					Entry("fails to connect to POSTGRES", "gcp_postgres", mutualTLSEnabled, useIncorrectCA),
				)
			})
		})

		Context("Mutual TLS", func() {
			var mutualTLSEnabled = true
			var useIncorrectCA = false

			DescribeTable("DB Connections", testDBConnectionOverTLS,
				Entry("allows TLS connections to MYSQL", "gcp_mysql", mutualTLSEnabled, useIncorrectCA),
				Entry("allows TLS connections to POSTGRES", "gcp_postgres", mutualTLSEnabled, useIncorrectCA),
			)
		})
	})
})
<|endoftext|>


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

// +build linux

package unix_test

import (
	"bytes"
	"go/build"
	"net"
	"os"
	"syscall"
	"testing"

	"golang.org/x/sys/unix"
)

// TestSCMCredentials tests the sending and receiving of credentials
// (PID, UID, GID) in an ancillary message between two UNIX
// sockets. The SO_PASSCRED socket option is enabled on the sending
// socket for this to work.
func TestSCMCredentials(t *testing.T) {
	socketTypeTests := []struct {
		socketType int
		dataLen    int
	}{
		{
			unix.SOCK_STREAM,
			1,
		}, {
			unix.SOCK_DGRAM,
			0,
		},
	}

	for _, tt := range socketTypeTests {
		if tt.socketType == unix.SOCK_DGRAM && !atLeast1p10() {
			t.Log("skipping DGRAM test on pre-1.10")
			continue
		}

		fds, err := unix.Socketpair(unix.AF_LOCAL, tt.socketType, 0)
		if err != nil {
			t.Fatalf("Socketpair: %v", err)
		}
		defer unix.Close(fds[0])
		defer unix.Close(fds[1])

		err = unix.SetsockoptInt(fds[0], unix.SOL_SOCKET, unix.SO_PASSCRED, 1)
		if err != nil {
			t.Fatalf("SetsockoptInt: %v", err)
		}

		srvFile := os.NewFile(uintptr(fds[0]), "server")
		defer srvFile.Close()
		srv, err := net.FileConn(srvFile)
		if err != nil {
			t.Errorf("FileConn: %v", err)
			return
		}
		defer srv.Close()

		cliFile := os.NewFile(uintptr(fds[1]), "client")
		defer cliFile.Close()
		cli, err := net.FileConn(cliFile)
		if err != nil {
			t.Errorf("FileConn: %v", err)
			return
		}
		defer cli.Close()

		var ucred unix.Ucred
		if os.Getuid() != 0 {
			ucred.Pid = int32(os.Getpid())
			ucred.Uid = 0
			ucred.Gid = 0
			oob := unix.UnixCredentials(&ucred)
			_, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
			if op, ok := err.(*net.OpError); ok {
				err = op.Err
			}
			if sys, ok := err.(*os.SyscallError); ok {
				err = sys.Err
			}
			if err != syscall.EPERM {
				t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
			}
		}

		ucred.Pid = int32(os.Getpid())
		ucred.Uid = uint32(os.Getuid())
		ucred.Gid = uint32(os.Getgid())
		oob := unix.UnixCredentials(&ucred)

		// On SOCK_STREAM, this is internally going to send a dummy byte
		n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
		if err != nil {
			t.Fatalf("WriteMsgUnix: %v", err)
		}
		if n != 0 {
			t.Fatalf("WriteMsgUnix n = %d, want 0", n)
		}
		if oobn != len(oob) {
			t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob))
		}

		oob2 := make([]byte, 10*len(oob))
		n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2)
		if err != nil {
			t.Fatalf("ReadMsgUnix: %v", err)
		}
		if flags != 0 {
			t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags)
		}
		if n != tt.dataLen {
			t.Fatalf("ReadMsgUnix n = %d, want %d", n, tt.dataLen)
		}
		if oobn2 != oobn {
			// without SO_PASSCRED set on the socket, ReadMsgUnix will
			// return zero oob bytes
			t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn)
		}
		oob2 = oob2[:oobn2]
		if !bytes.Equal(oob, oob2) {
			t.Fatal("ReadMsgUnix oob bytes don't match")
		}

		scm, err := unix.ParseSocketControlMessage(oob2)
		if err != nil {
			t.Fatalf("ParseSocketControlMessage: %v", err)
		}
		newUcred, err := unix.ParseUnixCredentials(&scm[0])
		if err != nil {
			t.Fatalf("ParseUnixCredentials: %v", err)
		}
		if *newUcred != ucred {
			t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred)
		}
	}
}

// atLeast1p10 reports whether we are running on Go 1.10 or later.
func atLeast1p10() bool {
	for _, ver := range build.Default.ReleaseTags {
		if ver == "go1.10" {
			return true
		}
	}
	return false
}
<commit_msg>unix: solicit EPERM via wrong PID in creds test.<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux

package unix_test

import (
	"bytes"
	"go/build"
	"net"
	"os"
	"syscall"
	"testing"

	"golang.org/x/sys/unix"
)

// TestSCMCredentials tests the sending and receiving of credentials
// (PID, UID, GID) in an ancillary message between two UNIX
// sockets. The SO_PASSCRED socket option is enabled on the sending
// socket for this to work.
func TestSCMCredentials(t *testing.T) {
	socketTypeTests := []struct {
		socketType int
		dataLen    int
	}{
		{
			unix.SOCK_STREAM,
			1,
		}, {
			unix.SOCK_DGRAM,
			0,
		},
	}

	for _, tt := range socketTypeTests {
		if tt.socketType == unix.SOCK_DGRAM && !atLeast1p10() {
			t.Log("skipping DGRAM test on pre-1.10")
			continue
		}

		fds, err := unix.Socketpair(unix.AF_LOCAL, tt.socketType, 0)
		if err != nil {
			t.Fatalf("Socketpair: %v", err)
		}
		defer unix.Close(fds[0])
		defer unix.Close(fds[1])

		err = unix.SetsockoptInt(fds[0], unix.SOL_SOCKET, unix.SO_PASSCRED, 1)
		if err != nil {
			t.Fatalf("SetsockoptInt: %v", err)
		}

		srvFile := os.NewFile(uintptr(fds[0]), "server")
		defer srvFile.Close()
		srv, err := net.FileConn(srvFile)
		if err != nil {
			t.Errorf("FileConn: %v", err)
			return
		}
		defer srv.Close()

		cliFile := os.NewFile(uintptr(fds[1]), "client")
		defer cliFile.Close()
		cli, err := net.FileConn(cliFile)
		if err != nil {
			t.Errorf("FileConn: %v", err)
			return
		}
		defer cli.Close()

		var ucred unix.Ucred
		ucred.Pid = int32(os.Getpid() - 1)
		ucred.Uid = uint32(os.Getuid())
		ucred.Gid = uint32(os.Getgid())
		oob := unix.UnixCredentials(&ucred)
		_, _, err = cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
		if op, ok := err.(*net.OpError); ok {
			err = op.Err
		}
		if sys, ok := err.(*os.SyscallError); ok {
			err = sys.Err
		}
		if err != syscall.EPERM {
			t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
		}

		// Fix the PID.
		ucred.Pid = int32(os.Getpid())
		oob = unix.UnixCredentials(&ucred)

		// On SOCK_STREAM, this is internally going to send a dummy byte
		n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
		if err != nil {
			t.Fatalf("WriteMsgUnix: %v", err)
		}
		if n != 0 {
			t.Fatalf("WriteMsgUnix n = %d, want 0", n)
		}
		if oobn != len(oob) {
			t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob))
		}

		oob2 := make([]byte, 10*len(oob))
		n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2)
		if err != nil {
			t.Fatalf("ReadMsgUnix: %v", err)
		}
		if flags != 0 {
			t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags)
		}
		if n != tt.dataLen {
			t.Fatalf("ReadMsgUnix n = %d, want %d", n, tt.dataLen)
		}
		if oobn2 != oobn {
			// without SO_PASSCRED set on the socket, ReadMsgUnix will
			// return zero oob bytes
			t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn)
		}
		oob2 = oob2[:oobn2]
		if !bytes.Equal(oob, oob2) {
			t.Fatal("ReadMsgUnix oob bytes don't match")
		}

		scm, err := unix.ParseSocketControlMessage(oob2)
		if err != nil {
			t.Fatalf("ParseSocketControlMessage: %v", err)
		}
		newUcred, err := unix.ParseUnixCredentials(&scm[0])
		if err != nil {
			t.Fatalf("ParseUnixCredentials: %v", err)
		}
		if *newUcred != ucred {
			t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred)
		}
	}
}

// atLeast1p10 reports whether we are running on Go 1.10 or later.
func atLeast1p10() bool {
	for _, ver := range build.Default.ReleaseTags {
		if ver == "go1.10" {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2016-2022 The Libsacloud 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 api

import (
	"fmt"
	"net/http"
	"strings"
	"time"

	sacloudhttp "github.com/sacloud/go-http"
	"github.com/sacloud/libsacloud/v2"
	"github.com/sacloud/libsacloud/v2/helper/defaults"
	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/fake"
	"github.com/sacloud/libsacloud/v2/sacloud/trace"
	"github.com/sacloud/libsacloud/v2/sacloud/trace/otel"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

// NewCaller 指定のオプションでsacloud.APICallerを構築して返す
func NewCaller(opts ...*CallerOptions) sacloud.APICaller {
	return newCaller(MergeOptions(opts...))
}

// NewCallerWithDefaults 指定のオプション+環境変数/プロファイルを用いてsacloud.APICallerを構築して返す
//
// DefaultOption()で得られる*CallerOptionsにoptsをマージしてからNewCallerが呼ばれる
func NewCallerWithDefaults(opts *CallerOptions) (sacloud.APICaller, error) {
	defaultOpts, err := DefaultOption()
	if err != nil {
		return nil, err
	}
	return NewCaller(defaultOpts, opts), nil
}

func newCaller(opts *CallerOptions) sacloud.APICaller {
	// build http client
	httpClient := http.DefaultClient
	if opts.HTTPClient != nil {
		httpClient = opts.HTTPClient
	}
	if opts.HTTPRequestTimeout > 0 {
		httpClient.Timeout = time.Duration(opts.HTTPRequestTimeout) * time.Second
	}
	if opts.HTTPRequestTimeout == 0 {
		httpClient.Timeout = 300 * time.Second // デフォルト値
	}
	if opts.HTTPRequestRateLimit > 0 {
		httpClient.Transport = &sacloudhttp.RateLimitRoundTripper{RateLimitPerSec: opts.HTTPRequestRateLimit}
	}
	if opts.HTTPRequestRateLimit == 0 {
		httpClient.Transport = &sacloudhttp.RateLimitRoundTripper{RateLimitPerSec: 10} // デフォルト値
	}

	retryMax := 0
	if opts.RetryMax > 0 {
		retryMax = opts.RetryMax
	}

	retryWaitMax := time.Duration(0)
	if opts.RetryWaitMax > 0 {
		retryWaitMax = time.Duration(opts.RetryWaitMax) * time.Second
	}

	retryWaitMin := time.Duration(0)
	if opts.RetryWaitMin > 0 {
		retryWaitMin = time.Duration(opts.RetryWaitMin) * time.Second
	}

	ua := fmt.Sprintf("libsacloud/%s", libsacloud.Version)
	if opts.UserAgent != "" {
		ua = opts.UserAgent
	}

	caller := &sacloud.Client{
		AccessToken:       opts.AccessToken,
		AccessTokenSecret: opts.AccessTokenSecret,
		UserAgent:         ua,
		AcceptLanguage:    opts.AcceptLanguage,
		RetryMax:          retryMax,
		RetryWaitMax:      retryWaitMax,
		RetryWaitMin:      retryWaitMin,
		HTTPClient:        httpClient,
	}
	sacloud.DefaultStatePollingTimeout = 72 * time.Hour

	if opts.TraceAPI {
		// note: exact once
		trace.AddClientFactoryHooks()
	}
	if opts.TraceHTTP {
		caller.HTTPClient.Transport = &sacloudhttp.TracingRoundTripper{
			Transport: caller.HTTPClient.Transport,
		}
	}
	if opts.OpenTelemetry {
		otel.Initialize(opts.OpenTelemetryOptions...)
		transport := caller.HTTPClient.Transport
		if transport == nil {
			transport = http.DefaultTransport
		}
		caller.HTTPClient.Transport = otelhttp.NewTransport(transport)
	}

	if opts.FakeMode {
		if opts.FakeStorePath != "" {
			fake.DataStore = fake.NewJSONFileStore(opts.FakeStorePath)
		}
		// note: exact once
		fake.SwitchFactoryFuncToFake()

		SetupFakeDefaults()
	}

	if opts.DefaultZone != "" {
		sacloud.APIDefaultZone = opts.DefaultZone
	}

	if opts.APIRootURL != "" {
		if strings.HasSuffix(opts.APIRootURL, "/") {
			opts.APIRootURL = strings.TrimRight(opts.APIRootURL, "/")
		}
		sacloud.SakuraCloudAPIRoot = opts.APIRootURL
	}
	return caller
}

func SetupFakeDefaults() {
	defaultInterval := 10 * time.Millisecond

	// update default polling intervals: libsacloud/sacloud
	sacloud.DefaultStatePollingInterval = defaultInterval
	sacloud.DefaultDBStatusPollingInterval = defaultInterval
	// update default polling intervals: libsacloud/helper/setup
	defaults.DefaultDeleteWaitInterval = defaultInterval
	defaults.DefaultProvisioningWaitInterval = defaultInterval
	defaults.DefaultPollingInterval = defaultInterval
	// update default polling intervals: libsacloud/helper/builder
	defaults.DefaultNICUpdateWaitDuration = defaultInterval
	// update default timeouts and span: libsacloud/helper/power
	defaults.DefaultPowerHelperBootRetrySpan = defaultInterval
	defaults.DefaultPowerHelperShutdownRetrySpan = defaultInterval
	defaults.DefaultPowerHelperInitialRequestRetrySpan = defaultInterval
	defaults.DefaultPowerHelperInitialRequestTimeout = defaultInterval * 100

	fake.PowerOnDuration = time.Millisecond
	fake.PowerOffDuration = time.Millisecond
	fake.DiskCopyDuration = time.Millisecond
}
<commit_msg>helper/apiで環境変数SAKURACLOUD_ZONESが反映されない問題を修正 (#888)<commit_after>// Copyright 2016-2022 The Libsacloud 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 api

import (
	"fmt"
	"net/http"
	"strings"
	"time"

	sacloudhttp "github.com/sacloud/go-http"
	"github.com/sacloud/libsacloud/v2"
	"github.com/sacloud/libsacloud/v2/helper/defaults"
	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/fake"
	"github.com/sacloud/libsacloud/v2/sacloud/trace"
	"github.com/sacloud/libsacloud/v2/sacloud/trace/otel"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

// NewCaller 指定のオプションでsacloud.APICallerを構築して返す
func NewCaller(opts ...*CallerOptions) sacloud.APICaller {
	return newCaller(MergeOptions(opts...))
}

// NewCallerWithDefaults 指定のオプション+環境変数/プロファイルを用いてsacloud.APICallerを構築して返す
//
// DefaultOption()で得られる*CallerOptionsにoptsをマージしてからNewCallerが呼ばれる
func NewCallerWithDefaults(opts *CallerOptions) (sacloud.APICaller, error) {
	defaultOpts, err := DefaultOption()
	if err != nil {
		return nil, err
	}
	return NewCaller(defaultOpts, opts), nil
}

func newCaller(opts *CallerOptions) sacloud.APICaller {
	// build http client
	httpClient := http.DefaultClient
	if opts.HTTPClient != nil {
		httpClient = opts.HTTPClient
	}
	if opts.HTTPRequestTimeout > 0 {
		httpClient.Timeout = time.Duration(opts.HTTPRequestTimeout) * time.Second
	}
	if opts.HTTPRequestTimeout == 0 {
		httpClient.Timeout = 300 * time.Second // デフォルト値
	}
	if opts.HTTPRequestRateLimit > 0 {
		httpClient.Transport = &sacloudhttp.RateLimitRoundTripper{RateLimitPerSec: opts.HTTPRequestRateLimit}
	}
	if opts.HTTPRequestRateLimit == 0 {
		httpClient.Transport = &sacloudhttp.RateLimitRoundTripper{RateLimitPerSec: 10} // デフォルト値
	}

	retryMax := 0
	if opts.RetryMax > 0 {
		retryMax = opts.RetryMax
	}

	retryWaitMax := time.Duration(0)
	if opts.RetryWaitMax > 0 {
		retryWaitMax = time.Duration(opts.RetryWaitMax) * time.Second
	}

	retryWaitMin := time.Duration(0)
	if opts.RetryWaitMin > 0 {
		retryWaitMin = time.Duration(opts.RetryWaitMin) * time.Second
	}

	ua := fmt.Sprintf("libsacloud/%s", libsacloud.Version)
	if opts.UserAgent != "" {
		ua = opts.UserAgent
	}

	caller := &sacloud.Client{
		AccessToken:       opts.AccessToken,
		AccessTokenSecret: opts.AccessTokenSecret,
		UserAgent:         ua,
		AcceptLanguage:    opts.AcceptLanguage,
		RetryMax:          retryMax,
		RetryWaitMax:      retryWaitMax,
		RetryWaitMin:      retryWaitMin,
		HTTPClient:        httpClient,
	}
	sacloud.DefaultStatePollingTimeout = 72 * time.Hour

	if opts.TraceAPI {
		// note: exact once
		trace.AddClientFactoryHooks()
	}
	if opts.TraceHTTP {
		caller.HTTPClient.Transport = &sacloudhttp.TracingRoundTripper{
			Transport: caller.HTTPClient.Transport,
		}
	}
	if opts.OpenTelemetry {
		otel.Initialize(opts.OpenTelemetryOptions...)
		transport := caller.HTTPClient.Transport
		if transport == nil {
			transport = http.DefaultTransport
		}
		caller.HTTPClient.Transport = otelhttp.NewTransport(transport)
	}

	if opts.FakeMode {
		if opts.FakeStorePath != "" {
			fake.DataStore = fake.NewJSONFileStore(opts.FakeStorePath)
		}
		// note: exact once
		fake.SwitchFactoryFuncToFake()

		SetupFakeDefaults()
	}

	if opts.DefaultZone != "" {
		sacloud.APIDefaultZone = opts.DefaultZone
	}

	if opts.APIRootURL != "" {
		if strings.HasSuffix(opts.APIRootURL, "/") {
			opts.APIRootURL = strings.TrimRight(opts.APIRootURL, "/")
		}
		sacloud.SakuraCloudAPIRoot = opts.APIRootURL
	}

	if len(opts.Zones) > 0 {
		sacloud.SakuraCloudZones = opts.Zones
	}
	return caller
}

func SetupFakeDefaults() {
	defaultInterval := 10 * time.Millisecond

	// update default polling intervals: libsacloud/sacloud
	sacloud.DefaultStatePollingInterval = defaultInterval
	sacloud.DefaultDBStatusPollingInterval = defaultInterval
	// update default polling intervals: libsacloud/helper/setup
	defaults.DefaultDeleteWaitInterval = defaultInterval
	defaults.DefaultProvisioningWaitInterval = defaultInterval
	defaults.DefaultPollingInterval = defaultInterval
	// update default polling intervals: libsacloud/helper/builder
	defaults.DefaultNICUpdateWaitDuration = defaultInterval
	// update default timeouts and span: libsacloud/helper/power
	defaults.DefaultPowerHelperBootRetrySpan = defaultInterval
	defaults.DefaultPowerHelperShutdownRetrySpan = defaultInterval
	defaults.DefaultPowerHelperInitialRequestRetrySpan = defaultInterval
	defaults.DefaultPowerHelperInitialRequestTimeout = defaultInterval * 100

	fake.PowerOnDuration = time.Millisecond
	fake.PowerOffDuration = time.Millisecond
	fake.DiskCopyDuration = time.Millisecond
}
<|endoftext|>


<commit_before>/*
Package framed adds basic support for message framing over streams.

Message are length-prefixed.  The first two bytes are an unsigned 16 bit int
stored in little-endian byte order.  The remaining bytes are the bytes of the
message.

The use of a uint16 means that the maximum possible data length is 65535.

Example:

	package main

	import (
		"github.com/oxtoacart/framed"
		"net"
		"log"
	)

	func main() {
		// Replace host:port with an actual TCP server, for example the echo service
		if conn, err := net.Dial("tcp", "host:port"); err == nil {
			framedConn = Framed{conn}
			if err := framedConn.Write([]byte("Hello World")); err == nil {
				if resp, err := framedConn.Read(); err == nil {
					log.Println("We're done!")
				}
			}
		}
	}
*/
package framed

import (
	"encoding/binary"
	"fmt"
	"io"
	"bytes"
)

var endianness = binary.LittleEndian

/*
A Framed enhances an io.ReadWriteCloser to provide methods that allow writing
and reading frames.

Although the underlying ReadWriteCloser may be safe to use from multiple
goroutines, a Framed is not.
*/
type Framed struct {
	io.ReadWriteCloser // the raw underlying connection
}

/*
ReadFrame reads the next frame from the Framed.
*/
func (framed Framed) ReadFrame() (frame []byte, err error) {
	var numBytes uint16
	err = binary.Read(framed, endianness, &numBytes)
	if err != nil {
		return
	}
	frame = make([]byte, numBytes)
	bytesRead, err := framed.Read(frame)
	if err != nil {
		return
	}
	if bytesRead < int(numBytes) {
		err = fmt.Errorf("Too few bytes read.  Expected %s, got %s", numBytes, bytesRead)
	}
	return
}

/*
WriteFrame writes all of the supplied bytes to the Framed as a single frame.
*/
func (framed Framed) WriteFrame(byteArrays ...[]byte) (err error) {
	var numBytes uint16
	for _, bytes := range(byteArrays) {
		numBytes += uint16(len(bytes))
	}
	err = binary.Write(framed, endianness, numBytes)
	buf := bytes.NewBuffer(make([]byte, 0))
	for _, b := range(byteArrays) {
		buf.Write(b)
	}
	framed.Write(buf.Bytes())
	// TODO: figure out why the below doesn't work reliably with ftcp, as it
	// might be a little more efficient if we can get it to work
//	for _, bytes := range(byteArrays) {
//		framed.Write(bytes)
//	}
	return
}
<commit_msg>Fixed partial read issue<commit_after>/*
Package framed adds basic support for message framing over streams.

Message are length-prefixed.  The first two bytes are an unsigned 16 bit int
stored in little-endian byte order.  The remaining bytes are the bytes of the
message.

The use of a uint16 means that the maximum possible data length is 65535.

Example:

	package main

	import (
		"github.com/oxtoacart/framed"
		"net"
		"log"
	)

	func main() {
		// Replace host:port with an actual TCP server, for example the echo service
		if conn, err := net.Dial("tcp", "host:port"); err == nil {
			framedConn = Framed{conn}
			if err := framedConn.Write([]byte("Hello World")); err == nil {
				if resp, err := framedConn.Read(); err == nil {
					log.Println("We're done!")
				}
			}
		}
	}
*/
package framed

import (
	"encoding/binary"
	"io"
)

var endianness = binary.LittleEndian

/*
A Framed enhances an io.ReadWriteCloser to provide methods that allow writing
and reading frames.

Although the underlying ReadWriteCloser may be safe to use from multiple
goroutines, a Framed is not.
*/
type Framed struct {
	io.ReadWriteCloser // the raw underlying connection
}

/*
ReadFrame reads the next frame from the Framed.
*/
func (framed Framed) ReadFrame() (frame []byte, err error) {
	var nb uint16
	err = binary.Read(framed, endianness, &nb)
	if err != nil {
		return
	}
	numBytes := int(nb)
	frame = make([]byte, numBytes)
	for totalRead := 0; totalRead < numBytes; {
		var bytesRead int
		bytesRead, err = framed.Read(frame[totalRead:])
		if err != nil {
			return
		}
		totalRead += bytesRead
	}
	return
}

/*
WriteFrame writes all of the supplied bytes to the Framed as a single frame.
*/
func (framed Framed) WriteFrame(byteArrays ...[]byte) (err error) {
	var numBytes uint16
	for _, bytes := range byteArrays {
		numBytes += uint16(len(bytes))
	}
	err = binary.Write(framed, endianness, numBytes)
	for _, bytes := range byteArrays {
		framed.Write(bytes)
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 ipfans
//
// 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 pongor

import (
	"io"
	"path/filepath"

	"github.com/flosch/pongo2"
	"sync"
)

type PongorOption struct {
	// Directory to load templates. Default is "templates"
	Directory string
	// Reload to reload templates everytime.
	Reload bool
}

type Renderer struct {
	PongorOption
	templates map[string]*pongo2.Template
	lock      sync.RWMutex
}

func perparOption(options []PongorOption) PongorOption {
	var opt PongorOption
	if len(options) > 0 {
		opt = options[0]
	}
	if len(opt.Directory) == 0 {
		opt.Directory = "templates"
	}
	return opt
}

func GetRenderer(opt ...PongorOption) *Renderer {
	o := perparOption(opt)
	r := &Renderer{
		PongorOption: o,
		templates:    make(map[string]*pongo2.Template),
	}
	return r
}

func getContext(templateData interface{}) pongo2.Context {
	if templateData == nil {
		return nil
	}
	contextData, isMap := templateData.(map[string]interface{})
	if isMap {
		return contextData
	}
	return nil
}

func (r *Renderer) getTemplate(name string) (t *pongo2.Template, err error) {
	if r.Reload {
		return pongo2.FromFile(filepath.Join(r.Directory, name))
	}
	r.lock.Lock()
	defer r.lock.Unlock()
	var ok bool
	if t, ok = r.templates[name]; !ok {
		t, err = pongo2.FromFile(filepath.Join(r.Directory, name))
		if err != nil {
			return
		}
		r.templates[name] = t
	}
	return
}

func (r *Renderer) Render(w io.Writer, name string, data interface{}) error {
	template, err := r.getTemplate(name)
	if err != nil {
		return err
	}
	err = template.ExecuteWriter(getContext(data), w)
	return err
}
<commit_msg>use rwmutex for read performance<commit_after>// Copyright 2015 ipfans
//
// 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 pongor

import (
	"io"
	"path/filepath"

	"github.com/flosch/pongo2"
	"sync"
)

type PongorOption struct {
	// Directory to load templates. Default is "templates"
	Directory string
	// Reload to reload templates everytime.
	Reload bool
}

type Renderer struct {
	PongorOption
	templates map[string]*pongo2.Template
	lock      sync.RWMutex
}

func perparOption(options []PongorOption) PongorOption {
	var opt PongorOption
	if len(options) > 0 {
		opt = options[0]
	}
	if len(opt.Directory) == 0 {
		opt.Directory = "templates"
	}
	return opt
}

func GetRenderer(opt ...PongorOption) *Renderer {
	o := perparOption(opt)
	r := &Renderer{
		PongorOption: o,
		templates:    make(map[string]*pongo2.Template),
	}
	return r
}

func getContext(templateData interface{}) pongo2.Context {
	if templateData == nil {
		return nil
	}
	contextData, isMap := templateData.(map[string]interface{})
	if isMap {
		return contextData
	}
	return nil
}

func (r *Renderer) buildTemplatesCache(name string) (t *pongo2.Template, err error) {
	r.lock.Lock()
	defer r.lock.Unlock()
	t, err = pongo2.FromFile(filepath.Join(r.Directory, name))
	if err != nil {
		return
	}
	r.templates[name] = t
	return
}

func (r *Renderer) getTemplate(name string) (t *pongo2.Template, err error) {
	if r.Reload {
		return pongo2.FromFile(filepath.Join(r.Directory, name))
	}
	r.lock.RLock()
	var ok bool
	if t, ok = r.templates[name]; !ok {
		r.lock.RUnlock()
		t, err = r.buildTemplatesCache(name)
	} else {
		r.lock.RUnlock()
	}
	return
}

func (r *Renderer) Render(w io.Writer, name string, data interface{}) error {
	template, err := r.getTemplate(name)
	if err != nil {
		return err
	}
	err = template.ExecuteWriter(getContext(data), w)
	return err
}
<|endoftext|>


<commit_before>package server

import _ "embed" // Necessary to use go:embed

// Expected Firmware/PCR0 Event Types.
//
// Taken from TCG PC Client Platform Firmware Profile Specification,
// Table 14 Events.
const (
	NoAction     uint32 = 0x00000003
	Separator    uint32 = 0x00000004
	SCRTMVersion uint32 = 0x00000008
	NonhostInfo  uint32 = 0x00000011
)

var (
	// GCENonHostInfoSignature identifies the GCE Non-Host info event, which
	// indicates if memory encryption is enabled. This event is 32-bytes consisting
	// of the below signature (16 bytes), followed by a byte indicating whether
	// it is confidential, followed by 15 reserved bytes.
	GCENonHostInfoSignature = []byte("GCE NonHostInfo\x00")
)

// Standard Secure Boot certificates (DER encoded)
var (
	//go:embed secure-boot/GcePk.crt
	GceDefaultPKCert []byte
	//go:embed secure-boot/MicCorKEKCA2011_2011-06-24.crt
	MicrosoftKEKCA2011Cert []byte
	//go:embed secure-boot/MicWinProPCA2011_2011-10-19.crt
	WindowsProductionPCA2011Cert []byte
	//go:embed secure-boot/MicCorUEFCA2011_2011-06-27.crt
	MicrosoftUEFICA2011Cert []byte
)

// Revoked Signing certificates (DER encoded)
var (
	//go:embed secure-boot/canonical-boothole.crt
	RevokedCanonicalBootholeCert []byte
	//go:embed secure-boot/debian-boothole.crt
	RevokedDebianBootholeCert []byte
	//go:embed secure-boot/cisco-boothole.crt
	RevokedCiscoCert []byte
)
<commit_msg>server: Add functions for parsing GCE-specific data<commit_after>package server

import (
	"bytes"
	_ "embed" // Necessary to use go:embed
	"errors"
	"fmt"
	"strconv"

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

// Expected Firmware/PCR0 Event Types.
//
// Taken from TCG PC Client Platform Firmware Profile Specification,
// Table 14 Events.
const (
	NoAction     uint32 = 0x00000003
	Separator    uint32 = 0x00000004
	SCRTMVersion uint32 = 0x00000008
	NonhostInfo  uint32 = 0x00000011
)

var (
	// GCENonHostInfoSignature identifies the GCE Non-Host info event, which
	// indicates if memory encryption is enabled. This event is 32-bytes consisting
	// of the below signature (16 bytes), followed by a byte indicating whether
	// it is confidential, followed by 15 reserved bytes.
	GCENonHostInfoSignature = []byte("GCE NonHostInfo\x00")
	// GceVirtualFirmwarePrefix is the UCS-2 encoded string
	// "GCE Virtual Firmware v" without a null terminator. All GCE firmware
	// versions are UCS-2 encoded, start with this prefix, contain the firmware
	// version encoded as an integer, and end with a null terminator.
	GceVirtualFirmwarePrefix = []byte{0x47, 0x00, 0x43, 0x00,
		0x45, 0x00, 0x20, 0x00, 0x56, 0x00, 0x69, 0x00, 0x72, 0x00,
		0x74, 0x00, 0x75, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00,
		0x46, 0x00, 0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00,
		0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00, 0x76, 0x00}
)

// Standard Secure Boot certificates (DER encoded)
var (
	//go:embed secure-boot/GcePk.crt
	GceDefaultPKCert []byte
	//go:embed secure-boot/MicCorKEKCA2011_2011-06-24.crt
	MicrosoftKEKCA2011Cert []byte
	//go:embed secure-boot/MicWinProPCA2011_2011-10-19.crt
	WindowsProductionPCA2011Cert []byte
	//go:embed secure-boot/MicCorUEFCA2011_2011-06-27.crt
	MicrosoftUEFICA2011Cert []byte
)

// Revoked Signing certificates (DER encoded)
var (
	//go:embed secure-boot/canonical-boothole.crt
	RevokedCanonicalBootholeCert []byte
	//go:embed secure-boot/debian-boothole.crt
	RevokedDebianBootholeCert []byte
	//go:embed secure-boot/cisco-boothole.crt
	RevokedCiscoCert []byte
)

// ParseGCEFirmwareVersion attempts to parse the Firmware Version of a GCE VM
// from the bytes of the version string of the SRTM. This data should come from
// a valid and verified EV_S_CRTM_VERSION event.
func ParseGCEFirmwareVersion(version []byte) (uint32, error) {
	prefixLen := len(GceVirtualFirmwarePrefix)
	if (len(version) <= prefixLen) || (len(version)%2 != 0) {
		return 0, fmt.Errorf("length of GCE version (%d) is invalid", len(version))
	}
	if !bytes.Equal(version[:prefixLen], GceVirtualFirmwarePrefix) {
		return 0, errors.New("prefix for GCE version is missing")
	}
	asciiVersion := []byte{}
	for i, b := range version[prefixLen:] {
		// Skip the UCS-2 null bytes and the null terminator
		if b == '\x00' {
			continue
		}
		// All odd bytes in our UCS-2 string should be Null
		if i%2 != 0 {
			return 0, errors.New("invalid UCS-2 in the version string")
		}
		asciiVersion = append(asciiVersion, b)
	}

	versionNum, err := strconv.Atoi(string(asciiVersion))
	if err != nil {
		return 0, fmt.Errorf("when parsing GCE firmware version: %w", err)
	}
	return uint32(versionNum), nil
}

// ParseGCEConfidentialTechnology attempts to parse the Confidential VM
// technology used by a GCE VM from the GCE Non-Host info event. This data
// should come from a valid and verified EV_NONHOST_INFO event.
func ParseGCEConfidentialTechnology(nonHostInfo []byte) (pb.GCEConfidentialTechnology, error) {
	prefixLen := len(GCENonHostInfoSignature)
	if len(nonHostInfo) < (prefixLen + 1) {
		return pb.GCEConfidentialTechnology_NONE, fmt.Errorf("length of GCE Non-Host info (%d) is too short", len(nonHostInfo))
	}

	if !bytes.Equal(nonHostInfo[:prefixLen], GCENonHostInfoSignature) {
		return pb.GCEConfidentialTechnology_NONE, errors.New("prefix for GCE Non-Host info is missing")
	}
	tech := nonHostInfo[prefixLen]
	return pb.GCEConfidentialTechnology(tech), nil
}
<|endoftext|>


<commit_before>package vault

import (
	"encoding/json"
	"io/ioutil"
	"path"
	"testing"

	. "github.com/franela/goblin"
	"github.com/franela/vault/vault/testutils"
)

func TestVaultfile(t *testing.T) {
	g := Goblin(t)
	g.Describe("Vaultfile", func() {
		g.BeforeEach(func() {
			SetHomeDir(testutils.GetTemporaryHomeDir())
		})

		g.AfterEach(func() {
			testutils.RemoveTemporaryHomeDir(UnsetHomeDir())
		})

		g.Describe("#Save", func() {
			g.It("Should work", func() {
				v := &Vaultfile{}
				v.Recipients = []string{"a@a.com"}
				v.Save()

				content, err := ioutil.ReadFile(path.Join(GetHomeDir(), "Vaultfile"))
				g.Assert(err == nil).IsTrue()

				v2 := &Vaultfile{}
				er := json.Unmarshal(content, v2)
				g.Assert(er == nil).IsTrue()

				g.Assert(v).Equal(v2)
			})
		})
	})

	g.Describe("LoadVaultfile", func() {
		g.BeforeEach(func() {
			SetHomeDir(testutils.GetTemporaryHomeDir())
		})

		g.AfterEach(func() {
			testutils.RemoveTemporaryHomeDir(UnsetHomeDir())
		})

		g.It("Should load existing Vaultfile", func() {
			v := &Vaultfile{}
			v.Recipients = []string{"a@a.com"}
			v.Save()

			v2, err := LoadVaultfile()

			g.Assert(err == nil).IsTrue()
			g.Assert(v).Equal(v2)
		})

		g.It("Should return a new Vaultfile if it doesn't exist", func() {
			v, err := LoadVaultfile()

			g.Assert(err == nil).IsTrue()
			g.Assert(v).Equal(&Vaultfile{})
		})
	})
}
<commit_msg>Test to return en error if Vaultfile can't be parsed<commit_after>package vault

import (
	"encoding/json"
	"io/ioutil"
	"path"
	"testing"

	. "github.com/franela/goblin"
	"github.com/franela/vault/vault/testutils"
)

func TestVaultfile(t *testing.T) {
	g := Goblin(t)
	g.Describe("Vaultfile", func() {
		g.BeforeEach(func() {
			SetHomeDir(testutils.GetTemporaryHomeDir())
		})

		g.AfterEach(func() {
			testutils.RemoveTemporaryHomeDir(UnsetHomeDir())
		})

		g.Describe("#Save", func() {
			g.It("Should work", func() {
				v := &Vaultfile{}
				v.Recipients = []string{"a@a.com"}
				v.Save()

				content, err := ioutil.ReadFile(path.Join(GetHomeDir(), "Vaultfile"))
				g.Assert(err == nil).IsTrue()

				v2 := &Vaultfile{}
				er := json.Unmarshal(content, v2)
				g.Assert(er == nil).IsTrue()

				g.Assert(v).Equal(v2)
			})
		})
	})

	g.Describe("LoadVaultfile", func() {
		g.BeforeEach(func() {
			SetHomeDir(testutils.GetTemporaryHomeDir())
		})

		g.AfterEach(func() {
			testutils.RemoveTemporaryHomeDir(UnsetHomeDir())
		})

		g.It("Should load existing Vaultfile", func() {
			v := &Vaultfile{}
			v.Recipients = []string{"a@a.com"}
			v.Save()

			v2, err := LoadVaultfile()

			g.Assert(err == nil).IsTrue()
			g.Assert(v).Equal(v2)
		})

		g.It("Should return a new Vaultfile if it doesn't exist", func() {
			v, err := LoadVaultfile()

			g.Assert(err == nil).IsTrue()
			g.Assert(v).Equal(&Vaultfile{})
		})

		g.It("Should return an error when trying to parse the Vaultfile", func() {
			ioutil.WriteFile(path.Join(GetHomeDir(), "Vaultfile"), []byte("Not a JSON"), 0644)
			_, err := LoadVaultfile()
			g.Assert(err == nil).IsFalse()
		})
	})
}
<|endoftext|>


<commit_before>// +build linux,cgo

package native

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/execdriver"
	"github.com/docker/docker/pkg/parsers"
	"github.com/docker/docker/pkg/pools"
	"github.com/docker/docker/pkg/reexec"
	sysinfo "github.com/docker/docker/pkg/system"
	"github.com/docker/docker/pkg/term"
	"github.com/opencontainers/runc/libcontainer"
	"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/system"
	"github.com/opencontainers/runc/libcontainer/utils"
)

const (
	DriverName = "native"
	Version    = "0.2"
)

type driver struct {
	root             string
	initPath         string
	activeContainers map[string]libcontainer.Container
	machineMemory    int64
	factory          libcontainer.Factory
	sync.Mutex
}

func NewDriver(root, initPath string, options []string) (*driver, error) {
	meminfo, err := sysinfo.ReadMemInfo()
	if err != nil {
		return nil, err
	}

	if err := sysinfo.MkdirAll(root, 0700); err != nil {
		return nil, err
	}

	// choose cgroup manager
	// this makes sure there are no breaking changes to people
	// who upgrade from versions without native.cgroupdriver opt
	cgm := libcontainer.Cgroupfs
	if systemd.UseSystemd() {
		cgm = libcontainer.SystemdCgroups
	}

	// parse the options
	for _, option := range options {
		key, val, err := parsers.ParseKeyValueOpt(option)
		if err != nil {
			return nil, err
		}
		key = strings.ToLower(key)
		switch key {
		case "native.cgroupdriver":
			// override the default if they set options
			switch val {
			case "systemd":
				if systemd.UseSystemd() {
					cgm = libcontainer.SystemdCgroups
				} else {
					// warn them that they chose the wrong driver
					logrus.Warn("You cannot use systemd as native.cgroupdriver, using cgroupfs instead")
				}
			case "cgroupfs":
				cgm = libcontainer.Cgroupfs
			default:
				return nil, fmt.Errorf("Unknown native.cgroupdriver given %q. try cgroupfs or systemd", val)
			}
		default:
			return nil, fmt.Errorf("Unknown option %s\n", key)
		}
	}

	f, err := libcontainer.New(
		root,
		cgm,
		libcontainer.InitPath(reexec.Self(), DriverName),
	)
	if err != nil {
		return nil, err
	}

	return &driver{
		root:             root,
		initPath:         initPath,
		activeContainers: make(map[string]libcontainer.Container),
		machineMemory:    meminfo.MemTotal,
		factory:          f,
	}, nil
}

type execOutput struct {
	exitCode int
	err      error
}

func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
	// take the Command and populate the libcontainer.Config from it
	container, err := d.createContainer(c)
	if err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}

	p := &libcontainer.Process{
		Args: append([]string{c.ProcessConfig.Entrypoint}, c.ProcessConfig.Arguments...),
		Env:  c.ProcessConfig.Env,
		Cwd:  c.WorkingDir,
		User: c.ProcessConfig.User,
	}

	if err := setupPipes(container, &c.ProcessConfig, p, pipes); err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}

	cont, err := d.factory.Create(c.ID, container)
	if err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}
	d.Lock()
	d.activeContainers[c.ID] = cont
	d.Unlock()
	defer func() {
		cont.Destroy()
		d.cleanContainer(c.ID)
	}()

	if err := cont.Start(p); err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}

	if startCallback != nil {
		pid, err := p.Pid()
		if err != nil {
			p.Signal(os.Kill)
			p.Wait()
			return execdriver.ExitStatus{ExitCode: -1}, err
		}
		startCallback(&c.ProcessConfig, pid)
	}

	oom := notifyOnOOM(cont)
	waitF := p.Wait
	if nss := cont.Config().Namespaces; !nss.Contains(configs.NEWPID) {
		// we need such hack for tracking processes with inherited fds,
		// because cmd.Wait() waiting for all streams to be copied
		waitF = waitInPIDHost(p, cont)
	}
	ps, err := waitF()
	if err != nil {
		execErr, ok := err.(*exec.ExitError)
		if !ok {
			return execdriver.ExitStatus{ExitCode: -1}, err
		}
		ps = execErr.ProcessState
	}
	cont.Destroy()
	_, oomKill := <-oom
	return execdriver.ExitStatus{ExitCode: utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), OOMKilled: oomKill}, nil
}

// notifyOnOOM returns a channel that signals if the container received an OOM notification
// for any process.  If it is unable to subscribe to OOM notifications then a closed
// channel is returned as it will be non-blocking and return the correct result when read.
func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
	oom, err := container.NotifyOOM()
	if err != nil {
		logrus.Warnf("Your kernel does not support OOM notifications: %s", err)
		c := make(chan struct{})
		close(c)
		return c
	}
	return oom
}

func killCgroupProcs(c libcontainer.Container) {
	var procs []*os.Process
	if err := c.Pause(); err != nil {
		logrus.Warn(err)
	}
	pids, err := c.Processes()
	if err != nil {
		// don't care about childs if we can't get them, this is mostly because cgroup already deleted
		logrus.Warnf("Failed to get processes from container %s: %v", c.ID(), err)
	}
	for _, pid := range pids {
		if p, err := os.FindProcess(pid); err == nil {
			procs = append(procs, p)
			if err := p.Kill(); err != nil {
				logrus.Warn(err)
			}
		}
	}
	if err := c.Resume(); err != nil {
		logrus.Warn(err)
	}
	for _, p := range procs {
		if _, err := p.Wait(); err != nil {
			logrus.Warn(err)
		}
	}
}

func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
	return func() (*os.ProcessState, error) {
		pid, err := p.Pid()
		if err != nil {
			return nil, err
		}

		process, err := os.FindProcess(pid)
		s, err := process.Wait()
		if err != nil {
			execErr, ok := err.(*exec.ExitError)
			if !ok {
				return s, err
			}
			s = execErr.ProcessState
		}
		killCgroupProcs(c)
		p.Wait()
		return s, err
	}
}

func (d *driver) Kill(c *execdriver.Command, sig int) error {
	d.Lock()
	active := d.activeContainers[c.ID]
	d.Unlock()
	if active == nil {
		return fmt.Errorf("active container for %s does not exist", c.ID)
	}
	state, err := active.State()
	if err != nil {
		return err
	}
	return syscall.Kill(state.InitProcessPid, syscall.Signal(sig))
}

func (d *driver) Pause(c *execdriver.Command) error {
	d.Lock()
	active := d.activeContainers[c.ID]
	d.Unlock()
	if active == nil {
		return fmt.Errorf("active container for %s does not exist", c.ID)
	}
	return active.Pause()
}

func (d *driver) Unpause(c *execdriver.Command) error {
	d.Lock()
	active := d.activeContainers[c.ID]
	d.Unlock()
	if active == nil {
		return fmt.Errorf("active container for %s does not exist", c.ID)
	}
	return active.Resume()
}

func (d *driver) Terminate(c *execdriver.Command) error {
	defer d.cleanContainer(c.ID)
	container, err := d.factory.Load(c.ID)
	if err != nil {
		return err
	}
	defer container.Destroy()
	state, err := container.State()
	if err != nil {
		return err
	}
	pid := state.InitProcessPid
	currentStartTime, err := system.GetProcessStartTime(pid)
	if err != nil {
		return err
	}
	if state.InitProcessStartTime == currentStartTime {
		err = syscall.Kill(pid, 9)
		syscall.Wait4(pid, nil, 0, nil)
	}
	return err
}

func (d *driver) Info(id string) execdriver.Info {
	return &info{
		ID:     id,
		driver: d,
	}
}

func (d *driver) Name() string {
	return fmt.Sprintf("%s-%s", DriverName, Version)
}

func (d *driver) GetPidsForContainer(id string) ([]int, error) {
	d.Lock()
	active := d.activeContainers[id]
	d.Unlock()

	if active == nil {
		return nil, fmt.Errorf("active container for %s does not exist", id)
	}
	return active.Processes()
}

func (d *driver) cleanContainer(id string) error {
	d.Lock()
	delete(d.activeContainers, id)
	d.Unlock()
	return os.RemoveAll(filepath.Join(d.root, id))
}

func (d *driver) createContainerRoot(id string) error {
	return os.MkdirAll(filepath.Join(d.root, id), 0655)
}

func (d *driver) Clean(id string) error {
	return os.RemoveAll(filepath.Join(d.root, id))
}

func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
	d.Lock()
	c := d.activeContainers[id]
	d.Unlock()
	if c == nil {
		return nil, execdriver.ErrNotRunning
	}
	now := time.Now()
	stats, err := c.Stats()
	if err != nil {
		return nil, err
	}
	memoryLimit := c.Config().Cgroups.Memory
	// if the container does not have any memory limit specified set the
	// limit to the machines memory
	if memoryLimit == 0 {
		memoryLimit = d.machineMemory
	}
	return &execdriver.ResourceStats{
		Stats:       stats,
		Read:        now,
		MemoryLimit: memoryLimit,
	}, nil
}

type TtyConsole struct {
	console libcontainer.Console
}

func NewTtyConsole(console libcontainer.Console, pipes *execdriver.Pipes, rootuid int) (*TtyConsole, error) {
	tty := &TtyConsole{
		console: console,
	}

	if err := tty.AttachPipes(pipes); err != nil {
		tty.Close()
		return nil, err
	}

	return tty, nil
}

func (t *TtyConsole) Resize(h, w int) error {
	return term.SetWinsize(t.console.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
}

func (t *TtyConsole) AttachPipes(pipes *execdriver.Pipes) error {
	go func() {
		if wb, ok := pipes.Stdout.(interface {
			CloseWriters() error
		}); ok {
			defer wb.CloseWriters()
		}

		pools.Copy(pipes.Stdout, t.console)
	}()

	if pipes.Stdin != nil {
		go func() {
			pools.Copy(t.console, pipes.Stdin)

			pipes.Stdin.Close()
		}()
	}

	return nil
}

func (t *TtyConsole) Close() error {
	return t.console.Close()
}

func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConfig, p *libcontainer.Process, pipes *execdriver.Pipes) error {
	var term execdriver.Terminal
	var err error

	if processConfig.Tty {
		rootuid, err := container.HostUID()
		if err != nil {
			return err
		}
		cons, err := p.NewConsole(rootuid)
		if err != nil {
			return err
		}
		term, err = NewTtyConsole(cons, pipes, rootuid)
	} else {
		p.Stdout = pipes.Stdout
		p.Stderr = pipes.Stderr
		r, w, err := os.Pipe()
		if err != nil {
			return err
		}
		if pipes.Stdin != nil {
			go func() {
				io.Copy(w, pipes.Stdin)
				w.Close()
			}()
			p.Stdin = r
		}
		term = &execdriver.StdConsole{}
	}
	if err != nil {
		return err
	}
	processConfig.Terminal = term
	return nil
}
<commit_msg>Remove unused parameter in NewTtyConsole<commit_after>// +build linux,cgo

package native

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/execdriver"
	"github.com/docker/docker/pkg/parsers"
	"github.com/docker/docker/pkg/pools"
	"github.com/docker/docker/pkg/reexec"
	sysinfo "github.com/docker/docker/pkg/system"
	"github.com/docker/docker/pkg/term"
	"github.com/opencontainers/runc/libcontainer"
	"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/system"
	"github.com/opencontainers/runc/libcontainer/utils"
)

const (
	DriverName = "native"
	Version    = "0.2"
)

type driver struct {
	root             string
	initPath         string
	activeContainers map[string]libcontainer.Container
	machineMemory    int64
	factory          libcontainer.Factory
	sync.Mutex
}

func NewDriver(root, initPath string, options []string) (*driver, error) {
	meminfo, err := sysinfo.ReadMemInfo()
	if err != nil {
		return nil, err
	}

	if err := sysinfo.MkdirAll(root, 0700); err != nil {
		return nil, err
	}

	// choose cgroup manager
	// this makes sure there are no breaking changes to people
	// who upgrade from versions without native.cgroupdriver opt
	cgm := libcontainer.Cgroupfs
	if systemd.UseSystemd() {
		cgm = libcontainer.SystemdCgroups
	}

	// parse the options
	for _, option := range options {
		key, val, err := parsers.ParseKeyValueOpt(option)
		if err != nil {
			return nil, err
		}
		key = strings.ToLower(key)
		switch key {
		case "native.cgroupdriver":
			// override the default if they set options
			switch val {
			case "systemd":
				if systemd.UseSystemd() {
					cgm = libcontainer.SystemdCgroups
				} else {
					// warn them that they chose the wrong driver
					logrus.Warn("You cannot use systemd as native.cgroupdriver, using cgroupfs instead")
				}
			case "cgroupfs":
				cgm = libcontainer.Cgroupfs
			default:
				return nil, fmt.Errorf("Unknown native.cgroupdriver given %q. try cgroupfs or systemd", val)
			}
		default:
			return nil, fmt.Errorf("Unknown option %s\n", key)
		}
	}

	f, err := libcontainer.New(
		root,
		cgm,
		libcontainer.InitPath(reexec.Self(), DriverName),
	)
	if err != nil {
		return nil, err
	}

	return &driver{
		root:             root,
		initPath:         initPath,
		activeContainers: make(map[string]libcontainer.Container),
		machineMemory:    meminfo.MemTotal,
		factory:          f,
	}, nil
}

type execOutput struct {
	exitCode int
	err      error
}

func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
	// take the Command and populate the libcontainer.Config from it
	container, err := d.createContainer(c)
	if err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}

	p := &libcontainer.Process{
		Args: append([]string{c.ProcessConfig.Entrypoint}, c.ProcessConfig.Arguments...),
		Env:  c.ProcessConfig.Env,
		Cwd:  c.WorkingDir,
		User: c.ProcessConfig.User,
	}

	if err := setupPipes(container, &c.ProcessConfig, p, pipes); err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}

	cont, err := d.factory.Create(c.ID, container)
	if err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}
	d.Lock()
	d.activeContainers[c.ID] = cont
	d.Unlock()
	defer func() {
		cont.Destroy()
		d.cleanContainer(c.ID)
	}()

	if err := cont.Start(p); err != nil {
		return execdriver.ExitStatus{ExitCode: -1}, err
	}

	if startCallback != nil {
		pid, err := p.Pid()
		if err != nil {
			p.Signal(os.Kill)
			p.Wait()
			return execdriver.ExitStatus{ExitCode: -1}, err
		}
		startCallback(&c.ProcessConfig, pid)
	}

	oom := notifyOnOOM(cont)
	waitF := p.Wait
	if nss := cont.Config().Namespaces; !nss.Contains(configs.NEWPID) {
		// we need such hack for tracking processes with inherited fds,
		// because cmd.Wait() waiting for all streams to be copied
		waitF = waitInPIDHost(p, cont)
	}
	ps, err := waitF()
	if err != nil {
		execErr, ok := err.(*exec.ExitError)
		if !ok {
			return execdriver.ExitStatus{ExitCode: -1}, err
		}
		ps = execErr.ProcessState
	}
	cont.Destroy()
	_, oomKill := <-oom
	return execdriver.ExitStatus{ExitCode: utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), OOMKilled: oomKill}, nil
}

// notifyOnOOM returns a channel that signals if the container received an OOM notification
// for any process.  If it is unable to subscribe to OOM notifications then a closed
// channel is returned as it will be non-blocking and return the correct result when read.
func notifyOnOOM(container libcontainer.Container) <-chan struct{} {
	oom, err := container.NotifyOOM()
	if err != nil {
		logrus.Warnf("Your kernel does not support OOM notifications: %s", err)
		c := make(chan struct{})
		close(c)
		return c
	}
	return oom
}

func killCgroupProcs(c libcontainer.Container) {
	var procs []*os.Process
	if err := c.Pause(); err != nil {
		logrus.Warn(err)
	}
	pids, err := c.Processes()
	if err != nil {
		// don't care about childs if we can't get them, this is mostly because cgroup already deleted
		logrus.Warnf("Failed to get processes from container %s: %v", c.ID(), err)
	}
	for _, pid := range pids {
		if p, err := os.FindProcess(pid); err == nil {
			procs = append(procs, p)
			if err := p.Kill(); err != nil {
				logrus.Warn(err)
			}
		}
	}
	if err := c.Resume(); err != nil {
		logrus.Warn(err)
	}
	for _, p := range procs {
		if _, err := p.Wait(); err != nil {
			logrus.Warn(err)
		}
	}
}

func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
	return func() (*os.ProcessState, error) {
		pid, err := p.Pid()
		if err != nil {
			return nil, err
		}

		process, err := os.FindProcess(pid)
		s, err := process.Wait()
		if err != nil {
			execErr, ok := err.(*exec.ExitError)
			if !ok {
				return s, err
			}
			s = execErr.ProcessState
		}
		killCgroupProcs(c)
		p.Wait()
		return s, err
	}
}

func (d *driver) Kill(c *execdriver.Command, sig int) error {
	d.Lock()
	active := d.activeContainers[c.ID]
	d.Unlock()
	if active == nil {
		return fmt.Errorf("active container for %s does not exist", c.ID)
	}
	state, err := active.State()
	if err != nil {
		return err
	}
	return syscall.Kill(state.InitProcessPid, syscall.Signal(sig))
}

func (d *driver) Pause(c *execdriver.Command) error {
	d.Lock()
	active := d.activeContainers[c.ID]
	d.Unlock()
	if active == nil {
		return fmt.Errorf("active container for %s does not exist", c.ID)
	}
	return active.Pause()
}

func (d *driver) Unpause(c *execdriver.Command) error {
	d.Lock()
	active := d.activeContainers[c.ID]
	d.Unlock()
	if active == nil {
		return fmt.Errorf("active container for %s does not exist", c.ID)
	}
	return active.Resume()
}

func (d *driver) Terminate(c *execdriver.Command) error {
	defer d.cleanContainer(c.ID)
	container, err := d.factory.Load(c.ID)
	if err != nil {
		return err
	}
	defer container.Destroy()
	state, err := container.State()
	if err != nil {
		return err
	}
	pid := state.InitProcessPid
	currentStartTime, err := system.GetProcessStartTime(pid)
	if err != nil {
		return err
	}
	if state.InitProcessStartTime == currentStartTime {
		err = syscall.Kill(pid, 9)
		syscall.Wait4(pid, nil, 0, nil)
	}
	return err
}

func (d *driver) Info(id string) execdriver.Info {
	return &info{
		ID:     id,
		driver: d,
	}
}

func (d *driver) Name() string {
	return fmt.Sprintf("%s-%s", DriverName, Version)
}

func (d *driver) GetPidsForContainer(id string) ([]int, error) {
	d.Lock()
	active := d.activeContainers[id]
	d.Unlock()

	if active == nil {
		return nil, fmt.Errorf("active container for %s does not exist", id)
	}
	return active.Processes()
}

func (d *driver) cleanContainer(id string) error {
	d.Lock()
	delete(d.activeContainers, id)
	d.Unlock()
	return os.RemoveAll(filepath.Join(d.root, id))
}

func (d *driver) createContainerRoot(id string) error {
	return os.MkdirAll(filepath.Join(d.root, id), 0655)
}

func (d *driver) Clean(id string) error {
	return os.RemoveAll(filepath.Join(d.root, id))
}

func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
	d.Lock()
	c := d.activeContainers[id]
	d.Unlock()
	if c == nil {
		return nil, execdriver.ErrNotRunning
	}
	now := time.Now()
	stats, err := c.Stats()
	if err != nil {
		return nil, err
	}
	memoryLimit := c.Config().Cgroups.Memory
	// if the container does not have any memory limit specified set the
	// limit to the machines memory
	if memoryLimit == 0 {
		memoryLimit = d.machineMemory
	}
	return &execdriver.ResourceStats{
		Stats:       stats,
		Read:        now,
		MemoryLimit: memoryLimit,
	}, nil
}

type TtyConsole struct {
	console libcontainer.Console
}

func NewTtyConsole(console libcontainer.Console, pipes *execdriver.Pipes) (*TtyConsole, error) {
	tty := &TtyConsole{
		console: console,
	}

	if err := tty.AttachPipes(pipes); err != nil {
		tty.Close()
		return nil, err
	}

	return tty, nil
}

func (t *TtyConsole) Resize(h, w int) error {
	return term.SetWinsize(t.console.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
}

func (t *TtyConsole) AttachPipes(pipes *execdriver.Pipes) error {
	go func() {
		if wb, ok := pipes.Stdout.(interface {
			CloseWriters() error
		}); ok {
			defer wb.CloseWriters()
		}

		pools.Copy(pipes.Stdout, t.console)
	}()

	if pipes.Stdin != nil {
		go func() {
			pools.Copy(t.console, pipes.Stdin)

			pipes.Stdin.Close()
		}()
	}

	return nil
}

func (t *TtyConsole) Close() error {
	return t.console.Close()
}

func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConfig, p *libcontainer.Process, pipes *execdriver.Pipes) error {
	var term execdriver.Terminal
	var err error

	if processConfig.Tty {
		rootuid, err := container.HostUID()
		if err != nil {
			return err
		}
		cons, err := p.NewConsole(rootuid)
		if err != nil {
			return err
		}
		term, err = NewTtyConsole(cons, pipes)
	} else {
		p.Stdout = pipes.Stdout
		p.Stderr = pipes.Stderr
		r, w, err := os.Pipe()
		if err != nil {
			return err
		}
		if pipes.Stdin != nil {
			go func() {
				io.Copy(w, pipes.Stdin)
				w.Close()
			}()
			p.Stdin = r
		}
		term = &execdriver.StdConsole{}
	}
	if err != nil {
		return err
	}
	processConfig.Terminal = term
	return nil
}
<|endoftext|>


<commit_before>package server

import (
	"github.com/smancke/guble/protocol"

	"github.com/julienschmidt/httprouter"
	"github.com/rs/xid"

	"bytes"
	"io/ioutil"
	"net/http"
	"strings"
)

const X_HEADER_PREFIX = "x-guble-"

type RestMessageApi struct {
	Router
	mux    http.Handler
	prefix string
}

func NewRestMessageApi(router Router, prefix string) *RestMessageApi {
	mux := httprouter.New()
	api := &RestMessageApi{router, mux, prefix}

	p := removeTrailingSlash(prefix)
	mux.POST(p+"/message/*topic", api.PostMessage)

	return api
}

func (api *RestMessageApi) GetPrefix() string {
	return api.prefix
}

func (api *RestMessageApi) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	api.mux.ServeHTTP(w, r)
}

func (api *RestMessageApi) PostMessage(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, `Can not read body`, http.StatusBadRequest)
		return
	}

	msg := &protocol.Message{
		Path:          protocol.Path(params.ByName(`topic`)),
		Body:          body,
		UserID:        q(r, `userId`),
		ApplicationID: xid.New().String(),
		MessageID:     q(r, `messageId`),
		HeaderJSON:    headersToJson(r.Header),
	}

	api.HandleMessage(msg)
}

// returns a query parameter
func q(r *http.Request, name string) string {
	params := r.URL.Query()[name]
	if len(params) > 0 {
		return params[0]
	}
	return ""
}

func headersToJson(header http.Header) string {
	buff := &bytes.Buffer{}
	buff.WriteString("{")

	count := 0
	for key, valueList := range header {
		if strings.HasPrefix(strings.ToLower(key), X_HEADER_PREFIX) && len(valueList) > 0 {
			if count > 0 {
				buff.WriteString(",")
			}
			buff.WriteString(`"`)
			buff.WriteString(key[len(X_HEADER_PREFIX):])
			buff.WriteString(`":`)
			buff.WriteString(`"`)
			buff.WriteString(valueList[0])
			buff.WriteString(`"`)
			count++
		}
	}
	buff.WriteString("}")
	return string(buff.Bytes())
}

func removeTrailingSlash(path string) string {
	if len(path) > 0 && path[len(path)-1] == '/' {
		return path[:len(path)-1]
	}
	return path
}
<commit_msg>adding health-check in REST-API<commit_after>package server

import (
	"github.com/smancke/guble/protocol"

	"github.com/julienschmidt/httprouter"
	"github.com/rs/xid"

	"bytes"
	"io/ioutil"
	"net/http"
	"strings"
)

const X_HEADER_PREFIX = "x-guble-"

type RestMessageApi struct {
	Router
	mux    http.Handler
	prefix string
}

func NewRestMessageApi(router Router, prefix string) *RestMessageApi {
	mux := httprouter.New()
	api := &RestMessageApi{router, mux, prefix}

	p := removeTrailingSlash(prefix)
	mux.POST(p+"/message/*topic", api.PostMessage)

	return api
}

func (api *RestMessageApi) GetPrefix() string {
	return api.prefix
}

func (api *RestMessageApi) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	api.mux.ServeHTTP(w, r)
}

func (api *RestMessageApi) PostMessage(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, `Can not read body`, http.StatusBadRequest)
		return
	}

	msg := &protocol.Message{
		Path:          protocol.Path(params.ByName(`topic`)),
		Body:          body,
		UserID:        q(r, `userId`),
		ApplicationID: xid.New().String(),
		MessageID:     q(r, `messageId`),
		HeaderJSON:    headersToJson(r.Header),
	}

	api.HandleMessage(msg)
}

func (api *RestMessageApi) Check() error {
	return nil
}

// returns a query parameter
func q(r *http.Request, name string) string {
	params := r.URL.Query()[name]
	if len(params) > 0 {
		return params[0]
	}
	return ""
}

func headersToJson(header http.Header) string {
	buff := &bytes.Buffer{}
	buff.WriteString("{")

	count := 0
	for key, valueList := range header {
		if strings.HasPrefix(strings.ToLower(key), X_HEADER_PREFIX) && len(valueList) > 0 {
			if count > 0 {
				buff.WriteString(",")
			}
			buff.WriteString(`"`)
			buff.WriteString(key[len(X_HEADER_PREFIX):])
			buff.WriteString(`":`)
			buff.WriteString(`"`)
			buff.WriteString(valueList[0])
			buff.WriteString(`"`)
			count++
		}
	}
	buff.WriteString("}")
	return string(buff.Bytes())
}

func removeTrailingSlash(path string) string {
	if len(path) > 0 && path[len(path)-1] == '/' {
		return path[:len(path)-1]
	}
	return path
}
<|endoftext|>


<commit_before>package services

import (
	"github.com/jbrodriguez/go-tmdb"
	"github.com/jbrodriguez/mlog"
	"github.com/jbrodriguez/pubsub"
	// "io/ioutil"
	"errors"
	"fmt"
	"jbrodriguez/mediagui/server/dto"
	"jbrodriguez/mediagui/server/lib"
	"jbrodriguez/mediagui/server/model"
	"strconv"
	"strings"
	"time"
)

type Scraper struct {
	Service

	bus      *pubsub.PubSub
	settings *lib.Settings
	pool     *lib.Pool
	tmdb     *tmdb.Tmdb

	mailbox chan *pubsub.Mailbox
}

func NewScraper(bus *pubsub.PubSub, settings *lib.Settings) *Scraper {
	scraper := &Scraper{bus: bus, settings: settings}
	scraper.init()
	return scraper
}

func (s *Scraper) Start() {
	mlog.Info("Starting service Scraper ...")

	var err error
	s.tmdb, err = tmdb.NewClient("e610ded10c3f47d05fe797961d90fea6", false)
	if err != nil {
		mlog.Fatalf("Unable to create tmdb client: %s", err)
	}

	s.mailbox = s.register(s.bus, "/command/movie/scrape", s.scrapeMovie)
	s.registerAdditional(s.bus, "/command/movie/rescrape", s.reScrapeMovie, s.mailbox)
	s.registerAdditional(s.bus, "/event/config/changed", s.configChanged, s.mailbox)

	s.pool = lib.NewPool(12, 4000)

	go s.react()
}

func (s *Scraper) Stop() {
	mlog.Info("Stopped service Scraper ...")
}

func (s *Scraper) react() {
	for mbox := range s.mailbox {
		// mlog.Info("Scraper:Topic: %s", mbox.Topic)
		s.dispatch(mbox.Topic, mbox.Content)
	}
}

func (s *Scraper) scrapeMovie(msg *pubsub.Message) {
	movie := msg.Payload.(*model.Movie)

	scrape := &Scrape{
		s.bus,
		s.tmdb,
		&dto.Scrape{
			// BasePath: s.settings.WebDir,
			Movie:  movie,
			Forced: false,
		},
	}

	s.pool.Exec(scrape)
}

type Scrape struct {
	bus  *pubsub.PubSub
	tmdb *tmdb.Tmdb
	dto  *dto.Scrape
}

func (s *Scrape) Execute(wid int) {
	movie := s.dto.Movie.(*model.Movie)

	lib.Notify(s.bus, "import:progress", fmt.Sprintf("SCRAPE REQUESTED (%d) [%s]", wid, movie.Title))

	now := time.Now().UTC().Format(time.RFC3339)
	movie.Added = now
	movie.Modified = now

	movie.Score = 0

	lib.Notify(s.bus, "import:progress", fmt.Sprintf("STARTED TMDB (%d) [%s]", wid, movie.Title))
	movies, err := s.tmdb.SearchMovie(movie.Title)
	if err != nil {
		s.bus.Pub(nil, "/event/workunit/done")

		mlog.Error(err)
		return
	}

	if movies.Total_Results == 0 {
		lib.Notify(s.bus, "import:progress", fmt.Sprintf("TMDB: NO MATCH FOUND (%d) [%s]", wid, movie.Title))

		msg := &pubsub.Message{Payload: s.dto}
		s.bus.Pub(msg, "/event/movie/tmdbnotfound")

		return
	} else if movies.Total_Results > 1 {
		lib.Notify(s.bus, "import:progress", fmt.Sprintf("TMDB: MORE THAN ONE (%d) [%s]", wid, movie.Title))
	}

	id := movies.Results[0].Id

	_scrape(wid, s.tmdb, id, movie)

	s.dto.BaseUrl = s.tmdb.BaseUrl
	s.dto.SecureBaseUrl = s.tmdb.SecureBaseUrl

	lib.Notify(s.bus, "import:progress", fmt.Sprintf("SCRAPE COMPLETED (%d) [%s]", wid, movie.Title))

	msg := &pubsub.Message{Payload: s.dto}
	s.bus.Pub(msg, "/event/movie/scraped")
}

func (s *Scraper) reScrapeMovie(msg *pubsub.Message) {
	movie := msg.Payload.(*model.Movie)

	reScrape := &ReScrape{
		s.bus,
		s.tmdb,
		&dto.Scrape{
			// BasePath: s.settings.WebDir,
			Movie:  movie,
			Forced: true,
		},
	}

	s.pool.Exec(reScrape)
}

type ReScrape struct {
	bus  *pubsub.PubSub
	tmdb *tmdb.Tmdb
	dto  *dto.Scrape
}

func (s *ReScrape) Execute(wid int) {
	movie := s.dto.Movie.(*model.Movie)

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("RESCRAPE REQUESTED (%d) [%d] %s", wid, movie.Id, movie.Title))
	mlog.Info("RESCRAPE REQUESTED (%d) [%d] %s", wid, movie.Id, movie.Title)

	now := time.Now().UTC().Format(time.RFC3339)
	movie.Modified = now

	id := movie.Tmdb_Id

	err := _scrape(wid, s.tmdb, id, movie)
	if err != nil {
		// lib.Notify(s.bus, "import:progress", fmt.Sprintf("RESCRAPE FAILED (%d) [%d] %s: %s", wid, movie.Id, movie.Title, err))
		mlog.Warning("RESCRAPE FAILED (%d) [%d] %s: %s", wid, movie.Id, movie.Title, err)
		s.bus.Pub(nil, "/event/workunit/done")

		return
	}

	s.dto.BaseUrl = s.tmdb.BaseUrl
	s.dto.SecureBaseUrl = s.tmdb.SecureBaseUrl

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("RESCRAPE COMPLETED (%d) [%d] %s", wid, movie.Id, movie.Title))
	mlog.Info("RESCRAPE COMPLETED (%d) [%d] %s", wid, movie.Id, movie.Title)

	msg := &pubsub.Message{Payload: s.dto}
	s.bus.Pub(msg, "/event/movie/scraped")
}

func _scrape(wid int, tmdb *tmdb.Tmdb, id uint64, movie *model.Movie) error {
	// log.Printf("before getmovie [%d] %s", id, media.Movie.Title)
	// mlog.Info("[%s] before getmovie [%s]", movie.Title)
	gmr, err := tmdb.GetMovie(id)
	if err != nil {
		return errors.New(fmt.Sprintf("FAILED GETTING MOVIE (%d) [%s]", wid, movie.Title))
	}

	movie.Title = gmr.Title
	movie.Original_Title = gmr.Original_Title
	movie.Runtime = gmr.Runtime
	movie.Tmdb_Id = gmr.Id
	movie.Imdb_Id = gmr.Imdb_Id
	movie.Overview = gmr.Overview
	movie.Tagline = gmr.Tagline
	movie.Cover = gmr.Poster_Path
	movie.Backdrop = gmr.Backdrop_Path

	movie.Genres = ""
	for i := 0; i < len(gmr.Genres); i++ {
		attr := &gmr.Genres[i]
		if movie.Genres == "" {
			movie.Genres = attr.Name
		} else {
			movie.Genres += " " + attr.Name
		}
	}

	movie.Vote_Average = gmr.Vote_Average
	movie.Vote_Count = gmr.Vote_Count

	movie.Production_Countries = ""
	for i := 0; i < len(gmr.Production_Countries); i++ {
		attr := &gmr.Production_Countries[i]
		if movie.Production_Countries == "" {
			movie.Production_Countries = attr.Name
		} else {
			movie.Production_Countries += "|" + attr.Name
		}
	}

	var omdb model.Omdb

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("STARTED OMDB [%s]", movie.Title))
	err = lib.RestGet(fmt.Sprintf("http://www.omdbapi.com/?i=%s", movie.Imdb_Id), &omdb)
	if err != nil {
		return errors.New(fmt.Sprintf("OMDB Error: %s", err))
	}

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("omdb: %+v", omdb))

	vote := strings.Replace(omdb.Imdb_Vote, ",", "", -1)
	imdb_vote, _ := strconv.ParseUint(vote, 0, 64)
	imdb_rating, _ := strconv.ParseFloat(omdb.Imdb_Rating, 64)

	movie.Director = omdb.Director
	movie.Writer = omdb.Writer
	movie.Actors = omdb.Actors
	movie.Awards = omdb.Awards
	movie.Imdb_Rating = imdb_rating
	movie.Imdb_Votes = imdb_vote

	return nil
}

func (s *Scraper) configChanged(msg *pubsub.Message) {
	s.settings = msg.Payload.(*lib.Settings)
}
<commit_msg>(back) Split genres with a "|" and don't add a genre if it exists already (back) Don't add a country if it exists already<commit_after>package services

import (
	"github.com/jbrodriguez/go-tmdb"
	"github.com/jbrodriguez/mlog"
	"github.com/jbrodriguez/pubsub"
	// "io/ioutil"
	"errors"
	"fmt"
	"jbrodriguez/mediagui/server/dto"
	"jbrodriguez/mediagui/server/lib"
	"jbrodriguez/mediagui/server/model"
	"strconv"
	"strings"
	"time"
)

type Scraper struct {
	Service

	bus      *pubsub.PubSub
	settings *lib.Settings
	pool     *lib.Pool
	tmdb     *tmdb.Tmdb

	mailbox chan *pubsub.Mailbox
}

func NewScraper(bus *pubsub.PubSub, settings *lib.Settings) *Scraper {
	scraper := &Scraper{bus: bus, settings: settings}
	scraper.init()
	return scraper
}

func (s *Scraper) Start() {
	mlog.Info("Starting service Scraper ...")

	var err error
	s.tmdb, err = tmdb.NewClient("e610ded10c3f47d05fe797961d90fea6", false)
	if err != nil {
		mlog.Fatalf("Unable to create tmdb client: %s", err)
	}

	s.mailbox = s.register(s.bus, "/command/movie/scrape", s.scrapeMovie)
	s.registerAdditional(s.bus, "/command/movie/rescrape", s.reScrapeMovie, s.mailbox)
	s.registerAdditional(s.bus, "/event/config/changed", s.configChanged, s.mailbox)

	s.pool = lib.NewPool(12, 4000)

	go s.react()
}

func (s *Scraper) Stop() {
	mlog.Info("Stopped service Scraper ...")
}

func (s *Scraper) react() {
	for mbox := range s.mailbox {
		// mlog.Info("Scraper:Topic: %s", mbox.Topic)
		s.dispatch(mbox.Topic, mbox.Content)
	}
}

func (s *Scraper) scrapeMovie(msg *pubsub.Message) {
	movie := msg.Payload.(*model.Movie)

	scrape := &Scrape{
		s.bus,
		s.tmdb,
		&dto.Scrape{
			// BasePath: s.settings.WebDir,
			Movie:  movie,
			Forced: false,
		},
	}

	s.pool.Exec(scrape)
}

type Scrape struct {
	bus  *pubsub.PubSub
	tmdb *tmdb.Tmdb
	dto  *dto.Scrape
}

func (s *Scrape) Execute(wid int) {
	movie := s.dto.Movie.(*model.Movie)

	lib.Notify(s.bus, "import:progress", fmt.Sprintf("SCRAPE REQUESTED (%d) [%s]", wid, movie.Title))

	now := time.Now().UTC().Format(time.RFC3339)
	movie.Added = now
	movie.Modified = now

	movie.Score = 0

	lib.Notify(s.bus, "import:progress", fmt.Sprintf("STARTED TMDB (%d) [%s]", wid, movie.Title))
	movies, err := s.tmdb.SearchMovie(movie.Title)
	if err != nil {
		s.bus.Pub(nil, "/event/workunit/done")

		mlog.Error(err)
		return
	}

	if movies.Total_Results == 0 {
		lib.Notify(s.bus, "import:progress", fmt.Sprintf("TMDB: NO MATCH FOUND (%d) [%s]", wid, movie.Title))

		msg := &pubsub.Message{Payload: s.dto}
		s.bus.Pub(msg, "/event/movie/tmdbnotfound")

		return
	} else if movies.Total_Results > 1 {
		lib.Notify(s.bus, "import:progress", fmt.Sprintf("TMDB: MORE THAN ONE (%d) [%s]", wid, movie.Title))
	}

	id := movies.Results[0].Id

	_scrape(wid, s.tmdb, id, movie)

	s.dto.BaseUrl = s.tmdb.BaseUrl
	s.dto.SecureBaseUrl = s.tmdb.SecureBaseUrl

	lib.Notify(s.bus, "import:progress", fmt.Sprintf("SCRAPE COMPLETED (%d) [%s]", wid, movie.Title))

	msg := &pubsub.Message{Payload: s.dto}
	s.bus.Pub(msg, "/event/movie/scraped")
}

func (s *Scraper) reScrapeMovie(msg *pubsub.Message) {
	movie := msg.Payload.(*model.Movie)

	reScrape := &ReScrape{
		s.bus,
		s.tmdb,
		&dto.Scrape{
			// BasePath: s.settings.WebDir,
			Movie:  movie,
			Forced: true,
		},
	}

	s.pool.Exec(reScrape)
}

type ReScrape struct {
	bus  *pubsub.PubSub
	tmdb *tmdb.Tmdb
	dto  *dto.Scrape
}

func (s *ReScrape) Execute(wid int) {
	movie := s.dto.Movie.(*model.Movie)

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("RESCRAPE REQUESTED (%d) [%d] %s", wid, movie.Id, movie.Title))
	mlog.Info("RESCRAPE REQUESTED (%d) [%d] %s", wid, movie.Id, movie.Title)

	now := time.Now().UTC().Format(time.RFC3339)
	movie.Modified = now

	id := movie.Tmdb_Id

	err := _scrape(wid, s.tmdb, id, movie)
	if err != nil {
		// lib.Notify(s.bus, "import:progress", fmt.Sprintf("RESCRAPE FAILED (%d) [%d] %s: %s", wid, movie.Id, movie.Title, err))
		mlog.Warning("RESCRAPE FAILED (%d) [%d] %s: %s", wid, movie.Id, movie.Title, err)
		s.bus.Pub(nil, "/event/workunit/done")

		return
	}

	s.dto.BaseUrl = s.tmdb.BaseUrl
	s.dto.SecureBaseUrl = s.tmdb.SecureBaseUrl

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("RESCRAPE COMPLETED (%d) [%d] %s", wid, movie.Id, movie.Title))
	mlog.Info("RESCRAPE COMPLETED (%d) [%d] %s", wid, movie.Id, movie.Title)

	msg := &pubsub.Message{Payload: s.dto}
	s.bus.Pub(msg, "/event/movie/scraped")
}

func _scrape(wid int, tmdb *tmdb.Tmdb, id uint64, movie *model.Movie) error {
	// log.Printf("before getmovie [%d] %s", id, media.Movie.Title)
	// mlog.Info("[%s] before getmovie [%s]", movie.Title)
	gmr, err := tmdb.GetMovie(id)
	if err != nil {
		return errors.New(fmt.Sprintf("FAILED GETTING MOVIE (%d) [%s]", wid, movie.Title))
	}

	movie.Title = gmr.Title
	movie.Original_Title = gmr.Original_Title
	movie.Runtime = gmr.Runtime
	movie.Tmdb_Id = gmr.Id
	movie.Imdb_Id = gmr.Imdb_Id
	movie.Overview = gmr.Overview
	movie.Tagline = gmr.Tagline
	movie.Cover = gmr.Poster_Path
	movie.Backdrop = gmr.Backdrop_Path

	movie.Genres = ""
	for i := 0; i < len(gmr.Genres); i++ {
		attr := &gmr.Genres[i]
		if movie.Genres == "" {
			movie.Genres = attr.Name
		} else {
			if strings.Contains(movie.Genres, attr.Name) {
				continue
			}

			movie.Genres += "|" + attr.Name
		}
	}

	movie.Vote_Average = gmr.Vote_Average
	movie.Vote_Count = gmr.Vote_Count

	movie.Production_Countries = ""
	for i := 0; i < len(gmr.Production_Countries); i++ {
		attr := &gmr.Production_Countries[i]
		if movie.Production_Countries == "" {
			movie.Production_Countries = attr.Name
		} else {
			if strings.Contains(movie.Production_Countries, attr.Name) {
				continue
			}

			movie.Production_Countries += "|" + attr.Name
		}
	}

	var omdb model.Omdb

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("STARTED OMDB [%s]", movie.Title))
	err = lib.RestGet(fmt.Sprintf("http://www.omdbapi.com/?i=%s", movie.Imdb_Id), &omdb)
	if err != nil {
		return errors.New(fmt.Sprintf("OMDB Error: %s", err))
	}

	// lib.Notify(s.bus, "import:progress", fmt.Sprintf("omdb: %+v", omdb))

	vote := strings.Replace(omdb.Imdb_Vote, ",", "", -1)
	imdb_vote, _ := strconv.ParseUint(vote, 0, 64)
	imdb_rating, _ := strconv.ParseFloat(omdb.Imdb_Rating, 64)

	movie.Director = omdb.Director
	movie.Writer = omdb.Writer
	movie.Actors = omdb.Actors
	movie.Awards = omdb.Awards
	movie.Imdb_Rating = imdb_rating
	movie.Imdb_Votes = imdb_vote

	return nil
}

func (s *Scraper) configChanged(msg *pubsub.Message) {
	s.settings = msg.Payload.(*lib.Settings)
}
<|endoftext|>


<commit_before>package persistentvolumeclaim

import (
	"fmt"

	"github.com/rancher/norman/httperror"
	"github.com/rancher/norman/types"
	"github.com/rancher/rancher/pkg/api/store/storageclass"
	"github.com/rancher/rancher/pkg/clustermanager"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type Validator struct {
	ClusterManager *clustermanager.Manager
}

func (v *Validator) Validator(request *types.APIContext, schema *types.Schema, data map[string]interface{}) error {
	clusterName := v.ClusterManager.ClusterName(request)
	c, err := v.ClusterManager.UserContext(clusterName)
	if err != nil {
		return err
	}

	storageClassID, _ := data["storageClassId"].(string)
	storageClass, err := c.Storage.StorageClasses("").Get(storageClassID, v1.GetOptions{})
	if err != nil {
		return err
	}

	// if the referenced storage class does not have a storageaccounttype, storage account creation will fail in k8s
	if storageClass.Provisioner == storageclass.AzureDisk {
		if storageClass.Parameters[storageclass.StorageAccountType] == "" && storageClass.Parameters[storageclass.SkuName] == "" {
			return httperror.NewAPIError(httperror.InvalidBodyContent, fmt.Sprintf("invalid storage class [%s]: must provide "+
				"storageaccounttype or skuName", storageClass.Name))
		}
	}

	return nil
}
<commit_msg>return if no storage class<commit_after>package persistentvolumeclaim

import (
	"fmt"

	"github.com/rancher/norman/httperror"
	"github.com/rancher/norman/types"
	"github.com/rancher/rancher/pkg/api/store/storageclass"
	"github.com/rancher/rancher/pkg/clustermanager"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type Validator struct {
	ClusterManager *clustermanager.Manager
}

func (v *Validator) Validator(request *types.APIContext, schema *types.Schema, data map[string]interface{}) error {
	clusterName := v.ClusterManager.ClusterName(request)
	c, err := v.ClusterManager.UserContext(clusterName)
	if err != nil {
		return err
	}

	storageClassID, _ := data["storageClassId"].(string)
	if storageClassID == "" {
		return nil
	}

	storageClass, err := c.Storage.StorageClasses("").Get(storageClassID, v1.GetOptions{})
	if err != nil {
		return err
	}

	// if the referenced storage class does not have a storageaccounttype, storage account creation will fail in k8s
	if storageClass.Provisioner == storageclass.AzureDisk {
		if storageClass.Parameters[storageclass.StorageAccountType] == "" && storageClass.Parameters[storageclass.SkuName] == "" {
			return httperror.NewAPIError(httperror.InvalidBodyContent, fmt.Sprintf("invalid storage class [%s]: must provide "+
				"storageaccounttype or skuName", storageClass.Name))
		}
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 Google LLC

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 (
	"context"
	"time"

	"github.com/google/go-cmp/cmp/cmpopts"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/equality"

	"github.com/google/go-cmp/cmp"
	"knative.dev/pkg/apis"
)

const (
	minRetentionDuration = 10 * time.Second   // 10 seconds.
	maxRetentionDuration = 7 * 24 * time.Hour // 7 days.
)

func (current *PullSubscription) Validate(ctx context.Context) *apis.FieldError {
	return current.Spec.Validate(ctx).ViaField("spec")
}

func (current *PullSubscriptionSpec) Validate(ctx context.Context) *apis.FieldError {
	var errs *apis.FieldError
	// Topic [required]
	if current.Topic == "" {
		errs = errs.Also(apis.ErrMissingField("topic"))
	}
	// Sink [required]
	if current.Sink == nil || equality.Semantic.DeepEqual(current.Sink, &corev1.ObjectReference{}) {
		errs = errs.Also(apis.ErrMissingField("sink"))
	} else if err := validateRef(current.Sink); err != nil {
		errs = errs.Also(err.ViaField("sink"))
	}
	// Transformer [optional]
	if current.Transformer != nil && !equality.Semantic.DeepEqual(current.Transformer, &corev1.ObjectReference{}) {
		if err := validateRef(current.Transformer); err != nil {
			errs = errs.Also(err.ViaField("transformer"))
		}
	}

	if current.RetentionDuration != nil {
		// If set, RetentionDuration Cannot be longer than 7 days or shorter than 10 minutes.
		if *current.RetentionDuration < minRetentionDuration || *current.RetentionDuration > maxRetentionDuration {
			errs = errs.Also(apis.ErrInvalidValue(current.RetentionDuration, "retentionDuration"))
		}
	}

	// Mode [optional]
	switch current.Mode {
	case "", ModeCloudEventsBinary, ModeCloudEventsStructured, ModePushCompatible:
		// valid
	default:
		errs = errs.Also(apis.ErrInvalidValue(current.Mode, "mode"))
	}

	return errs
}

func validateRef(ref *corev1.ObjectReference) *apis.FieldError {
	// nil check.
	if ref == nil {
		return apis.ErrMissingField(apis.CurrentField)
	}
	// Check the object.
	var errs *apis.FieldError
	// Required Fields
	if ref.Name == "" {
		errs = errs.Also(apis.ErrMissingField("name"))
	}
	if ref.APIVersion == "" {
		errs = errs.Also(apis.ErrMissingField("apiVersion"))
	}
	if ref.Kind == "" {
		errs = errs.Also(apis.ErrMissingField("kind"))
	}

	return errs
}

func (current *PullSubscription) CheckImmutableFields(ctx context.Context, og apis.Immutable) *apis.FieldError {
	original, ok := og.(*PullSubscription)
	if !ok {
		return &apis.FieldError{Message: "The provided original was not a PullSubscription"}
	}
	if original == nil {
		return nil
	}

	// Modification of Sink and Transform allowed. Everything else is immutable.
	if diff := cmp.Diff(original.Spec, current.Spec,
		cmpopts.IgnoreFields(PullSubscriptionSpec{}, "Sink", "Transformer", "Mode")); diff != "" {
		return &apis.FieldError{
			Message: "Immutable fields changed (-old +new)",
			Paths:   []string{"spec"},
			Details: diff,
		}
	}
	return nil
}
<commit_msg>use ErrOutOfBoundsValue<commit_after>/*
Copyright 2019 Google LLC

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 (
	"context"
	"time"

	"github.com/google/go-cmp/cmp/cmpopts"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/equality"

	"github.com/google/go-cmp/cmp"
	"knative.dev/pkg/apis"
)

const (
	minRetentionDuration = 10 * time.Second   // 10 seconds.
	maxRetentionDuration = 7 * 24 * time.Hour // 7 days.
)

func (current *PullSubscription) Validate(ctx context.Context) *apis.FieldError {
	return current.Spec.Validate(ctx).ViaField("spec")
}

func (current *PullSubscriptionSpec) Validate(ctx context.Context) *apis.FieldError {
	var errs *apis.FieldError
	// Topic [required]
	if current.Topic == "" {
		errs = errs.Also(apis.ErrMissingField("topic"))
	}
	// Sink [required]
	if current.Sink == nil || equality.Semantic.DeepEqual(current.Sink, &corev1.ObjectReference{}) {
		errs = errs.Also(apis.ErrMissingField("sink"))
	} else if err := validateRef(current.Sink); err != nil {
		errs = errs.Also(err.ViaField("sink"))
	}
	// Transformer [optional]
	if current.Transformer != nil && !equality.Semantic.DeepEqual(current.Transformer, &corev1.ObjectReference{}) {
		if err := validateRef(current.Transformer); err != nil {
			errs = errs.Also(err.ViaField("transformer"))
		}
	}

	if current.RetentionDuration != nil {
		// If set, RetentionDuration Cannot be longer than 7 days or shorter than 10 minutes.
		if *current.RetentionDuration < minRetentionDuration || *current.RetentionDuration > maxRetentionDuration {
			errs = errs.Also(apis.ErrOutOfBoundsValue(current.RetentionDuration, minRetentionDuration, maxRetentionDuration, "retentionDuration"))
		}
	}

	// Mode [optional]
	switch current.Mode {
	case "", ModeCloudEventsBinary, ModeCloudEventsStructured, ModePushCompatible:
		// valid
	default:
		errs = errs.Also(apis.ErrInvalidValue(current.Mode, "mode"))
	}

	return errs
}

func validateRef(ref *corev1.ObjectReference) *apis.FieldError {
	// nil check.
	if ref == nil {
		return apis.ErrMissingField(apis.CurrentField)
	}
	// Check the object.
	var errs *apis.FieldError
	// Required Fields
	if ref.Name == "" {
		errs = errs.Also(apis.ErrMissingField("name"))
	}
	if ref.APIVersion == "" {
		errs = errs.Also(apis.ErrMissingField("apiVersion"))
	}
	if ref.Kind == "" {
		errs = errs.Also(apis.ErrMissingField("kind"))
	}

	return errs
}

func (current *PullSubscription) CheckImmutableFields(ctx context.Context, og apis.Immutable) *apis.FieldError {
	original, ok := og.(*PullSubscription)
	if !ok {
		return &apis.FieldError{Message: "The provided original was not a PullSubscription"}
	}
	if original == nil {
		return nil
	}

	// Modification of Sink and Transform allowed. Everything else is immutable.
	if diff := cmp.Diff(original.Spec, current.Spec,
		cmpopts.IgnoreFields(PullSubscriptionSpec{}, "Sink", "Transformer", "Mode")); diff != "" {
		return &apis.FieldError{
			Message: "Immutable fields changed (-old +new)",
			Paths:   []string{"spec"},
			Details: diff,
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package xpath

/*
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

void check_xpath_syntax_noop() {
}

char *check_xpath_syntax(const char *xpath) {
	char *rval = NULL;
	xmlXPathContextPtr ctx = xmlXPathNewContext(NULL);
	ctx->error = check_xpath_syntax_noop;
	xmlXPathCtxtCompile(ctx, (const xmlChar *)xpath);
	if (ctx->lastError.domain > 0) {
		//fprintf(stderr, "%s Code: %d Domain: %d", ctx->lastError.str2, ctx->lastError.code, ctx->lastError.domain);
		rval = "ERROR";
	}
	xmlXPathFreeContext(ctx);
	return rval;
}
*/
import "C"
import "unsafe"
import . "gokogiri/util"
import "runtime"
import "errors"

type Expression struct {
	Ptr *C.xmlXPathCompExpr
}

func Check(path string) (err error) {
	str := C.CString(path)
	defer C.free(unsafe.Pointer(str))
	cstr := C.check_xpath_syntax(str)
	if cstr != nil {
		err = errors.New(C.GoString(cstr))
	}
	return
}

func Compile(path string) (expr *Expression) {
	if len(path) == 0 {
		return
	}

	xpathBytes := AppendCStringTerminator([]byte(path))
	xpathPtr := unsafe.Pointer(&xpathBytes[0])
	ptr := C.xmlXPathCompile((*C.xmlChar)(xpathPtr))
	if ptr == nil {
		return
	}
	expr = &Expression{Ptr: ptr}
	runtime.SetFinalizer(expr, (*Expression).Free)
	return
}

func (exp *Expression) Free() {
	if exp.Ptr != nil {
		C.xmlXPathFreeCompExpr(exp.Ptr)
		exp.Ptr = nil
	}
}
<commit_msg>Better compile time error capture<commit_after>package xpath

/*
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <string.h>

void check_xpath_syntax_noop(void *ctx, const char *fmt, ...) {
}

char *check_xpath_syntax(const char *xpath) {
	xmlGenericErrorFunc err_func = check_xpath_syntax_noop;
	initGenericErrorDefaultFunc(&err_func);
	xmlResetLastError();
	xmlXPathCompile((const xmlChar *)xpath);
	xmlErrorPtr err = xmlGetLastError();
	if (err != NULL) {
		if (err->code == XML_XPATH_EXPR_ERROR) {
			// TODO: Not the cleanest but should scale well
			int size = strlen(err->message) + strlen(err->str1) + err->int1 + 16;
			char *msg = malloc(size);
			sprintf(msg, "%s%s\n%*s^", err->message, err->str1, err->int1, " ");
			return msg;
		} else {
			return strdup(err->message);
		}
	}
	return NULL;
}
*/
import "C"
import "unsafe"
import . "gokogiri/util"
import "runtime"
import "errors"

type Expression struct {
	Ptr *C.xmlXPathCompExpr
}

func Check(path string) (err error) {
	str := C.CString(path)
	defer C.free(unsafe.Pointer(str))
	cstr := C.check_xpath_syntax(str)
	if cstr != nil {
		defer C.free(unsafe.Pointer(cstr))
		err = errors.New(C.GoString(cstr))
	}
	return
}

func Compile(path string) (expr *Expression) {
	if len(path) == 0 {
		return
	}

	xpathBytes := AppendCStringTerminator([]byte(path))
	xpathPtr := unsafe.Pointer(&xpathBytes[0])
	ptr := C.xmlXPathCompile((*C.xmlChar)(xpathPtr))
	if ptr == nil {
		return
	}
	expr = &Expression{Ptr: ptr}
	runtime.SetFinalizer(expr, (*Expression).Free)
	return
}

func (exp *Expression) Free() {
	if exp.Ptr != nil {
		C.xmlXPathFreeCompExpr(exp.Ptr)
		exp.Ptr = nil
	}
}
<|endoftext|>