<commit_before>package disk_test

import (
	"errors"
	"fmt"

	"github.com/cloudfoundry/bosh-agent/platform/windows/disk"
	"github.com/cloudfoundry/bosh-utils/system/fakes"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const newLine = `
`

var _ = Describe("Linker", func() {
	var (
		cmdRunner *fakes.FakeCmdRunner
		linker    *disk.Linker
		location  string
	)

	BeforeEach(func() {
		cmdRunner = fakes.NewFakeCmdRunner()
		linker = &disk.Linker{
			Runner: cmdRunner,
		}
		location = `C:\my\location`
	})

	It("returns the linked destination when the link exists", func() {
		expectedTarget := `D:\`
		cmdRunner.AddCmdResult(
			findItemTargetCommand(location),
			fakes.FakeCmdResult{Stdout: fmt.Sprintf("%s%s", expectedTarget, newLine)},
		)

		target, err := linker.IsLinked(location)

		Expect(err).NotTo(HaveOccurred())
		Expect(target).To(Equal(expectedTarget))
	})

	It("when the isLinked command fails to run, returns a wrapped error", func() {
		cmdRunnerError := errors.New("It went wrong")
		cmdRunner.AddCmdResult(
			findItemTargetCommand(location),
			fakes.FakeCmdResult{ExitStatus: -1, Error: cmdRunnerError},
		)

		_, err := linker.IsLinked(location)
		Expect(err).To(MatchError(fmt.Sprintf(
			"Failed to run command \"%s\": It went wrong",
			findItemTargetCommand(location),
		)))
	})
})

func findItemTargetCommand(location string) string {
	return fmt.Sprintf(
		"powershell.exe Get-Item %s -ErrorAction Ignore | Select -ExpandProperty Target -ErrorAction Ignore",
		location,
	)
}
<commit_msg>Backfill testing for handling link checking for non-existant links<commit_after>package disk_test

import (
	"errors"
	"fmt"

	"github.com/cloudfoundry/bosh-agent/platform/windows/disk"
	"github.com/cloudfoundry/bosh-utils/system/fakes"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const newLine = `
`

var _ = Describe("Linker", func() {
	var (
		cmdRunner *fakes.FakeCmdRunner
		linker    *disk.Linker
		location  string
	)

	BeforeEach(func() {
		cmdRunner = fakes.NewFakeCmdRunner()
		linker = &disk.Linker{
			Runner: cmdRunner,
		}
		location = `C:\my\location`
	})

	It("returns the linked destination when the link exists", func() {
		expectedTarget := `D:\`
		cmdRunner.AddCmdResult(
			findItemTargetCommand(location),
			fakes.FakeCmdResult{Stdout: fmt.Sprintf("%s%s", expectedTarget, newLine)},
		)

		target, err := linker.IsLinked(location)

		Expect(err).NotTo(HaveOccurred())
		Expect(target).To(Equal(expectedTarget))
	})

	It("returns nothing when the link does not exist", func() {
		expectedTarget := ""
		badLocation := `c:\road\to\nowhere`

		cmdRunner.AddCmdResult(
			findItemTargetCommand(badLocation),
			fakes.FakeCmdResult{ExitStatus: 1, Stdout: fmt.Sprintf("%s%s", expectedTarget, newLine)},
		)

		target, err := linker.IsLinked(badLocation)

		Expect(err).NotTo(HaveOccurred())
		Expect(target).To(Equal(expectedTarget))
	})

	It("when the isLinked command fails to run, returns a wrapped error", func() {
		cmdRunnerError := errors.New("It went wrong")
		cmdRunner.AddCmdResult(
			findItemTargetCommand(location),
			fakes.FakeCmdResult{ExitStatus: -1, Error: cmdRunnerError},
		)

		_, err := linker.IsLinked(location)
		Expect(err).To(MatchError(fmt.Sprintf(
			"Failed to run command \"%s\": It went wrong",
			findItemTargetCommand(location),
		)))
	})
})

func findItemTargetCommand(location string) string {
	return fmt.Sprintf(
		"powershell.exe Get-Item %s -ErrorAction Ignore | Select -ExpandProperty Target -ErrorAction Ignore",
		location,
	)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/mitchellh/packer/builder/openstack-new"
	"github.com/mitchellh/packer/packer/plugin"
)

func main() {
	server, err := plugin.Server()
	if err != nil {
		panic(err)
	}
	server.RegisterBuilder(new(openstack.Builder))
	server.Serve()
}
<commit_msg>remove the new plugin<commit_after><|endoftext|>


<commit_before>/*
Copyright 2019 The Knative Authors

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

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

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

// log_parser.go collects failed tests from jobs that triggered the retryer and
// finds flaky tests that are relevant to that failed job.

package main

import (
	"fmt"
	"log"
	"path/filepath"
	"strings"

	"knative.dev/test-infra/shared/junit"
	"knative.dev/test-infra/shared/prow"
	"knative.dev/test-infra/tools/flaky-test-reporter/jsonreport"

	// TODO: remove this import once "k8s.io/test-infra" import problems are fixed
	// https://github.com/knative/test-infra/test-infra/issues/912
	"knative.dev/test-infra/tools/monitoring/prowapi"
)

var client jsonreport.Client

// InitLogParser configures jsonreport's dependencies.
func InitLogParser(serviceAccount string) error {
	var err error
	client, err = jsonreport.Initialize(serviceAccount)
	return err
}

// JobData contains the message describing a job, a local cache of its failed tests,
// and a cached flaky report it is referencing.
type JobData struct {
	*prowapi.ReportMessage
	failedTests  []string
	flakyReports []jsonreport.Report
}

// IsSupported checks to make sure the message can be processed with the current flaky
// test information
func (jd *JobData) IsSupported() bool {
	prefix := fmt.Sprintf("Job %s/%s did not fit criteria", jd.JobName, jd.RunID)
	if jd.Status != prowapi.FailureState {
		log.Printf("%s: message did not signal a failure: %v\n", prefix, jd.Status)
		return false
	}
	// check type
	if jd.JobType != prowapi.PresubmitJob {
		log.Printf("%s: message did not originate from presubmit: %v\n", prefix, jd.JobType)
		return false
	}
	// check repo
	if len(jd.Refs) == 0 {
		log.Printf("%s: message does not contain any repository references\n", prefix)
		return false
	}
	repos, err := client.GetReportRepos(flakesRecorderJobName)
	if err != nil {
		log.Printf("%s: error getting reporter's repositories: %v\n", prefix, err)
		return false
	}
	expRepo := false
	for _, repo := range repos {
		if jd.Refs[0].Repo == repo {
			expRepo = true
			break
		}
	}
	if !expRepo {
		log.Printf("%s: message's repo is not being analyzed by flaky test reporter: '%v'\n", prefix, jd.Refs[0].Repo)
		return false
	}
	// make sure pull ID exists
	if len(jd.Refs[0].Pulls) == 0 {
		log.Printf("%s: message does not contain any pull requests\n", prefix)
		return false
	}
	return true
}

// getFailedTests gets all the tests that failed in the given job.
func (jd *JobData) getFailedTests() ([]string, error) {
	// use cache if it is populated
	if jd.failedTests != nil {
		return jd.failedTests, nil
	}
	job := prow.NewJob(jd.JobName, string(jd.JobType), jd.Refs[0].Repo, jd.Refs[0].Pulls[0].Number)
	buildID, err := job.GetLatestBuildNumber()
	if err != nil {
		return nil, err
	}
	build := job.NewBuild(buildID)
	results, err := GetCombinedResultsForBuild(build)
	if err != nil {
		return nil, err
	}
	var tests []string
	for _, suites := range results {
		for _, suite := range suites.Suites {
			for _, test := range suite.TestCases {
				if test.GetTestStatus() == junit.Failed {
					tests = append(tests, fmt.Sprintf("%s.%s", suite.Name, test.Name))
				}
			}
		}
	}
	jd.failedTests = tests
	return tests, nil
}

// TODO: This function is a direct copy-paste of the function in
// tools/flaky-test-reporter/result.go. Refactor it out into a shared library.

// GetCombinedResultsForBuild gets all junit results from a build,
// and converts each one into a junit TestSuites struct
func GetCombinedResultsForBuild(build *prow.Build) ([]*junit.TestSuites, error) {
	var allSuites []*junit.TestSuites
	for _, artifact := range build.GetArtifacts() {
		_, fileName := filepath.Split(artifact)
		if !strings.HasPrefix(fileName, "junit_") || !strings.HasSuffix(fileName, ".xml") {
			continue
		}
		relPath, _ := filepath.Rel(build.StoragePath, artifact)
		contents, err := build.ReadFile(relPath)
		if nil != err {
			return nil, err
		}
		if suites, err := junit.UnMarshal(contents); nil != err {
			return nil, err
		} else {
			allSuites = append(allSuites, suites)
		}
	}
	return allSuites, nil
}

// getFlakyTests gets the current flaky tests from the repo JobData originated from
func (jd *JobData) getFlakyTests() ([]string, error) {
	return client.GetFlakyTests(flakesRecorderJobName, jd.Refs[0].Repo)
}

// compareTests compares lists of failed and flaky tests, and returns any outlying failed
// tests, i.e. tests that failed that are NOT flaky.
func getNonFlakyTests(failedTests, flakyTests []string) []string {
	flakyMap := map[string]bool{}
	for _, flaky := range flakyTests {
		flakyMap[flaky] = true
	}
	var notFlaky []string
	for _, failed := range failedTests {
		if _, ok := flakyMap[failed]; !ok {
			notFlaky = append(notFlaky, failed)
		}
	}
	return notFlaky
}
<commit_msg>Add comment explaining why retryer scans latest build instead of current build (#1307)<commit_after>/*
Copyright 2019 The Knative Authors

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

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

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

// log_parser.go collects failed tests from jobs that triggered the retryer and
// finds flaky tests that are relevant to that failed job.

package main

import (
	"fmt"
	"log"
	"path/filepath"
	"strings"

	"knative.dev/test-infra/shared/junit"
	"knative.dev/test-infra/shared/prow"
	"knative.dev/test-infra/tools/flaky-test-reporter/jsonreport"

	// TODO: remove this import once "k8s.io/test-infra" import problems are fixed
	// https://github.com/knative/test-infra/test-infra/issues/912
	"knative.dev/test-infra/tools/monitoring/prowapi"
)

var client jsonreport.Client

// InitLogParser configures jsonreport's dependencies.
func InitLogParser(serviceAccount string) error {
	var err error
	client, err = jsonreport.Initialize(serviceAccount)
	return err
}

// JobData contains the message describing a job, a local cache of its failed tests,
// and a cached flaky report it is referencing.
type JobData struct {
	*prowapi.ReportMessage
	failedTests  []string
	flakyReports []jsonreport.Report
}

// IsSupported checks to make sure the message can be processed with the current flaky
// test information
func (jd *JobData) IsSupported() bool {
	prefix := fmt.Sprintf("Job %s/%s did not fit criteria", jd.JobName, jd.RunID)
	if jd.Status != prowapi.FailureState {
		log.Printf("%s: message did not signal a failure: %v\n", prefix, jd.Status)
		return false
	}
	// check type
	if jd.JobType != prowapi.PresubmitJob {
		log.Printf("%s: message did not originate from presubmit: %v\n", prefix, jd.JobType)
		return false
	}
	// check repo
	if len(jd.Refs) == 0 {
		log.Printf("%s: message does not contain any repository references\n", prefix)
		return false
	}
	repos, err := client.GetReportRepos(flakesRecorderJobName)
	if err != nil {
		log.Printf("%s: error getting reporter's repositories: %v\n", prefix, err)
		return false
	}
	expRepo := false
	for _, repo := range repos {
		if jd.Refs[0].Repo == repo {
			expRepo = true
			break
		}
	}
	if !expRepo {
		log.Printf("%s: message's repo is not being analyzed by flaky test reporter: '%v'\n", prefix, jd.Refs[0].Repo)
		return false
	}
	// make sure pull ID exists
	if len(jd.Refs[0].Pulls) == 0 {
		log.Printf("%s: message does not contain any pull requests\n", prefix)
		return false
	}
	return true
}

// getFailedTests gets all the tests that failed in the given job.
func (jd *JobData) getFailedTests() ([]string, error) {
	// use cache if it is populated
	if len(jd.failedTests) > 0 {
		return jd.failedTests, nil
	}
	job := prow.NewJob(jd.JobName, string(jd.JobType), jd.Refs[0].Repo, jd.Refs[0].Pulls[0].Number)
	// Check latest build instead of using jd.RunID, as there are times where
	// devs initiated retry manually before retryer gets to it, and in this case
	// scaning latest build can help retryer avoid initiating another retry
	// since latest build has no test failure yet
	buildID, err := job.GetLatestBuildNumber()
	if err != nil {
		return nil, err
	}
	build := job.NewBuild(buildID)
	results, err := GetCombinedResultsForBuild(build)
	if err != nil {
		return nil, err
	}
	var tests []string
	for _, suites := range results {
		for _, suite := range suites.Suites {
			for _, test := range suite.TestCases {
				if test.GetTestStatus() == junit.Failed {
					tests = append(tests, fmt.Sprintf("%s.%s", suite.Name, test.Name))
				}
			}
		}
	}
	jd.failedTests = tests
	return tests, nil
}

// TODO: This function is a direct copy-paste of the function in
// tools/flaky-test-reporter/result.go. Refactor it out into a shared library.

// GetCombinedResultsForBuild gets all junit results from a build,
// and converts each one into a junit TestSuites struct
func GetCombinedResultsForBuild(build *prow.Build) ([]*junit.TestSuites, error) {
	var allSuites []*junit.TestSuites
	for _, artifact := range build.GetArtifacts() {
		_, fileName := filepath.Split(artifact)
		if !strings.HasPrefix(fileName, "junit_") || !strings.HasSuffix(fileName, ".xml") {
			continue
		}
		relPath, _ := filepath.Rel(build.StoragePath, artifact)
		contents, err := build.ReadFile(relPath)
		if nil != err {
			return nil, err
		}
		if suites, err := junit.UnMarshal(contents); nil != err {
			return nil, err
		} else {
			allSuites = append(allSuites, suites)
		}
	}
	return allSuites, nil
}

// getFlakyTests gets the current flaky tests from the repo JobData originated from
func (jd *JobData) getFlakyTests() ([]string, error) {
	return client.GetFlakyTests(flakesRecorderJobName, jd.Refs[0].Repo)
}

// compareTests compares lists of failed and flaky tests, and returns any outlying failed
// tests, i.e. tests that failed that are NOT flaky.
func getNonFlakyTests(failedTests, flakyTests []string) []string {
	flakyMap := map[string]bool{}
	for _, flaky := range flakyTests {
		flakyMap[flaky] = true
	}
	var notFlaky []string
	for _, failed := range failedTests {
		if _, ok := flakyMap[failed]; !ok {
			notFlaky = append(notFlaky, failed)
		}
	}
	return notFlaky
}
<|endoftext|>


<commit_before>package waiter

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
)

// LocalGatewayRouteTableVpcAssociationState fetches the LocalGatewayRouteTableVpcAssociation and its State
func LocalGatewayRouteTableVpcAssociationState(conn *ec2.EC2, localGatewayRouteTableVpcAssociationID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		input := &ec2.DescribeLocalGatewayRouteTableVpcAssociationsInput{
			LocalGatewayRouteTableVpcAssociationIds: aws.StringSlice([]string{localGatewayRouteTableVpcAssociationID}),
		}

		output, err := conn.DescribeLocalGatewayRouteTableVpcAssociations(input)

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

		var association *ec2.LocalGatewayRouteTableVpcAssociation

		for _, outputAssociation := range output.LocalGatewayRouteTableVpcAssociations {
			if outputAssociation == nil {
				continue
			}

			if aws.StringValue(outputAssociation.LocalGatewayRouteTableVpcAssociationId) == localGatewayRouteTableVpcAssociationID {
				association = outputAssociation
				break
			}
		}

		if association == nil {
			return association, ec2.RouteTableAssociationStateCodeDisassociated, nil
		}

		return association, aws.StringValue(association.State), nil
	}
}

const (
	ClientVpnEndpointStatusNotFound = "NotFound"

	ClientVpnEndpointStatusUnknown = "Unknown"
)

// ClientVpnEndpointStatus fetches the Client VPN endpoint and its Status
func ClientVpnEndpointStatus(conn *ec2.EC2, endpointID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		result, err := conn.DescribeClientVpnEndpoints(&ec2.DescribeClientVpnEndpointsInput{
			ClientVpnEndpointIds: aws.StringSlice([]string{endpointID}),
		})
		if tfec2.ErrCodeEquals(err, tfec2.ErrCodeClientVpnEndpointIdNotFound) {
			return nil, ClientVpnEndpointStatusNotFound, nil
		}
		if err != nil {
			return nil, ClientVpnEndpointStatusUnknown, err
		}

		if result == nil || len(result.ClientVpnEndpoints) == 0 || result.ClientVpnEndpoints[0] == nil {
			return nil, ClientVpnEndpointStatusNotFound, nil
		}

		endpoint := result.ClientVpnEndpoints[0]
		if endpoint.Status == nil || endpoint.Status.Code == nil {
			return endpoint, ClientVpnEndpointStatusUnknown, nil
		}

		return endpoint, aws.StringValue(endpoint.Status.Code), nil
	}
}

const (
	ClientVpnAuthorizationRuleStatusNotFound = "NotFound"

	ClientVpnAuthorizationRuleStatusUnknown = "Unknown"
)

// ClientVpnAuthorizationRuleStatus fetches the Client VPN authorization rule and its Status
// TODO: This should be in the waiters package, but has a dependency on isAWSErr()
func ClientVpnAuthorizationRuleStatus(conn *ec2.EC2, authorizationRuleID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		endpointID, targetNetworkCidr, accessGroupID, err := tfec2.ClientVpnAuthorizationRuleParseID(authorizationRuleID)
		if err != nil {
			return nil, ClientVpnAuthorizationRuleStatusUnknown, err
		}

		result, err := finder.ClientVpnAuthorizationRule(conn, endpointID, targetNetworkCidr, accessGroupID)
		if tfec2.ErrCodeEquals(err, tfec2.ErrCodeClientVpnAuthorizationRuleNotFound) {
			return nil, ClientVpnAuthorizationRuleStatusNotFound, nil
		}
		if err != nil {
			return nil, ClientVpnAuthorizationRuleStatusUnknown, err
		}

		if result == nil || len(result.AuthorizationRules) == 0 || result.AuthorizationRules[0] == nil {
			return nil, ClientVpnAuthorizationRuleStatusNotFound, nil
		}

		if len(result.AuthorizationRules) > 1 {
			return nil, ClientVpnAuthorizationRuleStatusUnknown, fmt.Errorf("internal error: found %d results for Client VPN authorization rule (%s) status, need 1", len(result.AuthorizationRules), authorizationRuleID)
		}

		rule := result.AuthorizationRules[0]
		if rule.Status == nil || rule.Status.Code == nil {
			return rule, ClientVpnAuthorizationRuleStatusUnknown, nil
		}

		return rule, aws.StringValue(rule.Status.Code), nil
	}
}
<commit_msg>Update aws/internal/service/ec2/waiter/status.go<commit_after>package waiter

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
	"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/finder"
)

// LocalGatewayRouteTableVpcAssociationState fetches the LocalGatewayRouteTableVpcAssociation and its State
func LocalGatewayRouteTableVpcAssociationState(conn *ec2.EC2, localGatewayRouteTableVpcAssociationID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		input := &ec2.DescribeLocalGatewayRouteTableVpcAssociationsInput{
			LocalGatewayRouteTableVpcAssociationIds: aws.StringSlice([]string{localGatewayRouteTableVpcAssociationID}),
		}

		output, err := conn.DescribeLocalGatewayRouteTableVpcAssociations(input)

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

		var association *ec2.LocalGatewayRouteTableVpcAssociation

		for _, outputAssociation := range output.LocalGatewayRouteTableVpcAssociations {
			if outputAssociation == nil {
				continue
			}

			if aws.StringValue(outputAssociation.LocalGatewayRouteTableVpcAssociationId) == localGatewayRouteTableVpcAssociationID {
				association = outputAssociation
				break
			}
		}

		if association == nil {
			return association, ec2.RouteTableAssociationStateCodeDisassociated, nil
		}

		return association, aws.StringValue(association.State), nil
	}
}

const (
	ClientVpnEndpointStatusNotFound = "NotFound"

	ClientVpnEndpointStatusUnknown = "Unknown"
)

// ClientVpnEndpointStatus fetches the Client VPN endpoint and its Status
func ClientVpnEndpointStatus(conn *ec2.EC2, endpointID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		result, err := conn.DescribeClientVpnEndpoints(&ec2.DescribeClientVpnEndpointsInput{
			ClientVpnEndpointIds: aws.StringSlice([]string{endpointID}),
		})
		if tfec2.ErrCodeEquals(err, tfec2.ErrCodeClientVpnEndpointIdNotFound) {
			return nil, ClientVpnEndpointStatusNotFound, nil
		}
		if err != nil {
			return nil, ClientVpnEndpointStatusUnknown, err
		}

		if result == nil || len(result.ClientVpnEndpoints) == 0 || result.ClientVpnEndpoints[0] == nil {
			return nil, ClientVpnEndpointStatusNotFound, nil
		}

		endpoint := result.ClientVpnEndpoints[0]
		if endpoint.Status == nil || endpoint.Status.Code == nil {
			return endpoint, ClientVpnEndpointStatusUnknown, nil
		}

		return endpoint, aws.StringValue(endpoint.Status.Code), nil
	}
}

const (
	ClientVpnAuthorizationRuleStatusNotFound = "NotFound"

	ClientVpnAuthorizationRuleStatusUnknown = "Unknown"
)

// ClientVpnAuthorizationRuleStatus fetches the Client VPN authorization rule and its Status
func ClientVpnAuthorizationRuleStatus(conn *ec2.EC2, authorizationRuleID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		endpointID, targetNetworkCidr, accessGroupID, err := tfec2.ClientVpnAuthorizationRuleParseID(authorizationRuleID)
		if err != nil {
			return nil, ClientVpnAuthorizationRuleStatusUnknown, err
		}

		result, err := finder.ClientVpnAuthorizationRule(conn, endpointID, targetNetworkCidr, accessGroupID)
		if tfec2.ErrCodeEquals(err, tfec2.ErrCodeClientVpnAuthorizationRuleNotFound) {
			return nil, ClientVpnAuthorizationRuleStatusNotFound, nil
		}
		if err != nil {
			return nil, ClientVpnAuthorizationRuleStatusUnknown, err
		}

		if result == nil || len(result.AuthorizationRules) == 0 || result.AuthorizationRules[0] == nil {
			return nil, ClientVpnAuthorizationRuleStatusNotFound, nil
		}

		if len(result.AuthorizationRules) > 1 {
			return nil, ClientVpnAuthorizationRuleStatusUnknown, fmt.Errorf("internal error: found %d results for Client VPN authorization rule (%s) status, need 1", len(result.AuthorizationRules), authorizationRuleID)
		}

		rule := result.AuthorizationRules[0]
		if rule.Status == nil || rule.Status.Code == nil {
			return rule, ClientVpnAuthorizationRuleStatusUnknown, nil
		}

		return rule, aws.StringValue(rule.Status.Code), nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 main

import (
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"
	"k8s.io/api/core/v1"

	"istio.io/pilot/platform/kube"
	"istio.io/pilot/platform/kube/inject"
	"istio.io/pilot/tools/version"
)

var (
	hub               string
	tag               string
	sidecarProxyUID   int64
	verbosity         int
	versionStr        string // override build version
	enableCoreDump    bool
	meshConfigMapName string
	imagePullPolicy   string
	includeIPRanges   string
	debugMode         bool

	inFilename  string
	outFilename string
)

var (
	injectCmd = &cobra.Command{
		Use:   "kube-inject",
		Short: "Inject Envoy sidecar into Kubernetes pod resources",
		Long: `

Automatic Envoy sidecar injection via k8s admission controller is not
ready yet. Instead, use kube-inject to manually inject Envoy sidecar
into Kubernetes resource files. Unsupported resources are left
unmodified so it is safe to run kube-inject over a single file that
contains multiple Service, ConfigMap, Deployment, etc. definitions for
a complex application. Its best to do this when the resource is
initially created.

k8s.io/docs/concepts/workloads/pods/pod-overview/#pod-templates is
updated for Job, DaemonSet, ReplicaSet, and Deployment YAML resource
documents. Support for additional pod-based resource types can be
added as necessary.

The Istio project is continually evolving so the Istio sidecar
configuration may change unannounced. When in doubt re-run istioctl
kube-inject on deployments to get the most up-to-date changes.
`,
		Example: `
# Update resources on the fly before applying.
kubectl apply -f <(istioctl kube-inject -f <resource.yaml>)

# Create a persistent version of the deployment with Envoy sidecar
# injected. This is particularly useful to understand what is
# being injected before committing to Kubernetes API server.
istioctl kube-inject -f deployment.yaml -o deployment-with-istio.yaml

# Update an existing deployment.
kubectl get deployment -o yaml | istioctl kube-inject -f - | kubectl apply -f -
`,
		RunE: func(_ *cobra.Command, _ []string) (err error) {
			if inFilename == "" {
				return errors.New("filename not specified (see --filename or -f)")
			}

			var reader io.Reader
			if inFilename == "-" {
				reader = os.Stdin
			} else {
				if reader, err = os.Open(inFilename); err != nil {
					return err
				}
			}

			var writer io.Writer
			if outFilename == "" {
				writer = os.Stdout
			} else {
				var file *os.File
				if file, err = os.Create(outFilename); err != nil {
					return err
				}
				writer = file
				defer func() { err = file.Close() }()
			}

			if versionStr == "" {
				versionStr = version.Line()
			}

			_, client, err := kube.CreateInterface(kubeconfig)
			if err != nil {
				return err
			}

			_, meshConfig, err := inject.GetMeshConfig(client, namespace, meshConfigMapName)
			if err != nil {
				// Temporary hack (few days), until this is properly implemented
				// https://github.com/istio/pilot/issues/1153
				istioMeshConfigMap, istioMeshConfig, err := inject.GetMeshConfig(client, istioNamespace, meshConfigMapName)
				if err != nil {
					return fmt.Errorf("Istio configMap not found in namespace %q, nor in namespace %q."+
						" Please run kube-inject with the argument `-i <istioSystemNamespace>`",
						namespace, istioNamespace)
				}

				meshConfig = istioMeshConfig
				_, err = inject.CreateMeshConfigMap(client, namespace, meshConfigMapName, istioMeshConfigMap)
				if err != nil {
					return fmt.Errorf("Cannot create Istio configuration map in namespace %s",
						namespace)
				}
			}

			config := &inject.Config{
				Policy:     inject.DefaultInjectionPolicy,
				Namespaces: []string{v1.NamespaceAll},
				Params: inject.Params{
					InitImage:         inject.InitImageName(hub, tag, debugMode),
					ProxyImage:        inject.ProxyImageName(hub, tag, debugMode),
					Verbosity:         verbosity,
					SidecarProxyUID:   sidecarProxyUID,
					Version:           versionStr,
					EnableCoreDump:    enableCoreDump,
					Mesh:              meshConfig,
					MeshConfigMapName: meshConfigMapName,
					ImagePullPolicy:   imagePullPolicy,
					IncludeIPRanges:   includeIPRanges,
					DebugMode:         debugMode,
				},
			}
			return inject.IntoResourceFile(config, reader, writer)
		},
	}
)

func init() {
	rootCmd.AddCommand(injectCmd)

	injectCmd.PersistentFlags().StringVar(&hub, "hub", inject.DefaultHub, "Docker hub")
	injectCmd.PersistentFlags().StringVar(&tag, "tag", version.Info.Version, "Docker tag")

	injectCmd.PersistentFlags().StringVarP(&inFilename, "filename", "f",
		"", "Input Kubernetes resource filename")
	injectCmd.PersistentFlags().StringVarP(&outFilename, "output", "o",
		"", "Modified output Kubernetes resource filename")
	injectCmd.PersistentFlags().IntVar(&verbosity, "verbosity",
		inject.DefaultVerbosity, "Runtime verbosity")
	injectCmd.PersistentFlags().Int64Var(&sidecarProxyUID, "sidecarProxyUID",
		inject.DefaultSidecarProxyUID, "Envoy sidecar UID")
	injectCmd.PersistentFlags().StringVar(&versionStr, "setVersionString",
		"", "Override version info injected into resource")
	injectCmd.PersistentFlags().StringVar(&meshConfigMapName, "meshConfigMapName", "istio",
		fmt.Sprintf("ConfigMap name for Istio mesh configuration, key should be %q", inject.ConfigMapKey))

	// Default --coreDump=true for pre-alpha development. Core dump
	// settings (i.e. sysctl kernel.*) affect all pods in a node and
	// require privileges. This option should only be used by the cluster
	// admin (see https://kubernetes.io/docs/concepts/cluster-administration/sysctl-cluster/)
	injectCmd.PersistentFlags().BoolVar(&enableCoreDump, "coreDump",
		true, "Enable/Disable core dumps in injected Envoy sidecar (--coreDump=true affects "+
			"all pods in a node and should only be used the cluster admin)")
	injectCmd.PersistentFlags().StringVar(&imagePullPolicy, "imagePullPolicy", inject.DefaultImagePullPolicy,
		"Sets the container image pull policy. Valid options are Always,IfNotPresent,Never."+
			"The default policy is IfNotPresent.")
	injectCmd.PersistentFlags().StringVar(&includeIPRanges, "includeIPRanges", "",
		"Comma separated list of IP ranges in CIDR form. If set, only redirect outbound "+
			"traffic to Envoy for IP ranges. Otherwise all outbound traffic is redirected")
	injectCmd.PersistentFlags().BoolVar(&debugMode, "debug", true, "Use debug images and settings for the sidecar")
}
<commit_msg>fix error handling in configmap handling (#1247)<commit_after>// Copyright 2017 Istio 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 main

import (
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"
	"k8s.io/api/core/v1"

	"istio.io/pilot/platform/kube"
	"istio.io/pilot/platform/kube/inject"
	"istio.io/pilot/tools/version"
)

var (
	hub               string
	tag               string
	sidecarProxyUID   int64
	verbosity         int
	versionStr        string // override build version
	enableCoreDump    bool
	meshConfigMapName string
	imagePullPolicy   string
	includeIPRanges   string
	debugMode         bool

	inFilename  string
	outFilename string
)

var (
	injectCmd = &cobra.Command{
		Use:   "kube-inject",
		Short: "Inject Envoy sidecar into Kubernetes pod resources",
		Long: `

Automatic Envoy sidecar injection via k8s admission controller is not
ready yet. Instead, use kube-inject to manually inject Envoy sidecar
into Kubernetes resource files. Unsupported resources are left
unmodified so it is safe to run kube-inject over a single file that
contains multiple Service, ConfigMap, Deployment, etc. definitions for
a complex application. Its best to do this when the resource is
initially created.

k8s.io/docs/concepts/workloads/pods/pod-overview/#pod-templates is
updated for Job, DaemonSet, ReplicaSet, and Deployment YAML resource
documents. Support for additional pod-based resource types can be
added as necessary.

The Istio project is continually evolving so the Istio sidecar
configuration may change unannounced. When in doubt re-run istioctl
kube-inject on deployments to get the most up-to-date changes.
`,
		Example: `
# Update resources on the fly before applying.
kubectl apply -f <(istioctl kube-inject -f <resource.yaml>)

# Create a persistent version of the deployment with Envoy sidecar
# injected. This is particularly useful to understand what is
# being injected before committing to Kubernetes API server.
istioctl kube-inject -f deployment.yaml -o deployment-with-istio.yaml

# Update an existing deployment.
kubectl get deployment -o yaml | istioctl kube-inject -f - | kubectl apply -f -
`,
		RunE: func(_ *cobra.Command, _ []string) (err error) {
			if inFilename == "" {
				return errors.New("filename not specified (see --filename or -f)")
			}

			var reader io.Reader
			if inFilename == "-" {
				reader = os.Stdin
			} else {
				if reader, err = os.Open(inFilename); err != nil {
					return err
				}
			}

			var writer io.Writer
			if outFilename == "" {
				writer = os.Stdout
			} else {
				var file *os.File
				if file, err = os.Create(outFilename); err != nil {
					return err
				}
				writer = file
				defer func() {
					// don't overwrite error if preceding injection failed
					errClose := file.Close()
					if err == nil {
						err = errClose
					}
				}()
			}

			if versionStr == "" {
				versionStr = version.Line()
			}

			_, client, err := kube.CreateInterface(kubeconfig)
			if err != nil {
				return err
			}

			_, meshConfig, err := inject.GetMeshConfig(client, namespace, meshConfigMapName)
			if err != nil {
				// Temporary hack (few days), until this is properly implemented
				// https://github.com/istio/pilot/issues/1153
				istioMeshConfigMap, istioMeshConfig, err := inject.GetMeshConfig(client,
					istioNamespace, meshConfigMapName)
				if err != nil {
					return fmt.Errorf("could not read valid configmap %q from namespace %q or %q: %v - "+
						"Re-run kube-inject with `-i <istioSystemNamespace> and ensure valid MeshConfig exists",
						meshConfigMapName, namespace, istioNamespace, err)
				}

				meshConfig = istioMeshConfig
				_, err = inject.CreateMeshConfigMap(client, namespace, meshConfigMapName, istioMeshConfigMap)
				if err != nil {
					return fmt.Errorf("cannot create Istio configuration map in namespace %s: %v",
						namespace, err)
				}
			}

			config := &inject.Config{
				Policy:     inject.DefaultInjectionPolicy,
				Namespaces: []string{v1.NamespaceAll},
				Params: inject.Params{
					InitImage:         inject.InitImageName(hub, tag, debugMode),
					ProxyImage:        inject.ProxyImageName(hub, tag, debugMode),
					Verbosity:         verbosity,
					SidecarProxyUID:   sidecarProxyUID,
					Version:           versionStr,
					EnableCoreDump:    enableCoreDump,
					Mesh:              meshConfig,
					MeshConfigMapName: meshConfigMapName,
					ImagePullPolicy:   imagePullPolicy,
					IncludeIPRanges:   includeIPRanges,
					DebugMode:         debugMode,
				},
			}
			return inject.IntoResourceFile(config, reader, writer)
		},
	}
)

func init() {
	rootCmd.AddCommand(injectCmd)

	injectCmd.PersistentFlags().StringVar(&hub, "hub", inject.DefaultHub, "Docker hub")
	injectCmd.PersistentFlags().StringVar(&tag, "tag", version.Info.Version, "Docker tag")

	injectCmd.PersistentFlags().StringVarP(&inFilename, "filename", "f",
		"", "Input Kubernetes resource filename")
	injectCmd.PersistentFlags().StringVarP(&outFilename, "output", "o",
		"", "Modified output Kubernetes resource filename")
	injectCmd.PersistentFlags().IntVar(&verbosity, "verbosity",
		inject.DefaultVerbosity, "Runtime verbosity")
	injectCmd.PersistentFlags().Int64Var(&sidecarProxyUID, "sidecarProxyUID",
		inject.DefaultSidecarProxyUID, "Envoy sidecar UID")
	injectCmd.PersistentFlags().StringVar(&versionStr, "setVersionString",
		"", "Override version info injected into resource")
	injectCmd.PersistentFlags().StringVar(&meshConfigMapName, "meshConfigMapName", "istio",
		fmt.Sprintf("ConfigMap name for Istio mesh configuration, key should be %q", inject.ConfigMapKey))

	// Default --coreDump=true for pre-alpha development. Core dump
	// settings (i.e. sysctl kernel.*) affect all pods in a node and
	// require privileges. This option should only be used by the cluster
	// admin (see https://kubernetes.io/docs/concepts/cluster-administration/sysctl-cluster/)
	injectCmd.PersistentFlags().BoolVar(&enableCoreDump, "coreDump",
		true, "Enable/Disable core dumps in injected Envoy sidecar (--coreDump=true affects "+
			"all pods in a node and should only be used the cluster admin)")
	injectCmd.PersistentFlags().StringVar(&imagePullPolicy, "imagePullPolicy", inject.DefaultImagePullPolicy,
		"Sets the container image pull policy. Valid options are Always,IfNotPresent,Never."+
			"The default policy is IfNotPresent.")
	injectCmd.PersistentFlags().StringVar(&includeIPRanges, "includeIPRanges", "",
		"Comma separated list of IP ranges in CIDR form. If set, only redirect outbound "+
			"traffic to Envoy for IP ranges. Otherwise all outbound traffic is redirected")
	injectCmd.PersistentFlags().BoolVar(&debugMode, "debug", true, "Use debug images and settings for the sidecar")
}
<|endoftext|>


<commit_before>package cluster

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/openshift/installer/data"
	"github.com/openshift/installer/pkg/asset"
	"github.com/openshift/installer/pkg/asset/installconfig"
	"github.com/openshift/installer/pkg/asset/kubeconfig"
	"github.com/openshift/installer/pkg/terraform"
	"github.com/openshift/installer/pkg/types"
)

const (
	// MetadataFilename is name of the file where clustermetadata is stored.
	MetadataFilename = "metadata.json"

	stateFileName = "terraform.state"
)

// Cluster uses the terraform executable to launch a cluster
// with the given terraform tfvar and generated templates.
type Cluster struct {
	FileList []*asset.File
}

var _ asset.WritableAsset = (*Cluster)(nil)

// Name returns the human-friendly name of the asset.
func (c *Cluster) Name() string {
	return "Cluster"
}

// Dependencies returns the direct dependency for launching
// the cluster.
func (c *Cluster) Dependencies() []asset.Asset {
	return []asset.Asset{
		&installconfig.InstallConfig{},
		&TerraformVariables{},
		&kubeconfig.Admin{},
	}
}

// Generate launches the cluster and generates the terraform state file on disk.
func (c *Cluster) Generate(parents asset.Parents) (err error) {
	installConfig := &installconfig.InstallConfig{}
	terraformVariables := &TerraformVariables{}
	adminKubeconfig := &kubeconfig.Admin{}
	parents.Get(installConfig, terraformVariables, adminKubeconfig)

	// Copy the terraform.tfvars to a temp directory where the terraform will be invoked within.
	tmpDir, err := ioutil.TempDir(os.TempDir(), "openshift-install-")
	if err != nil {
		return errors.Wrap(err, "failed to create temp dir for terraform execution")
	}
	defer os.RemoveAll(tmpDir)

	terraformVariablesFile := terraformVariables.Files()[0]
	if err := ioutil.WriteFile(filepath.Join(tmpDir, terraformVariablesFile.Filename), terraformVariablesFile.Data, 0600); err != nil {
		return errors.Wrap(err, "failed to write terraform.tfvars file")
	}

	platform := terraformVariables.Platform
	if err := data.Unpack(tmpDir, platform); err != nil {
		return err
	}

	metadata := &types.ClusterMetadata{
		ClusterName: installConfig.Config.ObjectMeta.Name,
	}

	defer func() {
		if data, err2 := json.Marshal(metadata); err2 == nil {
			c.FileList = append(c.FileList, &asset.File{
				Filename: MetadataFilename,
				Data:     data,
			})
		} else {
			err2 = errors.Wrap(err2, "failed to Marshal ClusterMetadata")
			if err == nil {
				err = err2
			} else {
				logrus.Error(err2)
			}
		}
		// serialize metadata and stuff it into c.FileList
	}()

	switch {
	case installConfig.Config.Platform.AWS != nil:
		metadata.ClusterPlatformMetadata.AWS = &types.ClusterAWSPlatformMetadata{
			Region: installConfig.Config.Platform.AWS.Region,
			Identifier: map[string]string{
				"tectonicClusterID": installConfig.Config.ClusterID,
			},
		}
	case installConfig.Config.Platform.OpenStack != nil:
		metadata.ClusterPlatformMetadata.OpenStack = &types.ClusterOpenStackPlatformMetadata{
			Region: installConfig.Config.Platform.OpenStack.Region,
			Identifier: map[string]string{
				"tectonicClusterID": installConfig.Config.ClusterID,
			},
		}
	case installConfig.Config.Platform.Libvirt != nil:
		metadata.ClusterPlatformMetadata.Libvirt = &types.ClusterLibvirtPlatformMetadata{
			URI: installConfig.Config.Platform.Libvirt.URI,
		}
	default:
		return fmt.Errorf("no known platform")
	}

	if err := data.Unpack(filepath.Join(tmpDir, "config.tf"), "config.tf"); err != nil {
		return err
	}

	logrus.Infof("Using Terraform to create cluster...")

	// This runs the terraform in a temp directory, the tfstate file will be returned
	// to the asset store to persist it on the disk.
	if err := terraform.Init(tmpDir); err != nil {
		return errors.Wrap(err, "failed to initialize terraform")
	}

	stateFile, err := terraform.Apply(tmpDir)
	if err != nil {
		err = errors.Wrap(err, "failed to run terraform")
	}

	data, err2 := ioutil.ReadFile(stateFile)
	if err2 == nil {
		c.FileList = append(c.FileList, &asset.File{
			Filename: stateFileName,
			Data:     data,
		})
	} else {
		if err == nil {
			err = err2
		} else {
			logrus.Errorf("Failed to read tfstate: %v", err2)
		}
	}

	// TODO(yifan): Use the kubeconfig to verify the cluster is up.
	return err
}

// Files returns the FileList generated by the asset.
func (c *Cluster) Files() []*asset.File {
	return c.FileList
}
<commit_msg>pkg/asset/cluster: Drop redundant os.TempDir()<commit_after>package cluster

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	"github.com/openshift/installer/data"
	"github.com/openshift/installer/pkg/asset"
	"github.com/openshift/installer/pkg/asset/installconfig"
	"github.com/openshift/installer/pkg/asset/kubeconfig"
	"github.com/openshift/installer/pkg/terraform"
	"github.com/openshift/installer/pkg/types"
)

const (
	// MetadataFilename is name of the file where clustermetadata is stored.
	MetadataFilename = "metadata.json"

	stateFileName = "terraform.state"
)

// Cluster uses the terraform executable to launch a cluster
// with the given terraform tfvar and generated templates.
type Cluster struct {
	FileList []*asset.File
}

var _ asset.WritableAsset = (*Cluster)(nil)

// Name returns the human-friendly name of the asset.
func (c *Cluster) Name() string {
	return "Cluster"
}

// Dependencies returns the direct dependency for launching
// the cluster.
func (c *Cluster) Dependencies() []asset.Asset {
	return []asset.Asset{
		&installconfig.InstallConfig{},
		&TerraformVariables{},
		&kubeconfig.Admin{},
	}
}

// Generate launches the cluster and generates the terraform state file on disk.
func (c *Cluster) Generate(parents asset.Parents) (err error) {
	installConfig := &installconfig.InstallConfig{}
	terraformVariables := &TerraformVariables{}
	adminKubeconfig := &kubeconfig.Admin{}
	parents.Get(installConfig, terraformVariables, adminKubeconfig)

	// Copy the terraform.tfvars to a temp directory where the terraform will be invoked within.
	tmpDir, err := ioutil.TempDir("", "openshift-install-")
	if err != nil {
		return errors.Wrap(err, "failed to create temp dir for terraform execution")
	}
	defer os.RemoveAll(tmpDir)

	terraformVariablesFile := terraformVariables.Files()[0]
	if err := ioutil.WriteFile(filepath.Join(tmpDir, terraformVariablesFile.Filename), terraformVariablesFile.Data, 0600); err != nil {
		return errors.Wrap(err, "failed to write terraform.tfvars file")
	}

	platform := terraformVariables.Platform
	if err := data.Unpack(tmpDir, platform); err != nil {
		return err
	}

	metadata := &types.ClusterMetadata{
		ClusterName: installConfig.Config.ObjectMeta.Name,
	}

	defer func() {
		if data, err2 := json.Marshal(metadata); err2 == nil {
			c.FileList = append(c.FileList, &asset.File{
				Filename: MetadataFilename,
				Data:     data,
			})
		} else {
			err2 = errors.Wrap(err2, "failed to Marshal ClusterMetadata")
			if err == nil {
				err = err2
			} else {
				logrus.Error(err2)
			}
		}
		// serialize metadata and stuff it into c.FileList
	}()

	switch {
	case installConfig.Config.Platform.AWS != nil:
		metadata.ClusterPlatformMetadata.AWS = &types.ClusterAWSPlatformMetadata{
			Region: installConfig.Config.Platform.AWS.Region,
			Identifier: map[string]string{
				"tectonicClusterID": installConfig.Config.ClusterID,
			},
		}
	case installConfig.Config.Platform.OpenStack != nil:
		metadata.ClusterPlatformMetadata.OpenStack = &types.ClusterOpenStackPlatformMetadata{
			Region: installConfig.Config.Platform.OpenStack.Region,
			Identifier: map[string]string{
				"tectonicClusterID": installConfig.Config.ClusterID,
			},
		}
	case installConfig.Config.Platform.Libvirt != nil:
		metadata.ClusterPlatformMetadata.Libvirt = &types.ClusterLibvirtPlatformMetadata{
			URI: installConfig.Config.Platform.Libvirt.URI,
		}
	default:
		return fmt.Errorf("no known platform")
	}

	if err := data.Unpack(filepath.Join(tmpDir, "config.tf"), "config.tf"); err != nil {
		return err
	}

	logrus.Infof("Using Terraform to create cluster...")

	// This runs the terraform in a temp directory, the tfstate file will be returned
	// to the asset store to persist it on the disk.
	if err := terraform.Init(tmpDir); err != nil {
		return errors.Wrap(err, "failed to initialize terraform")
	}

	stateFile, err := terraform.Apply(tmpDir)
	if err != nil {
		err = errors.Wrap(err, "failed to run terraform")
	}

	data, err2 := ioutil.ReadFile(stateFile)
	if err2 == nil {
		c.FileList = append(c.FileList, &asset.File{
			Filename: stateFileName,
			Data:     data,
		})
	} else {
		if err == nil {
			err = err2
		} else {
			logrus.Errorf("Failed to read tfstate: %v", err2)
		}
	}

	// TODO(yifan): Use the kubeconfig to verify the cluster is up.
	return err
}

// Files returns the FileList generated by the asset.
func (c *Cluster) Files() []*asset.File {
	return c.FileList
}
<|endoftext|>


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

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

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

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

package prober

import (
	"fmt"
	"strconv"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
	kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
	execprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/exec"
	httprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/http"
	tcprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/tcp"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"

	"github.com/golang/glog"
)

const maxProbeRetries = 3

// Prober checks the healthiness of a container.
type Prober interface {
	Probe(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, error)
}

// Prober helps to check the liveness/readiness of a container.
type prober struct {
	exec   execprobe.ExecProber
	http   httprobe.HTTPProber
	tcp    tcprobe.TCPProber
	runner kubecontainer.ContainerCommandRunner

	readinessManager *kubecontainer.ReadinessManager
	refManager       *kubecontainer.RefManager
	recorder         record.EventRecorder
}

// NewProber creates a Prober, it takes a command runner and
// several container info managers.
func New(
	runner kubecontainer.ContainerCommandRunner,
	readinessManager *kubecontainer.ReadinessManager,
	refManager *kubecontainer.RefManager,
	recorder record.EventRecorder) Prober {

	return &prober{
		exec:   execprobe.New(),
		http:   httprobe.New(),
		tcp:    tcprobe.New(),
		runner: runner,

		readinessManager: readinessManager,
		refManager:       refManager,
		recorder:         recorder,
	}
}

// New prober for use in tests.
func NewTestProber(
	exec execprobe.ExecProber,
	readinessManager *kubecontainer.ReadinessManager,
	refManager *kubecontainer.RefManager,
	recorder record.EventRecorder) Prober {

	return &prober{
		exec:             exec,
		readinessManager: readinessManager,
		refManager:       refManager,
		recorder:         recorder,
	}
}

// Probe checks the liveness/readiness of the given container.
// If the container's liveness probe is unsuccessful, set readiness to false.
// If liveness is successful, do a readiness check and set readiness accordingly.
func (pb *prober) Probe(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, error) {
	// Build a name string for logs.
	ctrName := fmt.Sprintf("%s:%s", kubecontainer.GetPodFullName(pod), container.Name)

	// Probe liveness.
	if container.LivenessProbe != nil {
		live, output, err := pb.probeLiveness(pod, status, container, containerID, createdAt)
		if err != nil || live != probe.Success {
			// Liveness failed in one way or another.
			pb.readinessManager.SetReadiness(containerID, false)
			ref, ok := pb.refManager.GetRef(containerID)
			if !ok {
				glog.Warningf("No ref for pod %q - '%v'", containerID, container.Name)
			}
			if err != nil {
				glog.V(1).Infof("Liveness probe for %q errored: %v", ctrName, err)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Liveness probe errored: %v", err)
				}
				return probe.Unknown, err
			} else { // live != probe.Success
				glog.V(1).Infof("Liveness probe for %q failed (%v): %s", ctrName, live, output)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Liveness probe failed: %s", output)
				}
				return live, nil
			}
		}
		glog.V(3).Infof("Liveness probe for %q succeeded", ctrName)
	}

	// Probe readiness.
	if container.ReadinessProbe != nil {
		ready, output, err := pb.probeReadiness(pod, status, container, containerID, createdAt)
		if err != nil || ready != probe.Success {
			// Readiness failed in one way or another.
			pb.readinessManager.SetReadiness(containerID, false)
			ref, ok := pb.refManager.GetRef(containerID)
			if !ok {
				glog.Warningf("No ref for pod '%v' - '%v'", containerID, container.Name)
			}
			if err != nil {
				glog.V(1).Infof("readiness probe for %q errored: %v", ctrName, err)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Readiness probe errored: %v", err)
				}
				return probe.Unknown, err
			} else { // ready != probe.Success
				glog.V(1).Infof("Readiness probe for %q failed (%v): %s", ctrName, ready, output)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Readiness probe failed: %s", output)
				}
				return ready, nil
			}
		}
		glog.V(1).Infof("Readiness probe for %q succeeded", ctrName)
	}

	pb.readinessManager.SetReadiness(containerID, true)
	return probe.Success, nil
}

// probeLiveness probes the liveness of a container.
// If the initalDelay since container creation on liveness probe has not passed the probe will return probe.Success.
func (pb *prober) probeLiveness(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, string, error) {
	p := container.LivenessProbe
	if p == nil {
		return probe.Success, "", nil
	}
	if time.Now().Unix()-createdAt < p.InitialDelaySeconds {
		return probe.Success, "", nil
	}
	return pb.runProbeWithRetries(p, pod, status, container, containerID, maxProbeRetries)
}

// probeReadiness probes the readiness of a container.
// If the initial delay on the readiness probe has not passed the probe will return probe.Failure.
func (pb *prober) probeReadiness(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, string, error) {
	p := container.ReadinessProbe
	if p == nil {
		return probe.Success, "", nil
	}
	if time.Now().Unix()-createdAt < p.InitialDelaySeconds {
		return probe.Failure, "", nil
	}
	return pb.runProbeWithRetries(p, pod, status, container, containerID, maxProbeRetries)
}

// runProbeWithRetries tries to probe the container in a finite loop, it returns the last result
// if it never succeeds.
func (pb *prober) runProbeWithRetries(p *api.Probe, pod *api.Pod, status api.PodStatus, container api.Container, containerID string, retries int) (probe.Result, string, error) {
	var err error
	var result probe.Result
	var output string
	for i := 0; i < retries; i++ {
		result, output, err = pb.runProbe(p, pod, status, container, containerID)
		if result == probe.Success {
			return probe.Success, output, nil
		}
	}
	return result, output, err
}

func (pb *prober) runProbe(p *api.Probe, pod *api.Pod, status api.PodStatus, container api.Container, containerID string) (probe.Result, string, error) {
	timeout := time.Duration(p.TimeoutSeconds) * time.Second
	if p.Exec != nil {
		glog.V(4).Infof("Exec-Probe Pod: %v, Container: %v, Command: %v", pod, container, p.Exec.Command)
		return pb.exec.Probe(pb.newExecInContainer(pod, container, containerID, p.Exec.Command))
	}
	if p.HTTPGet != nil {
		port, err := extractPort(p.HTTPGet.Port, container)
		if err != nil {
			return probe.Unknown, "", err
		}
		host, port, path := extractGetParams(p.HTTPGet, status, port)
		glog.V(4).Infof("HTTP-Probe Host: %v, Port: %v, Path: %v", host, port, path)
		return pb.http.Probe(host, port, path, timeout)
	}
	if p.TCPSocket != nil {
		port, err := extractPort(p.TCPSocket.Port, container)
		if err != nil {
			return probe.Unknown, "", err
		}
		glog.V(4).Infof("TCP-Probe PodIP: %v, Port: %v, Timeout: %v", status.PodIP, port, timeout)
		return pb.tcp.Probe(status.PodIP, port, timeout)
	}
	glog.Warningf("Failed to find probe builder for container: %v", container)
	return probe.Unknown, "", nil
}

func extractGetParams(action *api.HTTPGetAction, status api.PodStatus, port int) (string, int, string) {
	host := action.Host
	if host == "" {
		host = status.PodIP
	}
	return host, port, action.Path
}

func extractPort(param util.IntOrString, container api.Container) (int, error) {
	port := -1
	var err error
	switch param.Kind {
	case util.IntstrInt:
		port := param.IntVal
		if port > 0 && port < 65536 {
			return port, nil
		}
		return port, fmt.Errorf("invalid port number: %v", port)
	case util.IntstrString:
		port = findPortByName(container, param.StrVal)
		if port == -1 {
			// Last ditch effort - maybe it was an int stored as string?
			if port, err = strconv.Atoi(param.StrVal); err != nil {
				return port, err
			}
		}
		if port > 0 && port < 65536 {
			return port, nil
		}
		return port, fmt.Errorf("invalid port number: %v", port)
	default:
		return port, fmt.Errorf("IntOrString had no kind: %+v", param)
	}
}

// findPortByName is a helper function to look up a port in a container by name.
// Returns the HostPort if found, -1 if not found.
func findPortByName(container api.Container, portName string) int {
	for _, port := range container.Ports {
		if port.Name == portName {
			return port.HostPort
		}
	}
	return -1
}

type execInContainer struct {
	run func() ([]byte, error)
}

func (p *prober) newExecInContainer(pod *api.Pod, container api.Container, containerID string, cmd []string) exec.Cmd {
	return execInContainer{func() ([]byte, error) {
		return p.runner.RunInContainer(containerID, cmd)
	}}
}

func (eic execInContainer) CombinedOutput() ([]byte, error) {
	return eic.run()
}

func (eic execInContainer) SetDir(dir string) {
	//unimplemented
}
<commit_msg>reduce verbosity of log line<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

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

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

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

package prober

import (
	"fmt"
	"strconv"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
	kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
	execprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/exec"
	httprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/http"
	tcprobe "github.com/GoogleCloudPlatform/kubernetes/pkg/probe/tcp"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"

	"github.com/golang/glog"
)

const maxProbeRetries = 3

// Prober checks the healthiness of a container.
type Prober interface {
	Probe(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, error)
}

// Prober helps to check the liveness/readiness of a container.
type prober struct {
	exec   execprobe.ExecProber
	http   httprobe.HTTPProber
	tcp    tcprobe.TCPProber
	runner kubecontainer.ContainerCommandRunner

	readinessManager *kubecontainer.ReadinessManager
	refManager       *kubecontainer.RefManager
	recorder         record.EventRecorder
}

// NewProber creates a Prober, it takes a command runner and
// several container info managers.
func New(
	runner kubecontainer.ContainerCommandRunner,
	readinessManager *kubecontainer.ReadinessManager,
	refManager *kubecontainer.RefManager,
	recorder record.EventRecorder) Prober {

	return &prober{
		exec:   execprobe.New(),
		http:   httprobe.New(),
		tcp:    tcprobe.New(),
		runner: runner,

		readinessManager: readinessManager,
		refManager:       refManager,
		recorder:         recorder,
	}
}

// New prober for use in tests.
func NewTestProber(
	exec execprobe.ExecProber,
	readinessManager *kubecontainer.ReadinessManager,
	refManager *kubecontainer.RefManager,
	recorder record.EventRecorder) Prober {

	return &prober{
		exec:             exec,
		readinessManager: readinessManager,
		refManager:       refManager,
		recorder:         recorder,
	}
}

// Probe checks the liveness/readiness of the given container.
// If the container's liveness probe is unsuccessful, set readiness to false.
// If liveness is successful, do a readiness check and set readiness accordingly.
func (pb *prober) Probe(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, error) {
	// Build a name string for logs.
	ctrName := fmt.Sprintf("%s:%s", kubecontainer.GetPodFullName(pod), container.Name)

	// Probe liveness.
	if container.LivenessProbe != nil {
		live, output, err := pb.probeLiveness(pod, status, container, containerID, createdAt)
		if err != nil || live != probe.Success {
			// Liveness failed in one way or another.
			pb.readinessManager.SetReadiness(containerID, false)
			ref, ok := pb.refManager.GetRef(containerID)
			if !ok {
				glog.Warningf("No ref for pod %q - '%v'", containerID, container.Name)
			}
			if err != nil {
				glog.V(1).Infof("Liveness probe for %q errored: %v", ctrName, err)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Liveness probe errored: %v", err)
				}
				return probe.Unknown, err
			} else { // live != probe.Success
				glog.V(1).Infof("Liveness probe for %q failed (%v): %s", ctrName, live, output)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Liveness probe failed: %s", output)
				}
				return live, nil
			}
		}
		glog.V(3).Infof("Liveness probe for %q succeeded", ctrName)
	}

	// Probe readiness.
	if container.ReadinessProbe != nil {
		ready, output, err := pb.probeReadiness(pod, status, container, containerID, createdAt)
		if err != nil || ready != probe.Success {
			// Readiness failed in one way or another.
			pb.readinessManager.SetReadiness(containerID, false)
			ref, ok := pb.refManager.GetRef(containerID)
			if !ok {
				glog.Warningf("No ref for pod '%v' - '%v'", containerID, container.Name)
			}
			if err != nil {
				glog.V(1).Infof("readiness probe for %q errored: %v", ctrName, err)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Readiness probe errored: %v", err)
				}
				return probe.Unknown, err
			} else { // ready != probe.Success
				glog.V(1).Infof("Readiness probe for %q failed (%v): %s", ctrName, ready, output)
				if ok {
					pb.recorder.Eventf(ref, "unhealthy", "Readiness probe failed: %s", output)
				}
				return ready, nil
			}
		}
		glog.V(3).Infof("Readiness probe for %q succeeded", ctrName)
	}

	pb.readinessManager.SetReadiness(containerID, true)
	return probe.Success, nil
}

// probeLiveness probes the liveness of a container.
// If the initalDelay since container creation on liveness probe has not passed the probe will return probe.Success.
func (pb *prober) probeLiveness(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, string, error) {
	p := container.LivenessProbe
	if p == nil {
		return probe.Success, "", nil
	}
	if time.Now().Unix()-createdAt < p.InitialDelaySeconds {
		return probe.Success, "", nil
	}
	return pb.runProbeWithRetries(p, pod, status, container, containerID, maxProbeRetries)
}

// probeReadiness probes the readiness of a container.
// If the initial delay on the readiness probe has not passed the probe will return probe.Failure.
func (pb *prober) probeReadiness(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, string, error) {
	p := container.ReadinessProbe
	if p == nil {
		return probe.Success, "", nil
	}
	if time.Now().Unix()-createdAt < p.InitialDelaySeconds {
		return probe.Failure, "", nil
	}
	return pb.runProbeWithRetries(p, pod, status, container, containerID, maxProbeRetries)
}

// runProbeWithRetries tries to probe the container in a finite loop, it returns the last result
// if it never succeeds.
func (pb *prober) runProbeWithRetries(p *api.Probe, pod *api.Pod, status api.PodStatus, container api.Container, containerID string, retries int) (probe.Result, string, error) {
	var err error
	var result probe.Result
	var output string
	for i := 0; i < retries; i++ {
		result, output, err = pb.runProbe(p, pod, status, container, containerID)
		if result == probe.Success {
			return probe.Success, output, nil
		}
	}
	return result, output, err
}

func (pb *prober) runProbe(p *api.Probe, pod *api.Pod, status api.PodStatus, container api.Container, containerID string) (probe.Result, string, error) {
	timeout := time.Duration(p.TimeoutSeconds) * time.Second
	if p.Exec != nil {
		glog.V(4).Infof("Exec-Probe Pod: %v, Container: %v, Command: %v", pod, container, p.Exec.Command)
		return pb.exec.Probe(pb.newExecInContainer(pod, container, containerID, p.Exec.Command))
	}
	if p.HTTPGet != nil {
		port, err := extractPort(p.HTTPGet.Port, container)
		if err != nil {
			return probe.Unknown, "", err
		}
		host, port, path := extractGetParams(p.HTTPGet, status, port)
		glog.V(4).Infof("HTTP-Probe Host: %v, Port: %v, Path: %v", host, port, path)
		return pb.http.Probe(host, port, path, timeout)
	}
	if p.TCPSocket != nil {
		port, err := extractPort(p.TCPSocket.Port, container)
		if err != nil {
			return probe.Unknown, "", err
		}
		glog.V(4).Infof("TCP-Probe PodIP: %v, Port: %v, Timeout: %v", status.PodIP, port, timeout)
		return pb.tcp.Probe(status.PodIP, port, timeout)
	}
	glog.Warningf("Failed to find probe builder for container: %v", container)
	return probe.Unknown, "", nil
}

func extractGetParams(action *api.HTTPGetAction, status api.PodStatus, port int) (string, int, string) {
	host := action.Host
	if host == "" {
		host = status.PodIP
	}
	return host, port, action.Path
}

func extractPort(param util.IntOrString, container api.Container) (int, error) {
	port := -1
	var err error
	switch param.Kind {
	case util.IntstrInt:
		port := param.IntVal
		if port > 0 && port < 65536 {
			return port, nil
		}
		return port, fmt.Errorf("invalid port number: %v", port)
	case util.IntstrString:
		port = findPortByName(container, param.StrVal)
		if port == -1 {
			// Last ditch effort - maybe it was an int stored as string?
			if port, err = strconv.Atoi(param.StrVal); err != nil {
				return port, err
			}
		}
		if port > 0 && port < 65536 {
			return port, nil
		}
		return port, fmt.Errorf("invalid port number: %v", port)
	default:
		return port, fmt.Errorf("IntOrString had no kind: %+v", param)
	}
}

// findPortByName is a helper function to look up a port in a container by name.
// Returns the HostPort if found, -1 if not found.
func findPortByName(container api.Container, portName string) int {
	for _, port := range container.Ports {
		if port.Name == portName {
			return port.HostPort
		}
	}
	return -1
}

type execInContainer struct {
	run func() ([]byte, error)
}

func (p *prober) newExecInContainer(pod *api.Pod, container api.Container, containerID string, cmd []string) exec.Cmd {
	return execInContainer{func() ([]byte, error) {
		return p.runner.RunInContainer(containerID, cmd)
	}}
}

func (eic execInContainer) CombinedOutput() ([]byte, error) {
	return eic.run()
}

func (eic execInContainer) SetDir(dir string) {
	//unimplemented
}
<|endoftext|>


<commit_before>/*
Copyright 2016-2017 Mirantis

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 libvirttools

import (
	"fmt"
	"strings"

	"github.com/golang/glog"
	libvirtxml "github.com/libvirt/libvirt-go-xml"

	"github.com/Mirantis/virtlet/pkg/virt"
)

type diskItem struct {
	driver diskDriver
	volume VMVolume
}

func (di *diskItem) setup(config *VMConfig) (*libvirtxml.DomainDisk, error) {
	diskDef, err := di.volume.Setup()
	if err != nil {
		return nil, err
	}
	diskDef.Target = di.driver.target()
	diskDef.Address = di.driver.address()
	return diskDef, nil
}

type diskList struct {
	config *VMConfig
	items  []*diskItem
}

// newDiskSet creates a diskList for the specified VMConfig, volume
// source and volume owner
func newDiskList(config *VMConfig, source VMVolumeSource, owner VolumeOwner) (*diskList, error) {
	vmVols, err := source(config, owner)
	if err != nil {
		return nil, err
	}

	diskDriverFactory, err := getDiskDriverFactory(config.ParsedAnnotations.DiskDriver)
	if err != nil {
		return nil, err
	}
	var items []*diskItem
	for n, volume := range vmVols {
		driver, err := diskDriverFactory(n)
		if err != nil {
			return nil, err
		}
		items = append(items, &diskItem{driver, volume})
	}

	return &diskList{config, items}, nil
}

// setupVolumes performs the setup procedure on each volume in the
// diskList and returns a list of libvirtxml DomainDisk structs
func (dl *diskList) setup() ([]libvirtxml.DomainDisk, error) {
	var domainDisks []libvirtxml.DomainDisk
	for n, item := range dl.items {
		diskDef, err := item.setup(dl.config)
		if err != nil {
			// try to tear down volumes that were already set up
			for _, item := range dl.items[:n] {
				if err := item.volume.Teardown(); err != nil {
					glog.Warningf("Failed to tear down a volume on error: %v", err)
				}
			}
			return nil, err
		}
		domainDisks = append(domainDisks, *diskDef)
	}
	return domainDisks, nil
}

// writeVolumeImages writes images for volumes that are based on
// generated images (such as cloud-init nocloud datasource).  It must
// be passed a VirtDomain for which images are being generated.
func (dl *diskList) writeImages(domain virt.VirtDomain) error {
	domainDesc, err := domain.Xml()
	if err != nil {
		return fmt.Errorf("couldn't get domain xml: %v", err)
	}

	volumeMap := make(diskPathMap)
	for _, item := range dl.items {
		uuid := item.volume.Uuid()
		if uuid != "" {
			diskPath, err := item.driver.diskPath(domainDesc)
			if err != nil {
				return err
			}
			volumeMap[uuid] = *diskPath
		}
	}

	for _, item := range dl.items {
		if err := item.volume.WriteImage(volumeMap); err != nil {
			return err
		}
	}

	return nil
}

func (dl *diskList) teardown() error {
	var errs []string
	for _, item := range dl.items {
		if err := item.volume.Teardown(); err != nil {
			errs = append(errs, err.Error())
		}
	}
	if errs != nil {
		return fmt.Errorf("failed to tear down some of the volumes:\n%s", strings.Join(errs, "\n"))
	}
	return nil
}
<commit_msg>Fix comments in disklist<commit_after>/*
Copyright 2016-2017 Mirantis

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 libvirttools

import (
	"fmt"
	"strings"

	"github.com/golang/glog"
	libvirtxml "github.com/libvirt/libvirt-go-xml"

	"github.com/Mirantis/virtlet/pkg/virt"
)

type diskItem struct {
	driver diskDriver
	volume VMVolume
}

func (di *diskItem) setup(config *VMConfig) (*libvirtxml.DomainDisk, error) {
	diskDef, err := di.volume.Setup()
	if err != nil {
		return nil, err
	}
	diskDef.Target = di.driver.target()
	diskDef.Address = di.driver.address()
	return diskDef, nil
}

type diskList struct {
	config *VMConfig
	items  []*diskItem
}

// newDiskList creates a diskList for the specified VMConfig, volume
// source and volume owner
func newDiskList(config *VMConfig, source VMVolumeSource, owner VolumeOwner) (*diskList, error) {
	vmVols, err := source(config, owner)
	if err != nil {
		return nil, err
	}

	diskDriverFactory, err := getDiskDriverFactory(config.ParsedAnnotations.DiskDriver)
	if err != nil {
		return nil, err
	}
	var items []*diskItem
	for n, volume := range vmVols {
		driver, err := diskDriverFactory(n)
		if err != nil {
			return nil, err
		}
		items = append(items, &diskItem{driver, volume})
	}

	return &diskList{config, items}, nil
}

// setup performs the setup procedure on each volume in the diskList
// and returns a list of libvirtxml DomainDisk structs
func (dl *diskList) setup() ([]libvirtxml.DomainDisk, error) {
	var domainDisks []libvirtxml.DomainDisk
	for n, item := range dl.items {
		diskDef, err := item.setup(dl.config)
		if err != nil {
			// try to tear down volumes that were already set up
			for _, item := range dl.items[:n] {
				if err := item.volume.Teardown(); err != nil {
					glog.Warningf("Failed to tear down a volume on error: %v", err)
				}
			}
			return nil, err
		}
		domainDisks = append(domainDisks, *diskDef)
	}
	return domainDisks, nil
}

// writeImages writes images for volumes that are based on generated
// images (such as cloud-init nocloud datasource).  It must be passed
// a VirtDomain for which images are being generated.
func (dl *diskList) writeImages(domain virt.VirtDomain) error {
	domainDesc, err := domain.Xml()
	if err != nil {
		return fmt.Errorf("couldn't get domain xml: %v", err)
	}

	volumeMap := make(diskPathMap)
	for _, item := range dl.items {
		uuid := item.volume.Uuid()
		if uuid != "" {
			diskPath, err := item.driver.diskPath(domainDesc)
			if err != nil {
				return err
			}
			volumeMap[uuid] = *diskPath
		}
	}

	for _, item := range dl.items {
		if err := item.volume.WriteImage(volumeMap); err != nil {
			return err
		}
	}

	return nil
}

func (dl *diskList) teardown() error {
	var errs []string
	for _, item := range dl.items {
		if err := item.volume.Teardown(); err != nil {
			errs = append(errs, err.Error())
		}
	}
	if errs != nil {
		return fmt.Errorf("failed to tear down some of the volumes:\n%s", strings.Join(errs, "\n"))
	}
	return nil
}
<|endoftext|>


<commit_before>package mount

/*
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/_iovec.h>
#include <sys/mount.h>
#include <sys/param.h>
*/
import "C"

import (
	"fmt"
	"strings"
	"unsafe"
)

func allocateIOVecs(options []string) []C.struct_iovec {
	out := make([]C.struct_iovec, len(options))
	for i, option := range options {
		out[i].iov_base = unsafe.Pointer(C.CString(option))
		out[i].iov_len = C.size_t(len(option) + 1)
	}
	return out
}

func mount(device, target, mType string, flag uintptr, data string) error {
	isNullFS := false

	xs := strings.Split(data, ",")
	for _, x := range xs {
		if x == "bind" {
			isNullFS = true
		}
	}

	options := []string{"fspath", target}
	if isNullFS {
		options = append(options, "fstype", "nullfs", "target", device)
	} else {
		options = append(options, "fstype", mType, "from", device)
	}
	rawOptions := allocateIOVecs(options)
	for _, rawOption := range rawOptions {
		defer C.free(rawOption.iov_base)
	}

	if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 {
		reason := C.GoString(C.strerror(*C.__error()))
		return fmt.Errorf("Failed to call nmount: %s", reason)
	}
	return nil
}
<commit_msg>Parse key=value pairs from data and pass through to nmount<commit_after>package mount

/*
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/_iovec.h>
#include <sys/mount.h>
#include <sys/param.h>
*/
import "C"

import (
	"fmt"
	"strings"
	"unsafe"
)

func allocateIOVecs(options []string) []C.struct_iovec {
	out := make([]C.struct_iovec, len(options))
	for i, option := range options {
		out[i].iov_base = unsafe.Pointer(C.CString(option))
		out[i].iov_len = C.size_t(len(option) + 1)
	}
	return out
}

func mount(device, target, mType string, flag uintptr, data string) error {
	isNullFS := false

	options := []string{"fspath", target}

	if data != "" {
		xs := strings.Split(data, ",")
		for _, x := range xs {
			if x == "bind" {
				isNullFS = true
				continue
			}
			opt := strings.SplitN(x, "=", 2)
			options = append(options, opt[0])
			if len(opt) == 2 {
				options = append(options, opt[1])
			} else {
				options = append(options, "")
			}
		}
	}

	if isNullFS {
		options = append(options, "fstype", "nullfs", "target", device)
	} else {
		options = append(options, "fstype", mType, "from", device)
	}
	rawOptions := allocateIOVecs(options)
	for _, rawOption := range rawOptions {
		defer C.free(rawOption.iov_base)
	}

	if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 {
		reason := C.GoString(C.strerror(*C.__error()))
		return fmt.Errorf("Failed to call nmount: %s", reason)
	}
	return nil
}
<|endoftext|>


<commit_before>/*******************************************************************************
*
* Copyright 2022 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
	"github.com/gophercloud/gophercloud/pagination"
)

//Like `nodes.ListDetail(client, nil)`, but works around <https://github.com/gophercloud/gophercloud/issues/2431>.
func ironicNodesListDetail(client *gophercloud.ServiceClient) pagination.Pager {
	url := client.ServiceURL("nodes", "detail")
	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
		return ironicNodePage{nodes.NodePage{pagination.LinkedPageBase{PageResult: r}}}
	})
}

//Like `nodes.ExtractNodesInto()`, but casts into the correct pagination.Page type.
func ironicExtractNodesInto(r pagination.Page, v interface{}) error {
	return r.(ironicNodePage).Result.ExtractIntoSlicePtr(v, "nodes")
}

type ironicNodePage struct {
	nodes.NodePage
}

//
// NextPageURL uses the response's embedded link reference to navigate to the
// next page of results.
func (r ironicNodePage) NextPageURL() (string, error) {
	var s struct {
		Next string `json:"next"`
	}
	err := r.ExtractInto(&s)
	if err != nil {
		return "", err
	}
	if s.Next != "" {
		return s.Next, nil
	}
	//fallback
	return r.NodePage.NextPageURL()
}
<commit_msg>fix govet<commit_after>/*******************************************************************************
*
* Copyright 2022 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
	"github.com/gophercloud/gophercloud/pagination"
)

//Like `nodes.ListDetail(client, nil)`, but works around <https://github.com/gophercloud/gophercloud/issues/2431>.
func ironicNodesListDetail(client *gophercloud.ServiceClient) pagination.Pager {
	url := client.ServiceURL("nodes", "detail")
	return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
		return ironicNodePage{nodes.NodePage{LinkedPageBase: pagination.LinkedPageBase{PageResult: r}}}
	})
}

//Like `nodes.ExtractNodesInto()`, but casts into the correct pagination.Page type.
func ironicExtractNodesInto(r pagination.Page, v interface{}) error {
	return r.(ironicNodePage).Result.ExtractIntoSlicePtr(v, "nodes")
}

type ironicNodePage struct {
	nodes.NodePage
}

//
// NextPageURL uses the response's embedded link reference to navigate to the
// next page of results.
func (r ironicNodePage) NextPageURL() (string, error) {
	var s struct {
		Next string `json:"next"`
	}
	err := r.ExtractInto(&s)
	if err != nil {
		return "", err
	}
	if s.Next != "" {
		return s.Next, nil
	}
	//fallback
	return r.NodePage.NextPageURL()
}
<|endoftext|>


<commit_before>// Copyright 2016 The Cockroach 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.
//
// Author: Radu Berinde (radu@cockroachlabs.com)

package distsqlrun

import (
	"io"

	"golang.org/x/net/context"

	"github.com/cockroachdb/cockroach/pkg/internal/client"
	"github.com/cockroachdb/cockroach/pkg/roachpb"
	"github.com/cockroachdb/cockroach/pkg/rpc"
	"github.com/cockroachdb/cockroach/pkg/sql/parser"
	"github.com/cockroachdb/cockroach/pkg/util/log"
	"github.com/cockroachdb/cockroach/pkg/util/stop"
	"github.com/cockroachdb/cockroach/pkg/util/tracing"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
)

// ServerConfig encompasses the configuration required to create a
// DistSQLServer.
type ServerConfig struct {
	log.AmbientContext

	DB           *client.DB
	RPCContext   *rpc.Context
	Stopper      *stop.Stopper
	TestingKnobs TestingKnobs
}

// ServerImpl implements the server for the distributed SQL APIs.
type ServerImpl struct {
	ServerConfig
	evalCtx       parser.EvalContext
	flowRegistry  *flowRegistry
	flowScheduler *flowScheduler
}

var _ DistSQLServer = &ServerImpl{}

// NewServer instantiates a DistSQLServer.
func NewServer(cfg ServerConfig) *ServerImpl {
	ds := &ServerImpl{
		ServerConfig: cfg,
		evalCtx: parser.EvalContext{
			ReCache: parser.NewRegexpCache(512),
		},
		flowRegistry:  makeFlowRegistry(),
		flowScheduler: newFlowScheduler(cfg.AmbientContext, cfg.Stopper),
	}
	return ds
}

// Start launches workers for the server.
func (ds *ServerImpl) Start() {
	ds.flowScheduler.Start()
}

// Note: unless an error is returned, the returned context contains a span that
// must be finished through Flow.Cleanup.
func (ds *ServerImpl) setupFlow(
	ctx context.Context, req *SetupFlowRequest, syncFlowConsumer RowReceiver,
) (context.Context, *Flow, error) {
	const opName = "flow"
	var sp opentracing.Span
	if req.TraceContext == nil {
		sp = ds.Tracer.StartSpan(opName)
		ctx = opentracing.ContextWithSpan(ctx, sp)
	} else {
		var err error
		// TODO(andrei): in the following call we're ignoring the returned
		// recordedTrace. Figure out how to return the recording to the remote
		// caller after the flow is done.
		ctx, _, err = tracing.JoinRemoteTrace(ctx, ds.Tracer, req.TraceContext, opName)
		if err != nil {
			sp = ds.Tracer.StartSpan(opName)
			ctx = opentracing.ContextWithSpan(ctx, sp)
			log.Warningf(ctx, "failed to join a remote trace: %s", err)
		}
	}

	// TODO(radu): we should sanity check some of these fields (especially
	// txnProto).
	flowCtx := FlowCtx{
		AmbientContext: ds.AmbientContext,
		id:             req.Flow.FlowID,
		// TODO(andrei): more fields from evalCtx need to be initialized (#13821).
		evalCtx:      ds.evalCtx,
		rpcCtx:       ds.RPCContext,
		txnProto:     &req.Txn,
		clientDB:     ds.DB,
		testingKnobs: ds.TestingKnobs,
	}
	ctx = flowCtx.AnnotateCtx(ctx)
	flowCtx.evalCtx.Ctx = func() context.Context {
		// TODO(andrei): This is wrong. Each processor should override Ctx with its
		// own context.
		return ctx
	}

	f := newFlow(flowCtx, ds.flowRegistry, syncFlowConsumer)
	flowCtx.AddLogTagStr("f", f.id.Short())
	if err := f.setupFlow(ctx, &req.Flow); err != nil {
		log.Errorf(ctx, "error setting up flow: %s", err)
		sp.Finish()
		ctx = opentracing.ContextWithSpan(ctx, nil)
		return ctx, nil, err
	}
	return ctx, f, nil
}

// SetupSyncFlow sets up a synchoronous flow, connecting the sync response
// output stream to the given RowReceiver. The flow is not started. The flow
// will be associated with the given context.
// Note: the returned context contains a span that must be finished through
// Flow.Cleanup.
func (ds *ServerImpl) SetupSyncFlow(
	ctx context.Context, req *SetupFlowRequest, output RowReceiver,
) (context.Context, *Flow, error) {
	return ds.setupFlow(ds.AnnotateCtx(ctx), req, output)
}

// RunSyncFlow is part of the DistSQLServer interface.
func (ds *ServerImpl) RunSyncFlow(stream DistSQL_RunSyncFlowServer) error {
	// Set up the outgoing mailbox for the stream.
	mbox := newOutboxSyncFlowStream(stream)

	firstMsg, err := stream.Recv()
	if err != nil {
		return err
	}
	if firstMsg.SetupFlowRequest == nil {
		return errors.Errorf("first message in RunSyncFlow doesn't contain SetupFlowRequest")
	}
	req := firstMsg.SetupFlowRequest
	ctx, f, err := ds.SetupSyncFlow(stream.Context(), req, mbox)
	if err != nil {
		return err
	}
	mbox.setFlowCtx(&f.FlowCtx)

	if err := ds.Stopper.RunTask(func() {
		f.waitGroup.Add(1)
		mbox.start(ctx, &f.waitGroup)
		f.Start(ctx, func() {})
		f.Wait()
		f.Cleanup(ctx)
	}); err != nil {
		return err
	}
	return mbox.err
}

// SetupFlow is part of the DistSQLServer interface.
func (ds *ServerImpl) SetupFlow(_ context.Context, req *SetupFlowRequest) (*SimpleResponse, error) {
	// Note: the passed context will be canceled when this RPC completes, so we
	// can't associate it with the flow.
	ctx := ds.AnnotateCtx(context.TODO())
	ctx, f, err := ds.setupFlow(ctx, req, nil)
	if err != nil {
		return nil, err
	}
	if err := ds.flowScheduler.ScheduleFlow(ctx, f); err != nil {
		return nil, err
	}
	return &SimpleResponse{}, nil
}

func (ds *ServerImpl) flowStreamInt(ctx context.Context, stream DistSQL_FlowStreamServer) error {
	// Receive the first message.
	msg, err := stream.Recv()
	if err != nil {
		if err == io.EOF {
			return errors.Errorf("missing header message")
		}
		return err
	}
	if msg.Header == nil {
		return errors.Errorf("no header in first message")
	}
	flowID := msg.Header.FlowID
	streamID := msg.Header.StreamID
	if log.V(1) {
		log.Infof(ctx, "connecting inbound stream %s/%d", flowID.Short(), streamID)
	}
	f, receiver, cleanup, err := ds.flowRegistry.ConnectInboundStream(
		flowID, streamID, flowStreamDefaultTimeout)
	if err != nil {
		return err
	}
	defer cleanup()
	log.VEventf(ctx, 1, "connected inbound stream %s/%d", flowID.Short(), streamID)
	return ProcessInboundStream(f.AnnotateCtx(ctx), stream, msg, receiver)
}

// FlowStream is part of the DistSQLServer interface.
func (ds *ServerImpl) FlowStream(stream DistSQL_FlowStreamServer) error {
	ctx := ds.AnnotateCtx(stream.Context())
	err := ds.flowStreamInt(ctx, stream)
	if err != nil {
		log.Error(ctx, err)
	}
	return err
}

// TestingKnobs are the testing knobs.
type TestingKnobs struct {
	// RunBeforeBackfillChunk is called before executing each chunk of a
	// backfill during a schema change operation. It is called with the
	// current span and returns an error which eventually is returned to the
	// caller of SchemaChanger.exec(). It is called at the start of the
	// backfill function passed into the transaction executing the chunk.
	RunBeforeBackfillChunk func(sp roachpb.Span) error

	// RunAfterBackfillChunk is called after executing each chunk of a
	// backfill during a schema change operation. It is called just before
	// returning from the backfill function passed into the transaction
	// executing the chunk. It is always called even when the backfill
	// function returns an error, or if the table has already been dropped.
	RunAfterBackfillChunk func()
}

// ModuleTestingKnobs is part of the base.ModuleTestingKnobs interface.
func (*TestingKnobs) ModuleTestingKnobs() {}
<commit_msg>sql/distsqlrun: do not call Finish on a nil span<commit_after>// Copyright 2016 The Cockroach 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.
//
// Author: Radu Berinde (radu@cockroachlabs.com)

package distsqlrun

import (
	"io"

	"golang.org/x/net/context"

	"github.com/cockroachdb/cockroach/pkg/internal/client"
	"github.com/cockroachdb/cockroach/pkg/roachpb"
	"github.com/cockroachdb/cockroach/pkg/rpc"
	"github.com/cockroachdb/cockroach/pkg/sql/parser"
	"github.com/cockroachdb/cockroach/pkg/util/log"
	"github.com/cockroachdb/cockroach/pkg/util/stop"
	"github.com/cockroachdb/cockroach/pkg/util/tracing"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
)

// ServerConfig encompasses the configuration required to create a
// DistSQLServer.
type ServerConfig struct {
	log.AmbientContext

	DB           *client.DB
	RPCContext   *rpc.Context
	Stopper      *stop.Stopper
	TestingKnobs TestingKnobs
}

// ServerImpl implements the server for the distributed SQL APIs.
type ServerImpl struct {
	ServerConfig
	evalCtx       parser.EvalContext
	flowRegistry  *flowRegistry
	flowScheduler *flowScheduler
}

var _ DistSQLServer = &ServerImpl{}

// NewServer instantiates a DistSQLServer.
func NewServer(cfg ServerConfig) *ServerImpl {
	ds := &ServerImpl{
		ServerConfig: cfg,
		evalCtx: parser.EvalContext{
			ReCache: parser.NewRegexpCache(512),
		},
		flowRegistry:  makeFlowRegistry(),
		flowScheduler: newFlowScheduler(cfg.AmbientContext, cfg.Stopper),
	}
	return ds
}

// Start launches workers for the server.
func (ds *ServerImpl) Start() {
	ds.flowScheduler.Start()
}

// Note: unless an error is returned, the returned context contains a span that
// must be finished through Flow.Cleanup.
func (ds *ServerImpl) setupFlow(
	ctx context.Context, req *SetupFlowRequest, syncFlowConsumer RowReceiver,
) (context.Context, *Flow, error) {
	const opName = "flow"
	var sp opentracing.Span
	if req.TraceContext == nil {
		sp = ds.Tracer.StartSpan(opName)
		ctx = opentracing.ContextWithSpan(ctx, sp)
	} else {
		var err error
		// TODO(andrei): in the following call we're ignoring the returned
		// recordedTrace. Figure out how to return the recording to the remote
		// caller after the flow is done.
		ctx, _, err = tracing.JoinRemoteTrace(ctx, ds.Tracer, req.TraceContext, opName)
		if err != nil {
			sp = ds.Tracer.StartSpan(opName)
			ctx = opentracing.ContextWithSpan(ctx, sp)
			log.Warningf(ctx, "failed to join a remote trace: %s", err)
		}
	}

	// TODO(radu): we should sanity check some of these fields (especially
	// txnProto).
	flowCtx := FlowCtx{
		AmbientContext: ds.AmbientContext,
		id:             req.Flow.FlowID,
		// TODO(andrei): more fields from evalCtx need to be initialized (#13821).
		evalCtx:      ds.evalCtx,
		rpcCtx:       ds.RPCContext,
		txnProto:     &req.Txn,
		clientDB:     ds.DB,
		testingKnobs: ds.TestingKnobs,
	}
	ctx = flowCtx.AnnotateCtx(ctx)
	flowCtx.evalCtx.Ctx = func() context.Context {
		// TODO(andrei): This is wrong. Each processor should override Ctx with its
		// own context.
		return ctx
	}

	f := newFlow(flowCtx, ds.flowRegistry, syncFlowConsumer)
	flowCtx.AddLogTagStr("f", f.id.Short())
	if err := f.setupFlow(ctx, &req.Flow); err != nil {
		log.Errorf(ctx, "error setting up flow: %s", err)
		tracing.FinishSpan(sp)
		ctx = opentracing.ContextWithSpan(ctx, nil)
		return ctx, nil, err
	}
	return ctx, f, nil
}

// SetupSyncFlow sets up a synchoronous flow, connecting the sync response
// output stream to the given RowReceiver. The flow is not started. The flow
// will be associated with the given context.
// Note: the returned context contains a span that must be finished through
// Flow.Cleanup.
func (ds *ServerImpl) SetupSyncFlow(
	ctx context.Context, req *SetupFlowRequest, output RowReceiver,
) (context.Context, *Flow, error) {
	return ds.setupFlow(ds.AnnotateCtx(ctx), req, output)
}

// RunSyncFlow is part of the DistSQLServer interface.
func (ds *ServerImpl) RunSyncFlow(stream DistSQL_RunSyncFlowServer) error {
	// Set up the outgoing mailbox for the stream.
	mbox := newOutboxSyncFlowStream(stream)

	firstMsg, err := stream.Recv()
	if err != nil {
		return err
	}
	if firstMsg.SetupFlowRequest == nil {
		return errors.Errorf("first message in RunSyncFlow doesn't contain SetupFlowRequest")
	}
	req := firstMsg.SetupFlowRequest
	ctx, f, err := ds.SetupSyncFlow(stream.Context(), req, mbox)
	if err != nil {
		return err
	}
	mbox.setFlowCtx(&f.FlowCtx)

	if err := ds.Stopper.RunTask(func() {
		f.waitGroup.Add(1)
		mbox.start(ctx, &f.waitGroup)
		f.Start(ctx, func() {})
		f.Wait()
		f.Cleanup(ctx)
	}); err != nil {
		return err
	}
	return mbox.err
}

// SetupFlow is part of the DistSQLServer interface.
func (ds *ServerImpl) SetupFlow(_ context.Context, req *SetupFlowRequest) (*SimpleResponse, error) {
	// Note: the passed context will be canceled when this RPC completes, so we
	// can't associate it with the flow.
	ctx := ds.AnnotateCtx(context.TODO())
	ctx, f, err := ds.setupFlow(ctx, req, nil)
	if err != nil {
		return nil, err
	}
	if err := ds.flowScheduler.ScheduleFlow(ctx, f); err != nil {
		return nil, err
	}
	return &SimpleResponse{}, nil
}

func (ds *ServerImpl) flowStreamInt(ctx context.Context, stream DistSQL_FlowStreamServer) error {
	// Receive the first message.
	msg, err := stream.Recv()
	if err != nil {
		if err == io.EOF {
			return errors.Errorf("missing header message")
		}
		return err
	}
	if msg.Header == nil {
		return errors.Errorf("no header in first message")
	}
	flowID := msg.Header.FlowID
	streamID := msg.Header.StreamID
	if log.V(1) {
		log.Infof(ctx, "connecting inbound stream %s/%d", flowID.Short(), streamID)
	}
	f, receiver, cleanup, err := ds.flowRegistry.ConnectInboundStream(
		flowID, streamID, flowStreamDefaultTimeout)
	if err != nil {
		return err
	}
	defer cleanup()
	log.VEventf(ctx, 1, "connected inbound stream %s/%d", flowID.Short(), streamID)
	return ProcessInboundStream(f.AnnotateCtx(ctx), stream, msg, receiver)
}

// FlowStream is part of the DistSQLServer interface.
func (ds *ServerImpl) FlowStream(stream DistSQL_FlowStreamServer) error {
	ctx := ds.AnnotateCtx(stream.Context())
	err := ds.flowStreamInt(ctx, stream)
	if err != nil {
		log.Error(ctx, err)
	}
	return err
}

// TestingKnobs are the testing knobs.
type TestingKnobs struct {
	// RunBeforeBackfillChunk is called before executing each chunk of a
	// backfill during a schema change operation. It is called with the
	// current span and returns an error which eventually is returned to the
	// caller of SchemaChanger.exec(). It is called at the start of the
	// backfill function passed into the transaction executing the chunk.
	RunBeforeBackfillChunk func(sp roachpb.Span) error

	// RunAfterBackfillChunk is called after executing each chunk of a
	// backfill during a schema change operation. It is called just before
	// returning from the backfill function passed into the transaction
	// executing the chunk. It is always called even when the backfill
	// function returns an error, or if the table has already been dropped.
	RunAfterBackfillChunk func()
}

// ModuleTestingKnobs is part of the base.ModuleTestingKnobs interface.
func (*TestingKnobs) ModuleTestingKnobs() {}
<|endoftext|>