<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package upgrade

import (
	"fmt"
	"os"
	"time"

	"github.com/spf13/cobra"

	clientset "k8s.io/client-go/kubernetes"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
	"k8s.io/kubernetes/cmd/kubeadm/app/features"
	"k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
	"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
	"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
	dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
	"k8s.io/kubernetes/pkg/api/legacyscheme"
	"k8s.io/kubernetes/pkg/util/version"
)

const (
	upgradeManifestTimeout = 1 * time.Minute
)

// applyFlags holds the information about the flags that can be passed to apply
type applyFlags struct {
	nonInteractiveMode bool
	force              bool
	dryRun             bool
	etcdUpgrade        bool
	newK8sVersionStr   string
	newK8sVersion      *version.Version
	imagePullTimeout   time.Duration
	parent             *cmdUpgradeFlags
}

// SessionIsInteractive returns true if the session is of an interactive type (the default, can be opted out of with -y, -f or --dry-run)
func (f *applyFlags) SessionIsInteractive() bool {
	return !f.nonInteractiveMode
}

// NewCmdApply returns the cobra command for `kubeadm upgrade apply`
func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command {
	flags := &applyFlags{
		parent:           parentFlags,
		imagePullTimeout: 15 * time.Minute,
		etcdUpgrade:      true,
	}

	cmd := &cobra.Command{
		Use: "apply [version]",
		DisableFlagsInUseLine: true,
		Short: "Upgrade your Kubernetes cluster to the specified version.",
		Run: func(cmd *cobra.Command, args []string) {
			var err error
			flags.parent.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(flags.parent.ignorePreflightErrors, flags.parent.skipPreFlight)
			kubeadmutil.CheckErr(err)

			// Ensure the user is root
			err = runPreflightChecks(flags.parent.ignorePreflightErrorsSet)
			kubeadmutil.CheckErr(err)

			// If the version is specified in config file, pick up that value.
			if flags.parent.cfgPath != "" {
				cfg, err := upgrade.FetchConfigurationFromFile(flags.parent.cfgPath)
				kubeadmutil.CheckErr(err)

				if cfg.KubernetesVersion != "" {
					flags.newK8sVersionStr = cfg.KubernetesVersion
				}
			}

			// If the new version is already specified in config file, version arg is optional.
			if flags.newK8sVersionStr == "" {
				err = cmdutil.ValidateExactArgNumber(args, []string{"version"})
				kubeadmutil.CheckErr(err)
			}

			// If option was specified in both args and config file, args will overwrite the config file.
			if len(args) == 1 {
				flags.newK8sVersionStr = args[0]
			}

			// Default the flags dynamically, based on each others' value
			err = SetImplicitFlags(flags)
			kubeadmutil.CheckErr(err)

			err = RunApply(flags)
			kubeadmutil.CheckErr(err)
		},
	}

	// Specify the valid flags specific for apply
	cmd.Flags().BoolVarP(&flags.nonInteractiveMode, "yes", "y", flags.nonInteractiveMode, "Perform the upgrade and do not prompt for confirmation (non-interactive mode).")
	cmd.Flags().BoolVarP(&flags.force, "force", "f", flags.force, "Force upgrading although some requirements might not be met. This also implies non-interactive mode.")
	cmd.Flags().BoolVar(&flags.dryRun, "dry-run", flags.dryRun, "Do not change any state, just output what actions would be performed.")
	cmd.Flags().BoolVar(&flags.etcdUpgrade, "etcd-upgrade", flags.etcdUpgrade, "Perform the upgrade of etcd.")
	cmd.Flags().DurationVar(&flags.imagePullTimeout, "image-pull-timeout", flags.imagePullTimeout, "The maximum amount of time to wait for the control plane pods to be downloaded.")

	return cmd
}

// RunApply takes care of the actual upgrade functionality
// It does the following things:
// - Checks if the cluster is healthy
// - Gets the configuration from the kubeadm-config ConfigMap in the cluster
// - Enforces all version skew policies
// - Asks the user if they really want to upgrade
// - Makes sure the control plane images are available locally on the master(s)
// - Upgrades the control plane components
// - Applies the other resources that'd be created with kubeadm init as well, like
//   - Creating the RBAC rules for the bootstrap tokens and the cluster-info ConfigMap
//   - Applying new kube-dns and kube-proxy manifests
//   - Uploads the newly used configuration to the cluster ConfigMap
func RunApply(flags *applyFlags) error {

	// Start with the basics, verify that the cluster is healthy and get the configuration from the cluster (using the ConfigMap)
	upgradeVars, err := enforceRequirements(flags.parent, flags.dryRun, flags.newK8sVersionStr)
	if err != nil {
		return err
	}

	// Grab the external, versioned configuration and convert it to the internal type for usage here later
	internalcfg := &kubeadmapi.MasterConfiguration{}
	legacyscheme.Scheme.Convert(upgradeVars.cfg, internalcfg, nil)

	// Validate requested and validate actual version
	if err := configutil.NormalizeKubernetesVersion(internalcfg); err != nil {
		return err
	}

	// Use normalized version string in all following code.
	flags.newK8sVersionStr = internalcfg.KubernetesVersion
	k8sVer, err := version.ParseSemantic(flags.newK8sVersionStr)
	if err != nil {
		return fmt.Errorf("unable to parse normalized version %q as a semantic version", flags.newK8sVersionStr)
	}
	flags.newK8sVersion = k8sVer

	if err := features.ValidateVersion(features.InitFeatureGates, internalcfg.FeatureGates, internalcfg.KubernetesVersion); err != nil {
		return err
	}

	// Enforce the version skew policies
	if err := EnforceVersionPolicies(flags, upgradeVars.versionGetter); err != nil {
		return fmt.Errorf("[upgrade/version] FATAL: %v", err)
	}

	// If the current session is interactive, ask the user whether they really want to upgrade
	if flags.SessionIsInteractive() {
		if err := InteractivelyConfirmUpgrade("Are you sure you want to proceed with the upgrade?"); err != nil {
			return err
		}
	}

	// Use a prepuller implementation based on creating DaemonSets
	// and block until all DaemonSets are ready; then we know for sure that all control plane images are cached locally
	prepuller := upgrade.NewDaemonSetPrepuller(upgradeVars.client, upgradeVars.waiter, internalcfg)
	upgrade.PrepullImagesInParallel(prepuller, flags.imagePullTimeout)

	// Now; perform the upgrade procedure
	if err := PerformControlPlaneUpgrade(flags, upgradeVars.client, upgradeVars.waiter, internalcfg); err != nil {
		return fmt.Errorf("[upgrade/apply] FATAL: %v", err)
	}

	// Upgrade RBAC rules and addons.
	if err := upgrade.PerformPostUpgradeTasks(upgradeVars.client, internalcfg, flags.newK8sVersion, flags.dryRun); err != nil {
		return fmt.Errorf("[upgrade/postupgrade] FATAL post-upgrade error: %v", err)
	}

	if flags.dryRun {
		fmt.Println("[dryrun] Finished dryrunning successfully!")
		return nil
	}

	fmt.Println("")
	fmt.Printf("[upgrade/successful] SUCCESS! Your cluster was upgraded to %q. Enjoy!\n", flags.newK8sVersionStr)
	fmt.Println("")
	fmt.Println("[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets in turn.")

	return nil
}

// SetImplicitFlags handles dynamically defaulting flags based on each other's value
func SetImplicitFlags(flags *applyFlags) error {
	// If we are in dry-run or force mode; we should automatically execute this command non-interactively
	if flags.dryRun || flags.force {
		flags.nonInteractiveMode = true
	}

	if len(flags.newK8sVersionStr) == 0 {
		return fmt.Errorf("version string can't be empty")
	}

	return nil
}

// EnforceVersionPolicies makes sure that the version the user specified is valid to upgrade to
// There are both fatal and skippable (with --force) errors
func EnforceVersionPolicies(flags *applyFlags, versionGetter upgrade.VersionGetter) error {
	fmt.Printf("[upgrade/version] You have chosen to change the cluster version to %q\n", flags.newK8sVersionStr)

	versionSkewErrs := upgrade.EnforceVersionPolicies(versionGetter, flags.newK8sVersionStr, flags.newK8sVersion, flags.parent.allowExperimentalUpgrades, flags.parent.allowRCUpgrades)
	if versionSkewErrs != nil {

		if len(versionSkewErrs.Mandatory) > 0 {
			return fmt.Errorf("The --version argument is invalid due to these fatal errors:\n\n%v\nPlease fix the misalignments highlighted above and try upgrading again", kubeadmutil.FormatErrMsg(versionSkewErrs.Mandatory))
		}

		if len(versionSkewErrs.Skippable) > 0 {
			// Return the error if the user hasn't specified the --force flag
			if !flags.force {
				return fmt.Errorf("The --version argument is invalid due to these errors:\n\n%v\nCan be bypassed if you pass the --force flag", kubeadmutil.FormatErrMsg(versionSkewErrs.Skippable))
			}
			// Soft errors found, but --force was specified
			fmt.Printf("[upgrade/version] Found %d potential version compatibility errors but skipping since the --force flag is set: \n\n%v", len(versionSkewErrs.Skippable), kubeadmutil.FormatErrMsg(versionSkewErrs.Skippable))
		}
	}
	return nil
}

// PerformControlPlaneUpgrade actually performs the upgrade procedure for the cluster of your type (self-hosted or static-pod-hosted)
func PerformControlPlaneUpgrade(flags *applyFlags, client clientset.Interface, waiter apiclient.Waiter, internalcfg *kubeadmapi.MasterConfiguration) error {

	// Check if the cluster is self-hosted and act accordingly
	if upgrade.IsControlPlaneSelfHosted(client) {
		fmt.Printf("[upgrade/apply] Upgrading your Self-Hosted control plane to version %q...\n", flags.newK8sVersionStr)

		// Upgrade the self-hosted cluster
		return upgrade.SelfHostedControlPlane(client, waiter, internalcfg, flags.newK8sVersion)
	}

	// OK, the cluster is hosted using static pods. Upgrade a static-pod hosted cluster
	fmt.Printf("[upgrade/apply] Upgrading your Static Pod-hosted control plane to version %q...\n", flags.newK8sVersionStr)

	if flags.dryRun {
		return DryRunStaticPodUpgrade(internalcfg)
	}

	return PerformStaticPodUpgrade(client, waiter, internalcfg, flags.etcdUpgrade)
}

// PerformStaticPodUpgrade performs the upgrade of the control plane components for a static pod hosted cluster
func PerformStaticPodUpgrade(client clientset.Interface, waiter apiclient.Waiter, internalcfg *kubeadmapi.MasterConfiguration, etcdUpgrade bool) error {
	pathManager, err := upgrade.NewKubeStaticPodPathManagerUsingTempDirs(constants.GetStaticPodDirectory())
	if err != nil {
		return err
	}

	// The arguments, oldEtcdClient and newEtdClient, are uninitialized because passing in the clients allow for mocking the client during testing
	return upgrade.StaticPodControlPlane(waiter, pathManager, internalcfg, etcdUpgrade, nil, nil)
}

// DryRunStaticPodUpgrade fakes an upgrade of the control plane
func DryRunStaticPodUpgrade(internalcfg *kubeadmapi.MasterConfiguration) error {

	dryRunManifestDir, err := constants.CreateTempDirForKubeadm("kubeadm-upgrade-dryrun")
	if err != nil {
		return err
	}
	defer os.RemoveAll(dryRunManifestDir)

	if err := controlplane.CreateInitStaticPodManifestFiles(dryRunManifestDir, internalcfg); err != nil {
		return err
	}

	// Print the contents of the upgraded manifests and pretend like they were in /etc/kubernetes/manifests
	files := []dryrunutil.FileToPrint{}
	for _, component := range constants.MasterComponents {
		realPath := constants.GetStaticPodFilepath(component, dryRunManifestDir)
		outputPath := constants.GetStaticPodFilepath(component, constants.GetStaticPodDirectory())
		files = append(files, dryrunutil.NewFileToPrint(realPath, outputPath))
	}

	return dryrunutil.PrintDryRunFiles(files, os.Stdout)
}
<commit_msg>kubeadm - increase upgrade manifest timeout<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package upgrade

import (
	"fmt"
	"os"
	"time"

	"github.com/spf13/cobra"

	clientset "k8s.io/client-go/kubernetes"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
	cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
	"k8s.io/kubernetes/cmd/kubeadm/app/features"
	"k8s.io/kubernetes/cmd/kubeadm/app/phases/controlplane"
	"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
	"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
	dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun"
	"k8s.io/kubernetes/pkg/api/legacyscheme"
	"k8s.io/kubernetes/pkg/util/version"
)

const (
	upgradeManifestTimeout = 5 * time.Minute
)

// applyFlags holds the information about the flags that can be passed to apply
type applyFlags struct {
	nonInteractiveMode bool
	force              bool
	dryRun             bool
	etcdUpgrade        bool
	newK8sVersionStr   string
	newK8sVersion      *version.Version
	imagePullTimeout   time.Duration
	parent             *cmdUpgradeFlags
}

// SessionIsInteractive returns true if the session is of an interactive type (the default, can be opted out of with -y, -f or --dry-run)
func (f *applyFlags) SessionIsInteractive() bool {
	return !f.nonInteractiveMode
}

// NewCmdApply returns the cobra command for `kubeadm upgrade apply`
func NewCmdApply(parentFlags *cmdUpgradeFlags) *cobra.Command {
	flags := &applyFlags{
		parent:           parentFlags,
		imagePullTimeout: 15 * time.Minute,
		etcdUpgrade:      true,
	}

	cmd := &cobra.Command{
		Use: "apply [version]",
		DisableFlagsInUseLine: true,
		Short: "Upgrade your Kubernetes cluster to the specified version.",
		Run: func(cmd *cobra.Command, args []string) {
			var err error
			flags.parent.ignorePreflightErrorsSet, err = validation.ValidateIgnorePreflightErrors(flags.parent.ignorePreflightErrors, flags.parent.skipPreFlight)
			kubeadmutil.CheckErr(err)

			// Ensure the user is root
			err = runPreflightChecks(flags.parent.ignorePreflightErrorsSet)
			kubeadmutil.CheckErr(err)

			// If the version is specified in config file, pick up that value.
			if flags.parent.cfgPath != "" {
				cfg, err := upgrade.FetchConfigurationFromFile(flags.parent.cfgPath)
				kubeadmutil.CheckErr(err)

				if cfg.KubernetesVersion != "" {
					flags.newK8sVersionStr = cfg.KubernetesVersion
				}
			}

			// If the new version is already specified in config file, version arg is optional.
			if flags.newK8sVersionStr == "" {
				err = cmdutil.ValidateExactArgNumber(args, []string{"version"})
				kubeadmutil.CheckErr(err)
			}

			// If option was specified in both args and config file, args will overwrite the config file.
			if len(args) == 1 {
				flags.newK8sVersionStr = args[0]
			}

			// Default the flags dynamically, based on each others' value
			err = SetImplicitFlags(flags)
			kubeadmutil.CheckErr(err)

			err = RunApply(flags)
			kubeadmutil.CheckErr(err)
		},
	}

	// Specify the valid flags specific for apply
	cmd.Flags().BoolVarP(&flags.nonInteractiveMode, "yes", "y", flags.nonInteractiveMode, "Perform the upgrade and do not prompt for confirmation (non-interactive mode).")
	cmd.Flags().BoolVarP(&flags.force, "force", "f", flags.force, "Force upgrading although some requirements might not be met. This also implies non-interactive mode.")
	cmd.Flags().BoolVar(&flags.dryRun, "dry-run", flags.dryRun, "Do not change any state, just output what actions would be performed.")
	cmd.Flags().BoolVar(&flags.etcdUpgrade, "etcd-upgrade", flags.etcdUpgrade, "Perform the upgrade of etcd.")
	cmd.Flags().DurationVar(&flags.imagePullTimeout, "image-pull-timeout", flags.imagePullTimeout, "The maximum amount of time to wait for the control plane pods to be downloaded.")

	return cmd
}

// RunApply takes care of the actual upgrade functionality
// It does the following things:
// - Checks if the cluster is healthy
// - Gets the configuration from the kubeadm-config ConfigMap in the cluster
// - Enforces all version skew policies
// - Asks the user if they really want to upgrade
// - Makes sure the control plane images are available locally on the master(s)
// - Upgrades the control plane components
// - Applies the other resources that'd be created with kubeadm init as well, like
//   - Creating the RBAC rules for the bootstrap tokens and the cluster-info ConfigMap
//   - Applying new kube-dns and kube-proxy manifests
//   - Uploads the newly used configuration to the cluster ConfigMap
func RunApply(flags *applyFlags) error {

	// Start with the basics, verify that the cluster is healthy and get the configuration from the cluster (using the ConfigMap)
	upgradeVars, err := enforceRequirements(flags.parent, flags.dryRun, flags.newK8sVersionStr)
	if err != nil {
		return err
	}

	// Grab the external, versioned configuration and convert it to the internal type for usage here later
	internalcfg := &kubeadmapi.MasterConfiguration{}
	legacyscheme.Scheme.Convert(upgradeVars.cfg, internalcfg, nil)

	// Validate requested and validate actual version
	if err := configutil.NormalizeKubernetesVersion(internalcfg); err != nil {
		return err
	}

	// Use normalized version string in all following code.
	flags.newK8sVersionStr = internalcfg.KubernetesVersion
	k8sVer, err := version.ParseSemantic(flags.newK8sVersionStr)
	if err != nil {
		return fmt.Errorf("unable to parse normalized version %q as a semantic version", flags.newK8sVersionStr)
	}
	flags.newK8sVersion = k8sVer

	if err := features.ValidateVersion(features.InitFeatureGates, internalcfg.FeatureGates, internalcfg.KubernetesVersion); err != nil {
		return err
	}

	// Enforce the version skew policies
	if err := EnforceVersionPolicies(flags, upgradeVars.versionGetter); err != nil {
		return fmt.Errorf("[upgrade/version] FATAL: %v", err)
	}

	// If the current session is interactive, ask the user whether they really want to upgrade
	if flags.SessionIsInteractive() {
		if err := InteractivelyConfirmUpgrade("Are you sure you want to proceed with the upgrade?"); err != nil {
			return err
		}
	}

	// Use a prepuller implementation based on creating DaemonSets
	// and block until all DaemonSets are ready; then we know for sure that all control plane images are cached locally
	prepuller := upgrade.NewDaemonSetPrepuller(upgradeVars.client, upgradeVars.waiter, internalcfg)
	upgrade.PrepullImagesInParallel(prepuller, flags.imagePullTimeout)

	// Now; perform the upgrade procedure
	if err := PerformControlPlaneUpgrade(flags, upgradeVars.client, upgradeVars.waiter, internalcfg); err != nil {
		return fmt.Errorf("[upgrade/apply] FATAL: %v", err)
	}

	// Upgrade RBAC rules and addons.
	if err := upgrade.PerformPostUpgradeTasks(upgradeVars.client, internalcfg, flags.newK8sVersion, flags.dryRun); err != nil {
		return fmt.Errorf("[upgrade/postupgrade] FATAL post-upgrade error: %v", err)
	}

	if flags.dryRun {
		fmt.Println("[dryrun] Finished dryrunning successfully!")
		return nil
	}

	fmt.Println("")
	fmt.Printf("[upgrade/successful] SUCCESS! Your cluster was upgraded to %q. Enjoy!\n", flags.newK8sVersionStr)
	fmt.Println("")
	fmt.Println("[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets in turn.")

	return nil
}

// SetImplicitFlags handles dynamically defaulting flags based on each other's value
func SetImplicitFlags(flags *applyFlags) error {
	// If we are in dry-run or force mode; we should automatically execute this command non-interactively
	if flags.dryRun || flags.force {
		flags.nonInteractiveMode = true
	}

	if len(flags.newK8sVersionStr) == 0 {
		return fmt.Errorf("version string can't be empty")
	}

	return nil
}

// EnforceVersionPolicies makes sure that the version the user specified is valid to upgrade to
// There are both fatal and skippable (with --force) errors
func EnforceVersionPolicies(flags *applyFlags, versionGetter upgrade.VersionGetter) error {
	fmt.Printf("[upgrade/version] You have chosen to change the cluster version to %q\n", flags.newK8sVersionStr)

	versionSkewErrs := upgrade.EnforceVersionPolicies(versionGetter, flags.newK8sVersionStr, flags.newK8sVersion, flags.parent.allowExperimentalUpgrades, flags.parent.allowRCUpgrades)
	if versionSkewErrs != nil {

		if len(versionSkewErrs.Mandatory) > 0 {
			return fmt.Errorf("The --version argument is invalid due to these fatal errors:\n\n%v\nPlease fix the misalignments highlighted above and try upgrading again", kubeadmutil.FormatErrMsg(versionSkewErrs.Mandatory))
		}

		if len(versionSkewErrs.Skippable) > 0 {
			// Return the error if the user hasn't specified the --force flag
			if !flags.force {
				return fmt.Errorf("The --version argument is invalid due to these errors:\n\n%v\nCan be bypassed if you pass the --force flag", kubeadmutil.FormatErrMsg(versionSkewErrs.Skippable))
			}
			// Soft errors found, but --force was specified
			fmt.Printf("[upgrade/version] Found %d potential version compatibility errors but skipping since the --force flag is set: \n\n%v", len(versionSkewErrs.Skippable), kubeadmutil.FormatErrMsg(versionSkewErrs.Skippable))
		}
	}
	return nil
}

// PerformControlPlaneUpgrade actually performs the upgrade procedure for the cluster of your type (self-hosted or static-pod-hosted)
func PerformControlPlaneUpgrade(flags *applyFlags, client clientset.Interface, waiter apiclient.Waiter, internalcfg *kubeadmapi.MasterConfiguration) error {

	// Check if the cluster is self-hosted and act accordingly
	if upgrade.IsControlPlaneSelfHosted(client) {
		fmt.Printf("[upgrade/apply] Upgrading your Self-Hosted control plane to version %q...\n", flags.newK8sVersionStr)

		// Upgrade the self-hosted cluster
		return upgrade.SelfHostedControlPlane(client, waiter, internalcfg, flags.newK8sVersion)
	}

	// OK, the cluster is hosted using static pods. Upgrade a static-pod hosted cluster
	fmt.Printf("[upgrade/apply] Upgrading your Static Pod-hosted control plane to version %q...\n", flags.newK8sVersionStr)

	if flags.dryRun {
		return DryRunStaticPodUpgrade(internalcfg)
	}

	return PerformStaticPodUpgrade(client, waiter, internalcfg, flags.etcdUpgrade)
}

// PerformStaticPodUpgrade performs the upgrade of the control plane components for a static pod hosted cluster
func PerformStaticPodUpgrade(client clientset.Interface, waiter apiclient.Waiter, internalcfg *kubeadmapi.MasterConfiguration, etcdUpgrade bool) error {
	pathManager, err := upgrade.NewKubeStaticPodPathManagerUsingTempDirs(constants.GetStaticPodDirectory())
	if err != nil {
		return err
	}

	// The arguments, oldEtcdClient and newEtdClient, are uninitialized because passing in the clients allow for mocking the client during testing
	return upgrade.StaticPodControlPlane(waiter, pathManager, internalcfg, etcdUpgrade, nil, nil)
}

// DryRunStaticPodUpgrade fakes an upgrade of the control plane
func DryRunStaticPodUpgrade(internalcfg *kubeadmapi.MasterConfiguration) error {

	dryRunManifestDir, err := constants.CreateTempDirForKubeadm("kubeadm-upgrade-dryrun")
	if err != nil {
		return err
	}
	defer os.RemoveAll(dryRunManifestDir)

	if err := controlplane.CreateInitStaticPodManifestFiles(dryRunManifestDir, internalcfg); err != nil {
		return err
	}

	// Print the contents of the upgraded manifests and pretend like they were in /etc/kubernetes/manifests
	files := []dryrunutil.FileToPrint{}
	for _, component := range constants.MasterComponents {
		realPath := constants.GetStaticPodFilepath(component, dryRunManifestDir)
		outputPath := constants.GetStaticPodFilepath(component, constants.GetStaticPodDirectory())
		files = append(files, dryrunutil.NewFileToPrint(realPath, outputPath))
	}

	return dryrunutil.PrintDryRunFiles(files, os.Stdout)
}
<|endoftext|>


<commit_before>// File generated by Gopher Sauce
// DO NOT EDIT!!
package templates

import (
	"github.com/thestrukture/IDE/api/assets"
	sessionStore "github.com/thestrukture/IDE/api/sessions"
	"bytes"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
)

var Prod = true

// Scans template string and uses data provided from request
// to find the line causing the panic.
func DebugTemplate(w http.ResponseWriter, r *http.Request, tmpl string) {
	lastline := 0
	linestring := ""
	defer func() {
		if n := recover(); n != nil {
			log.Println()
			// log.Println(n)
			log.Println("Error on line :", lastline+1, ":"+strings.TrimSpace(linestring))
			//http.Redirect(w,r,"",307)
		}
	}()

	p, err := LoadPage(r.URL.Path)
	filename := tmpl + ".tmpl"
	body, err := assets.Asset(filename)
	session, er := sessionStore.Store.Get(r, "session-")

	if er != nil {
		session, er = sessionStore.Store.New(r, "session-")
	}
	p.Session = session
	p.R = r
	if err != nil {
		log.Print(err)

	} else {

		lines := strings.Split(string(body), "\n")
		// log.Println( lines )
		linebuffer := ""
		waitend := false
		open := 0
		for i, line := range lines {

			processd := false

			if strings.Contains(line, "{{with") || strings.Contains(line, "{{ with") || strings.Contains(line, "with}}") || strings.Contains(line, "with }}") || strings.Contains(line, "{{range") || strings.Contains(line, "{{ range") || strings.Contains(line, "range }}") || strings.Contains(line, "range}}") || strings.Contains(line, "{{if") || strings.Contains(line, "{{ if") || strings.Contains(line, "if }}") || strings.Contains(line, "if}}") || strings.Contains(line, "{{block") || strings.Contains(line, "{{ block") || strings.Contains(line, "block }}") || strings.Contains(line, "block}}") {
				linebuffer += line
				waitend = true

				endstr := ""
				processd = true
				if !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {

					open++

				}
				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string(body))
				lastline = i
				linestring = line
				erro := t.Execute(outp, p)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if waitend && !processd && !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end")) {
				linebuffer += line

				endstr := ""
				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string(body))
				lastline = i
				linestring = line
				erro := t.Execute(outp, p)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}

			}

			if !waitend && !processd {
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string(body))
				lastline = i
				linestring = line
				erro := t.Execute(outp, p)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if !processd && (strings.Contains(line, "{{end") || strings.Contains(line, "{{ end")) {
				open--

				if open == 0 {
					waitend = false

				}
			}
		}

	}

}

// Gets template string from assets package, and
// uses it with a provided pointer to a struct variable
// to find the line causing panic.
func DebugTemplatePath(tmpl string, intrf interface{}) {
	lastline := 0
	linestring := ""
	defer func() {
		if n := recover(); n != nil {

			log.Println("Error on line :", lastline+1, ":"+strings.TrimSpace(linestring))
			log.Println(n)
			//http.Redirect(w,r,"",307)
		}
	}()

	filename := tmpl
	body, err := assets.Asset(filename)

	if err != nil {
		log.Print(err)

	} else {

		lines := strings.Split(string(body), "\n")
		// log.Println( lines )
		linebuffer := ""
		waitend := false
		open := 0
		for i, line := range lines {

			processd := false

			if strings.Contains(line, "{{with") || strings.Contains(line, "{{ with") || strings.Contains(line, "with}}") || strings.Contains(line, "with }}") || strings.Contains(line, "{{range") || strings.Contains(line, "{{ range") || strings.Contains(line, "range }}") || strings.Contains(line, "range}}") || strings.Contains(line, "{{if") || strings.Contains(line, "{{ if") || strings.Contains(line, "if }}") || strings.Contains(line, "if}}") || strings.Contains(line, "{{block") || strings.Contains(line, "{{ block") || strings.Contains(line, "block }}") || strings.Contains(line, "block}}") {
				linebuffer += line
				waitend = true

				endstr := ""
				if !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {

					open++

				}

				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec

				processd = true
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string([]byte(fmt.Sprintf("%s%s", linebuffer, endstr))))
				lastline = i
				linestring = line
				erro := t.Execute(outp, intrf)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if waitend && !processd && !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {
				linebuffer += line

				endstr := ""
				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string([]byte(fmt.Sprintf("%s%s", linebuffer, endstr))))
				lastline = i
				linestring = line
				erro := t.Execute(outp, intrf)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}

			}

			if !waitend && !processd {
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string([]byte(fmt.Sprintf("%s%s", linebuffer))))
				lastline = i
				linestring = line
				erro := t.Execute(outp, intrf)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if !processd && (strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {
				open--

				if open == 0 {
					waitend = false

				}
			}
		}

	}

}
<commit_msg>fix sprintf bug.<commit_after>// File generated by Gopher Sauce
// DO NOT EDIT!!
package templates

import (
	"github.com/thestrukture/IDE/api/assets"
	sessionStore "github.com/thestrukture/IDE/api/sessions"
	"bytes"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
)

var Prod = true

// Scans template string and uses data provided from request
// to find the line causing the panic.
func DebugTemplate(w http.ResponseWriter, r *http.Request, tmpl string) {
	lastline := 0
	linestring := ""
	defer func() {
		if n := recover(); n != nil {
			log.Println()
			// log.Println(n)
			log.Println("Error on line :", lastline+1, ":"+strings.TrimSpace(linestring))
			//http.Redirect(w,r,"",307)
		}
	}()

	p, err := LoadPage(r.URL.Path)
	filename := tmpl + ".tmpl"
	body, err := assets.Asset(filename)
	session, er := sessionStore.Store.Get(r, "session-")

	if er != nil {
		session, er = sessionStore.Store.New(r, "session-")
	}
	p.Session = session
	p.R = r
	if err != nil {
		log.Print(err)

	} else {

		lines := strings.Split(string(body), "\n")
		// log.Println( lines )
		linebuffer := ""
		waitend := false
		open := 0
		for i, line := range lines {

			processd := false

			if strings.Contains(line, "{{with") || strings.Contains(line, "{{ with") || strings.Contains(line, "with}}") || strings.Contains(line, "with }}") || strings.Contains(line, "{{range") || strings.Contains(line, "{{ range") || strings.Contains(line, "range }}") || strings.Contains(line, "range}}") || strings.Contains(line, "{{if") || strings.Contains(line, "{{ if") || strings.Contains(line, "if }}") || strings.Contains(line, "if}}") || strings.Contains(line, "{{block") || strings.Contains(line, "{{ block") || strings.Contains(line, "block }}") || strings.Contains(line, "block}}") {
				linebuffer += line
				waitend = true

				endstr := ""
				processd = true
				if !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {

					open++

				}
				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string(body))
				lastline = i
				linestring = line
				erro := t.Execute(outp, p)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if waitend && !processd && !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end")) {
				linebuffer += line

				endstr := ""
				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string(body))
				lastline = i
				linestring = line
				erro := t.Execute(outp, p)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}

			}

			if !waitend && !processd {
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string(body))
				lastline = i
				linestring = line
				erro := t.Execute(outp, p)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if !processd && (strings.Contains(line, "{{end") || strings.Contains(line, "{{ end")) {
				open--

				if open == 0 {
					waitend = false

				}
			}
		}

	}

}

// Gets template string from assets package, and
// uses it with a provided pointer to a struct variable
// to find the line causing panic.
func DebugTemplatePath(tmpl string, intrf interface{}) {
	lastline := 0
	linestring := ""
	defer func() {
		if n := recover(); n != nil {

			log.Println("Error on line :", lastline+1, ":"+strings.TrimSpace(linestring))
			log.Println(n)
			//http.Redirect(w,r,"",307)
		}
	}()

	filename := tmpl
	body, err := assets.Asset(filename)

	if err != nil {
		log.Print(err)

	} else {

		lines := strings.Split(string(body), "\n")
		// log.Println( lines )
		linebuffer := ""
		waitend := false
		open := 0
		for i, line := range lines {

			processd := false

			if strings.Contains(line, "{{with") || strings.Contains(line, "{{ with") || strings.Contains(line, "with}}") || strings.Contains(line, "with }}") || strings.Contains(line, "{{range") || strings.Contains(line, "{{ range") || strings.Contains(line, "range }}") || strings.Contains(line, "range}}") || strings.Contains(line, "{{if") || strings.Contains(line, "{{ if") || strings.Contains(line, "if }}") || strings.Contains(line, "if}}") || strings.Contains(line, "{{block") || strings.Contains(line, "{{ block") || strings.Contains(line, "block }}") || strings.Contains(line, "block}}") {
				linebuffer += line
				waitend = true

				endstr := ""
				if !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {

					open++

				}

				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec

				processd = true
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string([]byte(fmt.Sprintf("%s%s", linebuffer, endstr))))
				lastline = i
				linestring = line
				erro := t.Execute(outp, intrf)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if waitend && !processd && !(strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {
				linebuffer += line

				endstr := ""
				for i := 0; i < open; i++ {
					endstr += "\n{{end}}"
				}
				//exec
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string([]byte(fmt.Sprintf("%s%s", linebuffer, endstr))))
				lastline = i
				linestring = line
				erro := t.Execute(outp, intrf)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}

			}

			if !waitend && !processd {
				outp := new(bytes.Buffer)
				t := template.New("PageWrapper")
				t = t.Funcs(TemplateFuncStore)
				t, _ = t.Parse(string([]byte(fmt.Sprintf("%s", linebuffer))))
				lastline = i
				linestring = line
				erro := t.Execute(outp, intrf)
				if erro != nil {
					log.Println("Error on line :", i+1, line, erro.Error())
				}
			}

			if !processd && (strings.Contains(line, "{{end") || strings.Contains(line, "{{ end") || strings.Contains(line, "end}}") || strings.Contains(line, "end }}")) {
				open--

				if open == 0 {
					waitend = false

				}
			}
		}

	}

}
<|endoftext|>


<commit_before>package nativesequence

import (
	"testing"
	"github.com/johnny-morrice/godelbrot/base"
	"github.com/johnny-morrice/godelbrot/nativebase"
)

func TestSequence(t *testing.T) {
	if testing.Short() {
		panic("nativesequence testing impossible in short mode")
	}
	const iterateLimit = 10
	app := &nativebase.MockRenderApplication{
		MockRenderApplication: base.MockRenderApplication{
			PictureWidth: 10,
			PictureHeight: 10,
			Base: base.BaseConfig{DivergeLimit: 4.0, IterateLimit: iterateLimit},
		},
	}
	app.PlaneMin = complex(0.0, 0.0)
	app.PlaneMax = complex(10.0, 10.0)
	numerics := Make(app)
	out := numerics.Sequence()

	const expectedCount = 100
	actualArea := numerics.Area()

	if expectedCount != actualArea {
		t.Error("Expected area of", expectedCount,
			"but received", actualArea)
	}

	members := make([]base.PixelMember, actualArea)

	i := 0
	for point := range out {
		members[i] = point
		i++
	}
	actualCount := len(members)

	if expectedCount != actualCount {
		t.Error("Expected", expectedCount, "members but there were", actualCount)
	}
}
<commit_msg>Fix failing unit tests for nativesequence<commit_after>package nativesequence

import (
	"testing"
	"github.com/johnny-morrice/godelbrot/base"
	"github.com/johnny-morrice/godelbrot/nativebase"
)

func TestSequence(t *testing.T) {
	if testing.Short() {
		panic("nativesequence testing impossible in short mode")
	}
	const iterateLimit = 10
	app := &nativebase.MockRenderApplication{
		MockRenderApplication: base.MockRenderApplication{
			PictureWidth: 10,
			PictureHeight: 10,
			Base: base.BaseConfig{DivergeLimit: 4.0, IterateLimit: iterateLimit},
		},
	}
	app.PlaneMin = complex(0.0, 0.0)
	app.PlaneMax = complex(10.0, 10.0)
	numerics := Make(app)
	out := numerics.Sequence()

	const expectedCount = 100
	actualCount := len(out)

	if expectedCount != actualCount {
		t.Error("Expected", expectedCount, "members but there were", actualCount)
	}
}
<|endoftext|>


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

/*
	Package bitset implements bitsets.

	It provides methods for making a BitSet of an arbitrary
	upper limit, setting and testing bit locations, and clearing
	bit locations as well as the entire set.

	Example use:

	b := bitset.New(64000)
	b.SetBit(1000)
	if b.Bit(1000) {
		b.ClearBit(1000)
	}
*/
package bitset

// BitSet internal details
type BitSet struct {
	cap uint
	set      []uint64
}

// Make a BitSet with an upper limit on size.
func New(cap uint) *BitSet {
	return &BitSet{cap, make([]uint64, (cap+(64-1))/64)}
}

// Query maximum size of a bit set
func (b *BitSet) Cap() uint {
	return b.cap
}

/// Test whether bit i is set.
func (b *BitSet) Bit(i uint) bool {
	if b != nil && i < b.cap {
		return ((b.set[i/64] & (1 << (i % 64))) != 0)
	}
	return false
}

// Set bit i to 1
func (b *BitSet) SetBit(i uint) {
	if b != nil && i < b.cap {
		b.set[i/64] |= (1 << (i % 64))
	}
}

// Clear bit i to 0
func (b *BitSet) ClearBit(i uint) {
	if b != nil && i < b.cap {
		b.set[i/64] &^= 1 << (i % 64)
	}
}

// Clear entire BitSet
func (b *BitSet) Clear() {
	if b != nil {
		for i, _ := range b.set {
			b.set[i] = 0
		}
	}
}

// From Wikipedia: http://en.wikipedia.org/wiki/Hamming_weight
const m1  uint64 = 0x5555555555555555 //binary: 0101...
const m2  uint64 = 0x3333333333333333 //binary: 00110011..
const m4  uint64 = 0x0f0f0f0f0f0f0f0f //binary:  4 zeros,  4 ones ...

// From Wikipedia: count number of set bits.
func popcount_2(x uint64) uint64 {
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits
    x += x >>  8;  //put count of each 16 bits into their lowest 8 bits
    x += x >> 16;  //put count of each 32 bits into their lowest 8 bits
    x += x >> 32;  //put count of each 64 bits into their lowest 8 bits
    return x & 0x7f;
}

// Size (number of set bits)
func (b *BitSet) Count() uint {
   	if b != nil {
		cnt := uint64(0)
		for i, _ := range b.set {
			cnt += popcount_2(b.set[i])
		}
		return uint(cnt)
	}
	return 0
}

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

/*
	Package bitset implements bitsets.

	It provides methods for making a BitSet of an arbitrary
	upper limit, setting and testing bit locations, and clearing
	bit locations as well as the entire set.

	Example use:

	b := bitset.New(64000)
	b.SetBit(1000)
	if b.Bit(1000) {
		b.ClearBit(1000)
	}
*/
package bitset

// BitSet internal details
type BitSet struct {
	capacity uint
	set      []uint64
}

// Make a BitSet with an upper limit on size.
func New(capacity uint) *BitSet {
	return &BitSet{capacity, make([]uint64, (capacity+(64-1))/64)}
}

// Query maximum size of a bit set
func (b *BitSet) Cap() uint {
	return b.capacity
}

/// Test whether bit i is set.
func (b *BitSet) Bit(i uint) bool {
	if b != nil && i < b.capacity {
		return ((b.set[i/64] & (1 << (i % 64))) != 0)
	}
	return false
}

// Set bit i to 1
func (b *BitSet) SetBit(i uint) {
	if b != nil && i < b.capacity {
		b.set[i/64] |= (1 << (i % 64))
	}
}

// Clear bit i to 0
func (b *BitSet) ClearBit(i uint) {
	if b != nil && i < b.capacity {
		b.set[i/64] &^= 1 << (i % 64)
	}
}

// Clear entire BitSet
func (b *BitSet) Clear() {
	if b != nil {
		for i, _ := range b.set {
			b.set[i] = 0
		}
	}
}

// From Wikipedia: http://en.wikipedia.org/wiki/Hamming_weight
const m1  uint64 = 0x5555555555555555 //binary: 0101...
const m2  uint64 = 0x3333333333333333 //binary: 00110011..
const m4  uint64 = 0x0f0f0f0f0f0f0f0f //binary:  4 zeros,  4 ones ...

// From Wikipedia: count number of set bits.
func popcount_2(x uint64) uint64 {
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits
    x += x >>  8;  //put count of each 16 bits into their lowest 8 bits
    x += x >> 16;  //put count of each 32 bits into their lowest 8 bits
    x += x >> 32;  //put count of each 64 bits into their lowest 8 bits
    return x & 0x7f;
}

// Size (number of set bits)
func (b *BitSet) Count() uint {
   	if b != nil {
		cnt := uint64(0)
		for i, _ := range b.set {
			cnt += popcount_2(b.set[i])
		}
		return uint(cnt)
	}
	return 0
}

<|endoftext|>


<commit_before>package goblueboxapi

import (
	"errors"
	"fmt"
	"net/url"
	"strings"
)

// BlocksService exposes the API endpoints to interact with blocks.
type BlocksService struct {
	client *Client
}

// A Block is an on demand virtual computing resource.
type Block struct {
	ID       string
	Hostname string
	IPs      []BlockIP
	Status   string
}

// A BlockIP holds an IPv4 or IPv6 address for a block.
type BlockIP struct {
	Address string
}

// BlockParams holds the information needed to boot a block. Product and
// Template as well as either SshPublicKey or Password (but not both) must be
// specified.
type BlockParams struct {
	Product      string
	Template     string
	Password     string
	SshPublicKey string
	Hostname     string
	Username     string
	Location     string
	IPv6Only     bool
}

func (p BlockParams) validates() error {
	if p.Product == "" {
		return errors.New(`must specify "Product"`)
	}
	if p.Template == "" {
		return errors.New(`must specify "Template"`)
	}
	if p.Password != "" && p.SshPublicKey != "" {
		return errors.New(`only one of "Password" and "SshPublicKey" may be specified`)
	}
	if p.Password == "" && p.SshPublicKey == "" {
		return errors.New(`one of "Password" and "SshPublicKey" must be specified`)
	}

	return nil
}

func (p BlockParams) toValues() url.Values {
	v := url.Values{}
	if p.Product != "" {
		v.Set("product", p.Product)
	}
	if p.Template != "" {
		v.Set("template", p.Template)
	}
	if p.Password != "" {
		v.Set("password", p.Password)
	}
	if p.SshPublicKey != "" {
		v.Set("ssh_public_key", p.SshPublicKey)
	}
	if p.Hostname != "" {
		v.Set("hostname", p.Hostname)
	}
	if p.Username != "" {
		v.Set("username", p.Username)
	}
	if p.Location != "" {
		v.Set("location", p.Location)
	}
	if p.IPv6Only {
		v.Set("ipv6_only", "true")
	}

	return v
}

// List returns the currently running blocks, or an error if there was a problem
// fetching the information from the API.
func (s *BlocksService) List() ([]Block, error) {
	req, err := s.client.newRequest("GET", "/blocks", nil)
	if err != nil {
		return nil, err
	}

	var blocks []Block
	err = s.client.do(req, &blocks)

	return blocks, err
}

// Get returns a block given its Id, or an error if there was a problem fetching
// the information from the API.
func (s *BlocksService) Get(uuid string) (*Block, error) {
	req, err := s.client.newRequest("GET", fmt.Sprintf("/blocks/%s", uuid), nil)
	if err != nil {
		return nil, err
	}

	block := new(Block)
	err = s.client.do(req, block)

	return block, err
}

// Create boots a new block with the given parameters, and returns the block.
func (s *BlocksService) Create(p BlockParams) (*Block, error) {
	if err := p.validates(); err != nil {
		return nil, err
	}

	req, err := s.client.newRequest("POST", "/blocks", strings.NewReader(p.toValues().Encode()))
	if err != nil {
		return nil, err
	}

	block := new(Block)
	err = s.client.do(req, block)

	return block, err
}

// Destroy shuts down a block.
func (s *BlocksService) Destroy(uuid string) error {
	req, err := s.client.newRequest("DELETE", fmt.Sprintf("/blocks/%s", uuid), nil)
	if err != nil {
		return err
	}

	return s.client.do(req, nil)
}
<commit_msg>Add VSH ID to block payload<commit_after>package goblueboxapi

import (
	"errors"
	"fmt"
	"net/url"
	"strings"
)

// BlocksService exposes the API endpoints to interact with blocks.
type BlocksService struct {
	client *Client
}

// A Block is an on demand virtual computing resource.
type Block struct {
	ID       string
	Hostname string
	IPs      []BlockIP
	Status   string
	VSHID    string `json:"vsh_id"`
}

// A BlockIP holds an IPv4 or IPv6 address for a block.
type BlockIP struct {
	Address string
}

// BlockParams holds the information needed to boot a block. Product and
// Template as well as either SshPublicKey or Password (but not both) must be
// specified.
type BlockParams struct {
	Product      string
	Template     string
	Password     string
	SshPublicKey string
	Hostname     string
	Username     string
	Location     string
	IPv6Only     bool
}

func (p BlockParams) validates() error {
	if p.Product == "" {
		return errors.New(`must specify "Product"`)
	}
	if p.Template == "" {
		return errors.New(`must specify "Template"`)
	}
	if p.Password != "" && p.SshPublicKey != "" {
		return errors.New(`only one of "Password" and "SshPublicKey" may be specified`)
	}
	if p.Password == "" && p.SshPublicKey == "" {
		return errors.New(`one of "Password" and "SshPublicKey" must be specified`)
	}

	return nil
}

func (p BlockParams) toValues() url.Values {
	v := url.Values{}
	if p.Product != "" {
		v.Set("product", p.Product)
	}
	if p.Template != "" {
		v.Set("template", p.Template)
	}
	if p.Password != "" {
		v.Set("password", p.Password)
	}
	if p.SshPublicKey != "" {
		v.Set("ssh_public_key", p.SshPublicKey)
	}
	if p.Hostname != "" {
		v.Set("hostname", p.Hostname)
	}
	if p.Username != "" {
		v.Set("username", p.Username)
	}
	if p.Location != "" {
		v.Set("location", p.Location)
	}
	if p.IPv6Only {
		v.Set("ipv6_only", "true")
	}

	return v
}

// List returns the currently running blocks, or an error if there was a problem
// fetching the information from the API.
func (s *BlocksService) List() ([]Block, error) {
	req, err := s.client.newRequest("GET", "/blocks", nil)
	if err != nil {
		return nil, err
	}

	var blocks []Block
	err = s.client.do(req, &blocks)

	return blocks, err
}

// Get returns a block given its Id, or an error if there was a problem fetching
// the information from the API.
func (s *BlocksService) Get(uuid string) (*Block, error) {
	req, err := s.client.newRequest("GET", fmt.Sprintf("/blocks/%s", uuid), nil)
	if err != nil {
		return nil, err
	}

	block := new(Block)
	err = s.client.do(req, block)

	return block, err
}

// Create boots a new block with the given parameters, and returns the block.
func (s *BlocksService) Create(p BlockParams) (*Block, error) {
	if err := p.validates(); err != nil {
		return nil, err
	}

	req, err := s.client.newRequest("POST", "/blocks", strings.NewReader(p.toValues().Encode()))
	if err != nil {
		return nil, err
	}

	block := new(Block)
	err = s.client.do(req, block)

	return block, err
}

// Destroy shuts down a block.
func (s *BlocksService) Destroy(uuid string) error {
	req, err := s.client.newRequest("DELETE", fmt.Sprintf("/blocks/%s", uuid), nil)
	if err != nil {
		return err
	}

	return s.client.do(req, nil)
}
<|endoftext|>


<commit_before>package commandevaluators

import (
	"errors"
	"log"
	"strings"

	"github.com/byuoitav/av-api/base"
	"github.com/byuoitav/av-api/dbo"
	"github.com/byuoitav/configuration-database-microservice/accessors"
	"github.com/byuoitav/event-router-microservice/eventinfrastructure"
)

// Standby is struct that implements the CommandEvaluation struct
type StandbyDefault struct {
}

// Evaluate fulfills the CommmandEvaluation evaluate requirement.
func (s *StandbyDefault) Evaluate(room base.PublicRoom) (actions []base.ActionStructure, err error) {

	log.Printf("Evaluating for Standby Command.")

	var devices []accessors.Device
	eventInfo := eventinfrastructure.EventInfo{
		Type:           eventinfrastructure.CORESTATE,
		EventCause:     eventinfrastructure.USERINPUT,
		EventInfoKey:   "power",
		EventInfoValue: "standby",
	}

	if strings.EqualFold(room.Power, "standby") {

		log.Printf("Room-wide power set. Retrieving all devices.")
		devices, err = dbo.GetDevicesByRoom(room.Building, room.Room)
		if err != nil {
			return
		}

		log.Printf("Setting power to 'standby' state for all output devices.")
		for _, device := range devices {

			if device.Output {

				log.Printf("Adding device %+v", device.Name)
				eventInfo.Device = device.Name
				actions = append(actions, base.ActionStructure{
					Action:              "Standby",
					Device:              device,
					GeneratingEvaluator: "StandbyDefault",
					DeviceSpecific:      false,
					EventLog:            []eventinfrastructure.EventInfo{eventInfo},
				})
			}
		}
	}

	// now we go through and check if power 'standby' was set for any other device.
	for _, device := range room.Displays {
		log.Printf("Evaluating displays for command power standby. ")
		actions, err = s.evaluateDevice(device.Device, actions, devices, room.Room, room.Building, eventInfo)
		if err != nil {
			return
		}
	}

	for _, device := range room.AudioDevices {
		log.Printf("Evaluating audio devices for command power on. ")
		actions, err = s.evaluateDevice(device.Device, actions, devices, room.Room, room.Building, eventInfo)
		if err != nil {
			return
		}
	}
	log.Printf("%v actions generated.", len(actions))
	log.Printf("Evaluation complete.")

	return
}

// Validate fulfills the Fulfill requirement on the command interface
func (s *StandbyDefault) Validate(action base.ActionStructure) (err error) {
	log.Printf("Validating action for command Standby.")

	ok, _ := CheckCommands(action.Device.Commands, "Standby")
	if !ok || !strings.EqualFold(action.Action, "Standby") {
		log.Printf("ERROR. %s is an invalid command for %s", action.Action, action.Device.GetFullName())
		return errors.New(action.Action + " is an invalid command for" + action.Device.GetFullName())
	}

	log.Printf("Done.")
	return
}

// GetIncompatibleCommands keeps track of actions that are incompatable (on the same device)
func (s *StandbyDefault) GetIncompatibleCommands() (incompatableActions []string) {
	incompatableActions = []string{
		"PowerOn",
	}

	return
}

// Evaluate devices just pulls out the process we do with the audio-devices and displays into one function.
func (s *StandbyDefault) evaluateDevice(device base.Device, actions []base.ActionStructure, devices []accessors.Device, room string, building string, eventInfo eventinfrastructure.EventInfo) ([]base.ActionStructure, error) {
	// Check if we even need to start anything
	if strings.EqualFold(device.Power, "standby") {
		// check if we already added it
		index := checkActionListForDevice(actions, device.Name, room, building)
		if index == -1 {

			// Get the device, check the list of already retreived devices first, if not there,
			// hit the DB up for it.
			dev, err := getDevice(devices, device.Name, room, building)
			if err != nil {
				return actions, err
			}

			eventInfo.Device = device.Name
			actions = append(actions, base.ActionStructure{
				Action:              "Standby",
				Device:              dev,
				GeneratingEvaluator: "StandbyDefault",
				DeviceSpecific:      true,
				EventLog:            []eventinfrastructure.EventInfo{eventInfo},
			})
		}
	}
	return actions, nil
}
<commit_msg>hopefully everything has the right power states<commit_after>package commandevaluators

import (
	"errors"
	"log"
	"strings"

	"github.com/byuoitav/av-api/base"
	"github.com/byuoitav/av-api/dbo"
	"github.com/byuoitav/configuration-database-microservice/accessors"
	"github.com/byuoitav/event-router-microservice/eventinfrastructure"
)

// Standby is struct that implements the CommandEvaluation struct
type StandbyDefault struct {
}

// Evaluate fulfills the CommmandEvaluation evaluate requirement.
func (s *StandbyDefault) Evaluate(room base.PublicRoom) (actions []base.ActionStructure, err error) {

	log.Printf("Evaluating for Standby Command.")

	var devices []accessors.Device
	eventInfo := eventinfrastructure.EventInfo{
		Type:           eventinfrastructure.CORESTATE,
		EventCause:     eventinfrastructure.USERINPUT,
		EventInfoKey:   "power",
		EventInfoValue: "standby",
	}

	if strings.EqualFold(room.Power, "standby") {

		log.Printf("Room-wide power set. Retrieving all devices.")
		devices, err = dbo.GetDevicesByRoom(room.Building, room.Room)
		if err != nil {
			return
		}

		log.Printf("Setting power to 'standby' state for all output devices.")
		for _, device := range devices {

			containsStandby := false
			for _, ps := range device.PowerStates {
				if ps == "Standby" {
					containsStandby = true
					break
				}
			}
			if containsStandby {
				log.Printf("Adding device %+v", device.Name)
				eventInfo.Device = device.Name
				actions = append(actions, base.ActionStructure{
					Action:              "Standby",
					Device:              device,
					GeneratingEvaluator: "StandbyDefault",
					DeviceSpecific:      false,
					EventLog:            []eventinfrastructure.EventInfo{eventInfo},
				})
			}
			/*
				if device.Output {

					log.Printf("Adding device %+v", device.Name)
					eventInfo.Device = device.Name
					actions = append(actions, base.ActionStructure{
						Action:              "Standby",
						Device:              device,
						GeneratingEvaluator: "StandbyDefault",
						DeviceSpecific:      false,
						EventLog:            []eventinfrastructure.EventInfo{eventInfo},
					})
				}
			*/
		}
	}

	// now we go through and check if power 'standby' was set for any other device.
	for _, device := range room.Displays {
		log.Printf("Evaluating displays for command power standby. ")
		actions, err = s.evaluateDevice(device.Device, actions, devices, room.Room, room.Building, eventInfo)
		if err != nil {
			return
		}
	}

	for _, device := range room.AudioDevices {
		log.Printf("Evaluating audio devices for command power on. ")
		actions, err = s.evaluateDevice(device.Device, actions, devices, room.Room, room.Building, eventInfo)
		if err != nil {
			return
		}
	}
	log.Printf("%v actions generated.", len(actions))
	log.Printf("Evaluation complete.")

	return
}

// Validate fulfills the Fulfill requirement on the command interface
func (s *StandbyDefault) Validate(action base.ActionStructure) (err error) {
	log.Printf("Validating action for command Standby.")

	ok, _ := CheckCommands(action.Device.Commands, "Standby")
	if !ok || !strings.EqualFold(action.Action, "Standby") {
		log.Printf("ERROR. %s is an invalid command for %s", action.Action, action.Device.GetFullName())
		return errors.New(action.Action + " is an invalid command for" + action.Device.GetFullName())
	}

	log.Printf("Done.")
	return
}

// GetIncompatibleCommands keeps track of actions that are incompatable (on the same device)
func (s *StandbyDefault) GetIncompatibleCommands() (incompatableActions []string) {
	incompatableActions = []string{
		"PowerOn",
	}

	return
}

// Evaluate devices just pulls out the process we do with the audio-devices and displays into one function.
func (s *StandbyDefault) evaluateDevice(device base.Device, actions []base.ActionStructure, devices []accessors.Device, room string, building string, eventInfo eventinfrastructure.EventInfo) ([]base.ActionStructure, error) {
	// Check if we even need to start anything
	if strings.EqualFold(device.Power, "standby") {
		// check if we already added it
		index := checkActionListForDevice(actions, device.Name, room, building)
		if index == -1 {

			// Get the device, check the list of already retreived devices first, if not there,
			// hit the DB up for it.
			dev, err := getDevice(devices, device.Name, room, building)
			if err != nil {
				return actions, err
			}

			eventInfo.Device = device.Name
			actions = append(actions, base.ActionStructure{
				Action:              "Standby",
				Device:              dev,
				GeneratingEvaluator: "StandbyDefault",
				DeviceSpecific:      true,
				EventLog:            []eventinfrastructure.EventInfo{eventInfo},
			})
		}
	}
	return actions, nil
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package dashboard

import (
	"github.com/webx-top/echo"
)

func NewGlobalFooter(content func(echo.Context) error) *GlobalFooter {
	return &GlobalFooter{content: content}
}

type GlobalFooter struct {
	Tmpl    string //模板文件
	content func(echo.Context) error
}

func (c *GlobalFooter) Ready(ctx echo.Context) error {
	if c.content != nil {
		return c.content(ctx)
	}
	return nil
}

func (c *GlobalFooter) SetContentGenerator(content func(echo.Context) error) *GlobalFooter {
	c.content = content
	return c
}

type GlobalFooters []*GlobalFooter

func (c *GlobalFooters) Ready(ctx echo.Context) error {
	for _, blk := range *c {
		if blk != nil {
			if err := blk.Ready(ctx); err != nil {
				return err
			}
		}
	}
	return nil
}

// Remove 删除元素
func (c *GlobalFooters) Remove(index int) {
	if index < 0 {
		*c = (*c)[0:0]
		return
	}
	size := c.Size()
	if size > index {
		if size > index+1 {
			*c = append((*c)[0:index], (*c)[index+1:]...)
		} else {
			*c = (*c)[0:index]
		}
	}
}

func (c *GlobalFooters) Add(index int, list ...*GlobalFooter) {
	if len(list) == 0 {
		return
	}
	if index < 0 {
		*c = append(*c, list...)
		return
	}
	size := c.Size()
	if size > index {
		list = append(list, (*c)[index])
		(*c)[index] = list[0]
		if len(list) > 1 {
			c.Add(index+1, list[1:]...)
		}
		return
	}
	for start, end := size, index-1; start < end; start++ {
		*c = append(*c, nil)
	}
	*c = append(*c, list...)
}

// Set 设置元素
func (c *GlobalFooters) Set(index int, list ...*GlobalFooter) {
	if len(list) == 0 {
		return
	}
	if index < 0 {
		*c = append(*c, list...)
		return
	}
	size := c.Size()
	if size > index {
		(*c)[index] = list[0]
		if len(list) > 1 {
			c.Set(index+1, list[1:]...)
		}
		return
	}
	for start, end := size, index-1; start < end; start++ {
		*c = append(*c, nil)
	}
	*c = append(*c, list...)
}

func (c *GlobalFooters) Size() int {
	return len(*c)
}

var globalFooters = GlobalFooters{}

func GlobalFooterRegister(footer ...*GlobalFooter) {
	globalFooters.Add(-1, footer...)
}

func GlobalFooterAdd(index int, footer ...*GlobalFooter) {
	globalFooters.Add(index, footer...)
}

//GlobalFooterRemove 删除元素
func GlobalFooterRemove(index int) {
	globalFooters.Remove(index)
}

//GlobalFooterSet 设置元素
func GlobalFooterSet(index int, list ...*GlobalFooter) {
	globalFooters.Set(index, list...)
}

func GlobalFooterAll(_ echo.Context) GlobalFooters {
	return globalFooters
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package dashboard

import (
	"github.com/webx-top/echo"
)

func NewGlobalFooter(tmpl string, handle ...func(echo.Context) error) *GlobalFooter {
	var content func(echo.Context) error
	if len(handle) > 0 {
		content = handle[0]
	}
	return &GlobalFooter{Tmpl: tmpl, content: content}
}

type GlobalFooter struct {
	Tmpl    string //模板文件
	content func(echo.Context) error
}

func (c *GlobalFooter) Ready(ctx echo.Context) error {
	if c.content != nil {
		return c.content(ctx)
	}
	return nil
}

func (c *GlobalFooter) SetContentGenerator(content func(echo.Context) error) *GlobalFooter {
	c.content = content
	return c
}

func (c *GlobalFooter) SetTmpl(tmpl string) *GlobalFooter {
	c.Tmpl = tmpl
	return c
}

type GlobalFooters []*GlobalFooter

func (c *GlobalFooters) Ready(ctx echo.Context) error {
	for _, blk := range *c {
		if blk != nil {
			if err := blk.Ready(ctx); err != nil {
				return err
			}
		}
	}
	return nil
}

// Remove 删除元素
func (c *GlobalFooters) Remove(index int) {
	if index < 0 {
		*c = (*c)[0:0]
		return
	}
	size := c.Size()
	if size > index {
		if size > index+1 {
			*c = append((*c)[0:index], (*c)[index+1:]...)
		} else {
			*c = (*c)[0:index]
		}
	}
}

func (c *GlobalFooters) Add(index int, list ...*GlobalFooter) {
	if len(list) == 0 {
		return
	}
	if index < 0 {
		*c = append(*c, list...)
		return
	}
	size := c.Size()
	if size > index {
		list = append(list, (*c)[index])
		(*c)[index] = list[0]
		if len(list) > 1 {
			c.Add(index+1, list[1:]...)
		}
		return
	}
	for start, end := size, index-1; start < end; start++ {
		*c = append(*c, nil)
	}
	*c = append(*c, list...)
}

// Set 设置元素
func (c *GlobalFooters) Set(index int, list ...*GlobalFooter) {
	if len(list) == 0 {
		return
	}
	if index < 0 {
		*c = append(*c, list...)
		return
	}
	size := c.Size()
	if size > index {
		(*c)[index] = list[0]
		if len(list) > 1 {
			c.Set(index+1, list[1:]...)
		}
		return
	}
	for start, end := size, index-1; start < end; start++ {
		*c = append(*c, nil)
	}
	*c = append(*c, list...)
}

func (c *GlobalFooters) Size() int {
	return len(*c)
}

var globalFooters = GlobalFooters{}

func GlobalFooterRegister(footer ...*GlobalFooter) {
	globalFooters.Add(-1, footer...)
}

func GlobalFooterAdd(index int, footer ...*GlobalFooter) {
	globalFooters.Add(index, footer...)
}

//GlobalFooterRemove 删除元素
func GlobalFooterRemove(index int) {
	globalFooters.Remove(index)
}

//GlobalFooterSet 设置元素
func GlobalFooterSet(index int, list ...*GlobalFooter) {
	globalFooters.Set(index, list...)
}

func GlobalFooterAll(_ echo.Context) GlobalFooters {
	return globalFooters
}
<|endoftext|>


<commit_before>//+build ignore

package main

// This file is the input to TestValueForExpr in source_test.go, which
// ensures that each expression e immediately following a /*@kind*/(x)
// annotation, when passed to Function.ValueForExpr(e), returns a
// non-nil Value of the same type as e and of kind 'kind'.

func f(spilled, unspilled int) {
	_ = /*@UnOp*/ (spilled)
	_ = /*@Parameter*/ (unspilled)
	_ = /*@<nil>*/ (1 + 2) // (constant)
	i := 0

	f := func() (int, int) { return 0, 0 }

	/*@Call*/ (print( /*@BinOp*/ (i + 1)))
	_, _ = /*@Call*/ (f())
	ch := /*@MakeChan*/ (make(chan int))
	/*@UnOp*/ (<-ch)
	x := /*@UnOp*/ (<-ch)
	_ = x
	select {
	case /*@Extract*/ (<-ch):
	case x := /*@Extract*/ (<-ch):
		_ = x
	}
	defer /*@Function*/ (func() {
	})()
	go /*@Function*/ (func() {
	})()
	y := 0
	if true && /*@BinOp*/ (bool(y > 0)) {
		y = 1
	}
	_ = /*@Phi*/ (y)
	map1 := /*@MakeMap*/ (make(map[string]string))
	_ = map1
	_ = /*@Slice*/ (make([]int, 0))
	_ = /*@MakeClosure*/ (func() { print(spilled) })

	sl := []int{}
	_ = /*@Slice*/ (sl[:0])

	_ = /*@<nil>*/ (new(int)) // optimized away
	tmp := /*@Alloc*/ (new(int))
	_ = tmp
	var iface interface{}
	_ = /*@TypeAssert*/ (iface.(int))
	_ = /*@UnOp*/ (sl[0])
	_ = /*@IndexAddr*/ (&sl[0])
	_ = /*@Index*/ ([2]int{}[0])
	var p *int
	_ = /*@UnOp*/ (*p)

	_ = /*@UnOp*/ (global)
	/*@UnOp*/ (global)[""] = ""
	/*@Global*/ (global) = map[string]string{}

	var local t
	/*UnOp*/ (local.x) = 1

	// Exercise corner-cases of lvalues vs rvalues.
	type N *N
	var n N
	/*@UnOp*/ (n) = /*@UnOp*/ (n)
	/*@ChangeType*/ (n) = /*@Alloc*/ (&n)
	/*@UnOp*/ (n) = /*@UnOp*/ (*n)
	/*@UnOp*/ (n) = /*@UnOp*/ (**n)
}

func complit() {
	// Composite literals.
	// We get different results for
	// - composite literal as value (e.g. operand to print)
	// - composite literal initializer for addressable value
	// - composite literal value assigned to blank var

	// 1. Slices
	print( /*@Slice*/ ([]int{}))
	print( /*@Alloc*/ (&[]int{}))
	print(& /*@Slice*/ ([]int{}))

	sl1 := /*@Slice*/ ([]int{})
	sl2 := /*@Alloc*/ (&[]int{})
	sl3 := & /*@Slice*/ ([]int{})
	_, _, _ = sl1, sl2, sl3

	_ = /*@Slice*/ ([]int{})
	_ = /*@<nil>*/ (& /*@Slice*/ ([]int{})) // & optimized away
	_ = & /*@Slice*/ ([]int{})

	// 2. Arrays
	print( /*@UnOp*/ ([1]int{}))
	print( /*@Alloc*/ (&[1]int{}))
	print(& /*@Alloc*/ ([1]int{}))

	arr1 := /*@Alloc*/ ([1]int{})
	arr2 := /*@Alloc*/ (&[1]int{})
	arr3 := & /*@Alloc*/ ([1]int{})
	_, _, _ = arr1, arr2, arr3

	_ = /*@UnOp*/ ([1]int{})
	_ = /*@Alloc*/ (& /*@Alloc*/ ([1]int{}))
	_ = & /*@Alloc*/ ([1]int{})

	// 3. Maps
	type M map[int]int
	print( /*@MakeMap*/ (M{}))
	print( /*@Alloc*/ (&M{}))
	print(& /*@MakeMap*/ (M{}))

	m1 := /*@MakeMap*/ (M{})
	m2 := /*@Alloc*/ (&M{})
	m3 := & /*@MakeMap*/ (M{})
	_, _, _ = m1, m2, m3

	_ = /*@MakeMap*/ (M{})
	_ = /*@<nil>*/ (& /*@MakeMap*/ (M{})) // & optimized away
	_ = & /*@MakeMap*/ (M{})

	// 4. Structs
	print( /*@UnOp*/ (struct{}{}))
	print( /*@Alloc*/ (&struct{}{}))
	print(& /*@Alloc*/ (struct{}{}))

	s1 := /*@Alloc*/ (struct{}{})
	s2 := /*@Alloc*/ (&struct{}{})
	s3 := & /*@Alloc*/ (struct{}{})
	_, _, _ = s1, s2, s3

	_ = /*@UnOp*/ (struct{}{})
	_ = /*@Alloc*/ (& /*@Alloc*/ (struct{}{}))
	_ = & /*@Alloc*/ (struct{}{})
}

type t struct{ x int }

// Ensure we can locate methods of named types.
func (t) f(param int) {
	_ = /*@Parameter*/ (param)
}

// Ensure we can locate init functions.
func init() {
	m := /*@MakeMap*/ (make(map[string]string))
	_ = m
}

// Ensure we can locate variables in initializer expressions.
var global = /*@MakeMap*/ (make(map[string]string))
<commit_msg>ssa: remove tests for removed optimizations<commit_after>//+build ignore

package main

// This file is the input to TestValueForExpr in source_test.go, which
// ensures that each expression e immediately following a /*@kind*/(x)
// annotation, when passed to Function.ValueForExpr(e), returns a
// non-nil Value of the same type as e and of kind 'kind'.

func f(spilled, unspilled int) {
	_ = /*@UnOp*/ (spilled)
	_ = /*@Parameter*/ (unspilled)
	_ = /*@<nil>*/ (1 + 2) // (constant)
	i := 0

	f := func() (int, int) { return 0, 0 }

	/*@Call*/ (print( /*@BinOp*/ (i + 1)))
	_, _ = /*@Call*/ (f())
	ch := /*@MakeChan*/ (make(chan int))
	/*@UnOp*/ (<-ch)
	x := /*@UnOp*/ (<-ch)
	_ = x
	select {
	case /*@Extract*/ (<-ch):
	case x := /*@Extract*/ (<-ch):
		_ = x
	}
	defer /*@Function*/ (func() {
	})()
	go /*@Function*/ (func() {
	})()
	y := 0
	if true && /*@BinOp*/ (bool(y > 0)) {
		y = 1
	}
	_ = /*@Phi*/ (y)
	map1 := /*@MakeMap*/ (make(map[string]string))
	_ = map1
	_ = /*@Slice*/ (make([]int, 0))
	_ = /*@MakeClosure*/ (func() { print(spilled) })

	sl := []int{}
	_ = /*@Slice*/ (sl[:0])

	tmp := /*@Alloc*/ (new(int))
	_ = tmp
	var iface interface{}
	_ = /*@TypeAssert*/ (iface.(int))
	_ = /*@UnOp*/ (sl[0])
	_ = /*@IndexAddr*/ (&sl[0])
	_ = /*@Index*/ ([2]int{}[0])
	var p *int
	_ = /*@UnOp*/ (*p)

	_ = /*@UnOp*/ (global)
	/*@UnOp*/ (global)[""] = ""
	/*@Global*/ (global) = map[string]string{}

	var local t
	/*UnOp*/ (local.x) = 1

	// Exercise corner-cases of lvalues vs rvalues.
	type N *N
	var n N
	/*@UnOp*/ (n) = /*@UnOp*/ (n)
	/*@ChangeType*/ (n) = /*@Alloc*/ (&n)
	/*@UnOp*/ (n) = /*@UnOp*/ (*n)
	/*@UnOp*/ (n) = /*@UnOp*/ (**n)
}

func complit() {
	// Composite literals.
	// We get different results for
	// - composite literal as value (e.g. operand to print)
	// - composite literal initializer for addressable value
	// - composite literal value assigned to blank var

	// 1. Slices
	print( /*@Slice*/ ([]int{}))
	print( /*@Alloc*/ (&[]int{}))
	print(& /*@Slice*/ ([]int{}))

	sl1 := /*@Slice*/ ([]int{})
	sl2 := /*@Alloc*/ (&[]int{})
	sl3 := & /*@Slice*/ ([]int{})
	_, _, _ = sl1, sl2, sl3

	_ = /*@Slice*/ ([]int{})
	_ = & /*@Slice*/ ([]int{})

	// 2. Arrays
	print( /*@UnOp*/ ([1]int{}))
	print( /*@Alloc*/ (&[1]int{}))
	print(& /*@Alloc*/ ([1]int{}))

	arr1 := /*@Alloc*/ ([1]int{})
	arr2 := /*@Alloc*/ (&[1]int{})
	arr3 := & /*@Alloc*/ ([1]int{})
	_, _, _ = arr1, arr2, arr3

	_ = /*@UnOp*/ ([1]int{})
	_ = /*@Alloc*/ (& /*@Alloc*/ ([1]int{}))
	_ = & /*@Alloc*/ ([1]int{})

	// 3. Maps
	type M map[int]int
	print( /*@MakeMap*/ (M{}))
	print( /*@Alloc*/ (&M{}))
	print(& /*@MakeMap*/ (M{}))

	m1 := /*@MakeMap*/ (M{})
	m2 := /*@Alloc*/ (&M{})
	m3 := & /*@MakeMap*/ (M{})
	_, _, _ = m1, m2, m3

	_ = /*@MakeMap*/ (M{})
	_ = & /*@MakeMap*/ (M{})

	// 4. Structs
	print( /*@UnOp*/ (struct{}{}))
	print( /*@Alloc*/ (&struct{}{}))
	print(& /*@Alloc*/ (struct{}{}))

	s1 := /*@Alloc*/ (struct{}{})
	s2 := /*@Alloc*/ (&struct{}{})
	s3 := & /*@Alloc*/ (struct{}{})
	_, _, _ = s1, s2, s3

	_ = /*@UnOp*/ (struct{}{})
	_ = /*@Alloc*/ (& /*@Alloc*/ (struct{}{}))
	_ = & /*@Alloc*/ (struct{}{})
}

type t struct{ x int }

// Ensure we can locate methods of named types.
func (t) f(param int) {
	_ = /*@Parameter*/ (param)
}

// Ensure we can locate init functions.
func init() {
	m := /*@MakeMap*/ (make(map[string]string))
	_ = m
}

// Ensure we can locate variables in initializer expressions.
var global = /*@MakeMap*/ (make(map[string]string))
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package watcher

import (
	"sync"

	"github.com/juju/loggo"
	"launchpad.net/tomb"

	"github.com/juju/juju/state/api/base"
	"github.com/juju/juju/state/api/params"
)

var logger = loggo.GetLogger("juju.state.api.watcher")

// commonWatcher implements common watcher logic in one place to
// reduce code duplication, but it's not in fact a complete watcher;
// it's intended for embedding.
type commonWatcher struct {
	tomb tomb.Tomb
	wg   sync.WaitGroup
	in   chan interface{}

	// These fields must be set by the embedding watcher, before
	// calling init().

	// newResult must return a pointer to a value of the type returned
	// by the watcher's Next call.
	newResult func() interface{}

	// call should invoke the given API method, placing the call's
	// returned value in result (if any).
	call func(method string, result interface{}) error
}

// init must be called to initialize an embedded commonWatcher's
// fields. Make sure newResult and call fields are set beforehand.
func (w *commonWatcher) init() {
	w.in = make(chan interface{})
	if w.newResult == nil {
		panic("newResult must me set")
	}
	if w.call == nil {
		panic("call must be set")
	}
}

// commonLoop implements the loop structure common to the client
// watchers. It should be started in a separate goroutine by any
// watcher that embeds commonWatcher. It kills the commonWatcher's
// tomb when an error occurs.
// Callers of commonLoop must call w.wg.Add(1) before spawning this in a
// goroutine, so that we ensure this goroutine is actually accessed and the new
// helper goroutines are spawned before we stop in the outer loop.
func (w *commonWatcher) commonLoop() {
	defer close(w.in)
	w.wg.Add(1)
	go func() {
		// When the watcher has been stopped, we send a Stop request
		// to the server, which will remove the watcher and return a
		// CodeStopped error to any currently outstanding call to
		// Next. If a call to Next happens just after the watcher has
		// been stopped, we'll get a CodeNotFound error; Either way
		// we'll return, wait for the stop request to complete, and
		// the watcher will die with all resources cleaned up.
		defer w.wg.Done()
		<-w.tomb.Dying()
		if err := w.call("Stop", nil); err != nil {
			logger.Errorf("error trying to stop watcher: %v", err)
		}
	}()
	w.wg.Add(1)
	go func() {
		// Because Next blocks until there are changes, we need to
		// call it in a separate goroutine, so the watcher can be
		// stopped normally.
		defer w.wg.Done()
		for {
			result := w.newResult()
			err := w.call("Next", &result)
			if err != nil {
				if params.IsCodeStopped(err) || params.IsCodeNotFound(err) {
					if w.tomb.Err() != tomb.ErrStillAlive {
						// The watcher has been stopped at the client end, so we're
						// expecting one of the above two kinds of error.
						// We might see the same errors if the server itself
						// has been shut down, in which case we leave them
						// untouched.
						err = tomb.ErrDying
					}
				}
				// Something went wrong, just report the error and bail out.
				w.tomb.Kill(err)
				return
			}
			select {
			case <-w.tomb.Dying():
				return
			case w.in <- result:
				// Report back the result we just got.
			}
		}
	}()
	// We have started the commonLoop, so we have finished 1 of the waits
	// that we started waiting for.
	w.wg.Done()
	w.wg.Wait()
}

func (w *commonWatcher) Stop() error {
	w.tomb.Kill(nil)
	return w.tomb.Wait()
}

func (w *commonWatcher) Err() error {
	return w.tomb.Err()
}

// notifyWatcher will send events when something changes.
// It does not send content for those changes.
type notifyWatcher struct {
	commonWatcher
	caller          base.Caller
	notifyWatcherId string
	out             chan struct{}
}

// If an API call returns a NotifyWatchResult, you can use this to turn it into
// a local Watcher.
func NewNotifyWatcher(caller base.Caller, result params.NotifyWatchResult) NotifyWatcher {
	w := &notifyWatcher{
		caller:          caller,
		notifyWatcherId: result.NotifyWatcherId,
		out:             make(chan struct{}),
	}
	go func() {
		defer w.tomb.Done()
		defer close(w.out)
		defer w.wg.Wait() // Wait for watcher to be stopped.
		w.tomb.Kill(w.loop())
	}()
	return w
}

func (w *notifyWatcher) loop() error {
	// No results for this watcher type.
	w.newResult = func() interface{} { return nil }
	w.call = func(request string, result interface{}) error {
		return w.caller.Call("NotifyWatcher", w.notifyWatcherId, request, nil, &result)
	}
	w.commonWatcher.init()
	// We have to add a wait group here, otherwise we aren't guaranteed to
	// ever call the commonLoop goroutines.
	w.wg.Add(1)
	go w.commonLoop()

	for {
		select {
		// Since for a notifyWatcher there are no changes to send, we
		// just set the event (initial first, then after each change).
		case w.out <- struct{}{}:
		case <-w.tomb.Dying():
			return nil
		}
		if _, ok := <-w.in; !ok {
			// The tomb is already killed with the correct
			// error at this point, so just return.
			return nil
		}
	}
	return nil
}

// Changes returns a channel that receives a value when a given entity
// changes in some way.
func (w *notifyWatcher) Changes() <-chan struct{} {
	return w.out
}

// stringsWatcher will send events when something changes.
// The content of the changes is a list of strings.
type stringsWatcher struct {
	commonWatcher
	caller           base.Caller
	stringsWatcherId string
	out              chan []string
}

func NewStringsWatcher(caller base.Caller, result params.StringsWatchResult) StringsWatcher {
	w := &stringsWatcher{
		caller:           caller,
		stringsWatcherId: result.StringsWatcherId,
		out:              make(chan []string),
	}
	go func() {
		defer w.tomb.Done()
		defer close(w.out)
		w.tomb.Kill(w.loop(result.Changes))
	}()
	return w
}

func (w *stringsWatcher) loop(initialChanges []string) error {
	changes := initialChanges
	w.newResult = func() interface{} { return new(params.StringsWatchResult) }
	w.call = func(request string, result interface{}) error {
		return w.caller.Call("StringsWatcher", w.stringsWatcherId, request, nil, &result)
	}
	w.commonWatcher.init()
	// We have to add a wait group here, otherwise we aren't guaranteed to
	// ever call the commonLoop goroutines.
	w.wg.Add(1)
	go w.commonLoop()

	for {
		select {
		// Send the initial event or subsequent change.
		case w.out <- changes:
		case <-w.tomb.Dying():
			return nil
		}
		// Read the next change.
		data, ok := <-w.in
		if !ok {
			// The tomb is already killed with the correct error
			// at this point, so just return.
			return nil
		}
		changes = data.(*params.StringsWatchResult).Changes
	}
	return nil
}

// Changes returns a channel that receives a list of strings of watched
// entites with changes.
func (w *stringsWatcher) Changes() <-chan []string {
	return w.out
}

// relationUnitsWatcher will sends notifications of units entering and
// leaving the scope of a RelationUnit, and changes to the settings of
// those units known to have entered.
type relationUnitsWatcher struct {
	commonWatcher
	caller                 base.Caller
	relationUnitsWatcherId string
	out                    chan params.RelationUnitsChange
}

func NewRelationUnitsWatcher(caller base.Caller, result params.RelationUnitsWatchResult) RelationUnitsWatcher {
	w := &relationUnitsWatcher{
		caller:                 caller,
		relationUnitsWatcherId: result.RelationUnitsWatcherId,
		out: make(chan params.RelationUnitsChange),
	}
	go func() {
		defer w.tomb.Done()
		defer close(w.out)
		w.tomb.Kill(w.loop(result.Changes))
	}()
	return w
}

func (w *relationUnitsWatcher) loop(initialChanges params.RelationUnitsChange) error {
	changes := initialChanges
	w.newResult = func() interface{} { return new(params.RelationUnitsWatchResult) }
	w.call = func(request string, result interface{}) error {
		return w.caller.Call("RelationUnitsWatcher", w.relationUnitsWatcherId, request, nil, &result)
	}
	w.commonWatcher.init()
	// We have to add a wait group here, otherwise we aren't guaranteed to
	// ever call the commonLoop goroutines.
	w.wg.Add(1)
	go w.commonLoop()

	for {
		select {
		// Send the initial event or subsequent change.
		case w.out <- changes:
		case <-w.tomb.Dying():
			return nil
		}
		// Read the next change.
		data, ok := <-w.in
		if !ok {
			// The tomb is already killed with the correct error
			// at this point, so just return.
			return nil
		}
		changes = data.(*params.RelationUnitsWatchResult).Changes
	}
	return nil
}

// Changes returns a channel that will receive the changes to
// counterpart units in a relation. The first event on the channel
// holds the initial state of the relation in its Changed field.
func (w *relationUnitsWatcher) Changes() <-chan params.RelationUnitsChange {
	return w.out
}
<commit_msg>make the WaitGroup a local var, which leaves the tests passing, and avoids the possible race condition.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package watcher

import (
	"sync"

	"github.com/juju/loggo"
	"launchpad.net/tomb"

	"github.com/juju/juju/state/api/base"
	"github.com/juju/juju/state/api/params"
)

var logger = loggo.GetLogger("juju.state.api.watcher")

// commonWatcher implements common watcher logic in one place to
// reduce code duplication, but it's not in fact a complete watcher;
// it's intended for embedding.
type commonWatcher struct {
	tomb tomb.Tomb
	in   chan interface{}

	// These fields must be set by the embedding watcher, before
	// calling init().

	// newResult must return a pointer to a value of the type returned
	// by the watcher's Next call.
	newResult func() interface{}

	// call should invoke the given API method, placing the call's
	// returned value in result (if any).
	call func(method string, result interface{}) error
}

// init must be called to initialize an embedded commonWatcher's
// fields. Make sure newResult and call fields are set beforehand.
func (w *commonWatcher) init() {
	w.in = make(chan interface{})
	if w.newResult == nil {
		panic("newResult must me set")
	}
	if w.call == nil {
		panic("call must be set")
	}
}

// commonLoop implements the loop structure common to the client
// watchers. It should be started in a separate goroutine by any
// watcher that embeds commonWatcher. It kills the commonWatcher's
// tomb when an error occurs.
func (w *commonWatcher) commonLoop() {
	defer close(w.in)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		// When the watcher has been stopped, we send a Stop request
		// to the server, which will remove the watcher and return a
		// CodeStopped error to any currently outstanding call to
		// Next. If a call to Next happens just after the watcher has
		// been stopped, we'll get a CodeNotFound error; Either way
		// we'll return, wait for the stop request to complete, and
		// the watcher will die with all resources cleaned up.
		defer wg.Done()
		<-w.tomb.Dying()
		if err := w.call("Stop", nil); err != nil {
			logger.Errorf("error trying to stop watcher: %v", err)
		}
	}()
	wg.Add(1)
	go func() {
		// Because Next blocks until there are changes, we need to
		// call it in a separate goroutine, so the watcher can be
		// stopped normally.
		defer wg.Done()
		for {
			result := w.newResult()
			err := w.call("Next", &result)
			if err != nil {
				if params.IsCodeStopped(err) || params.IsCodeNotFound(err) {
					if w.tomb.Err() != tomb.ErrStillAlive {
						// The watcher has been stopped at the client end, so we're
						// expecting one of the above two kinds of error.
						// We might see the same errors if the server itself
						// has been shut down, in which case we leave them
						// untouched.
						err = tomb.ErrDying
					}
				}
				// Something went wrong, just report the error and bail out.
				w.tomb.Kill(err)
				return
			}
			select {
			case <-w.tomb.Dying():
				return
			case w.in <- result:
				// Report back the result we just got.
			}
		}
	}()
	wg.Wait()
}

func (w *commonWatcher) Stop() error {
	w.tomb.Kill(nil)
	return w.tomb.Wait()
}

func (w *commonWatcher) Err() error {
	return w.tomb.Err()
}

// notifyWatcher will send events when something changes.
// It does not send content for those changes.
type notifyWatcher struct {
	commonWatcher
	caller          base.Caller
	notifyWatcherId string
	out             chan struct{}
}

// If an API call returns a NotifyWatchResult, you can use this to turn it into
// a local Watcher.
func NewNotifyWatcher(caller base.Caller, result params.NotifyWatchResult) NotifyWatcher {
	w := &notifyWatcher{
		caller:          caller,
		notifyWatcherId: result.NotifyWatcherId,
		out:             make(chan struct{}),
	}
	go func() {
		defer w.tomb.Done()
		defer close(w.out)
		w.tomb.Kill(w.loop())
	}()
	return w
}

func (w *notifyWatcher) loop() error {
	// No results for this watcher type.
	w.newResult = func() interface{} { return nil }
	w.call = func(request string, result interface{}) error {
		return w.caller.Call("NotifyWatcher", w.notifyWatcherId, request, nil, &result)
	}
	w.commonWatcher.init()
	go w.commonLoop()

	for {
		select {
		// Since for a notifyWatcher there are no changes to send, we
		// just set the event (initial first, then after each change).
		case w.out <- struct{}{}:
		case <-w.tomb.Dying():
			return nil
		}
		if _, ok := <-w.in; !ok {
			// The tomb is already killed with the correct
			// error at this point, so just return.
			return nil
		}
	}
	return nil
}

// Changes returns a channel that receives a value when a given entity
// changes in some way.
func (w *notifyWatcher) Changes() <-chan struct{} {
	return w.out
}

// stringsWatcher will send events when something changes.
// The content of the changes is a list of strings.
type stringsWatcher struct {
	commonWatcher
	caller           base.Caller
	stringsWatcherId string
	out              chan []string
}

func NewStringsWatcher(caller base.Caller, result params.StringsWatchResult) StringsWatcher {
	w := &stringsWatcher{
		caller:           caller,
		stringsWatcherId: result.StringsWatcherId,
		out:              make(chan []string),
	}
	go func() {
		defer w.tomb.Done()
		defer close(w.out)
		w.tomb.Kill(w.loop(result.Changes))
	}()
	return w
}

func (w *stringsWatcher) loop(initialChanges []string) error {
	changes := initialChanges
	w.newResult = func() interface{} { return new(params.StringsWatchResult) }
	w.call = func(request string, result interface{}) error {
		return w.caller.Call("StringsWatcher", w.stringsWatcherId, request, nil, &result)
	}
	w.commonWatcher.init()
	go w.commonLoop()

	for {
		select {
		// Send the initial event or subsequent change.
		case w.out <- changes:
		case <-w.tomb.Dying():
			return nil
		}
		// Read the next change.
		data, ok := <-w.in
		if !ok {
			// The tomb is already killed with the correct error
			// at this point, so just return.
			return nil
		}
		changes = data.(*params.StringsWatchResult).Changes
	}
	return nil
}

// Changes returns a channel that receives a list of strings of watched
// entites with changes.
func (w *stringsWatcher) Changes() <-chan []string {
	return w.out
}

// relationUnitsWatcher will sends notifications of units entering and
// leaving the scope of a RelationUnit, and changes to the settings of
// those units known to have entered.
type relationUnitsWatcher struct {
	commonWatcher
	caller                 base.Caller
	relationUnitsWatcherId string
	out                    chan params.RelationUnitsChange
}

func NewRelationUnitsWatcher(caller base.Caller, result params.RelationUnitsWatchResult) RelationUnitsWatcher {
	w := &relationUnitsWatcher{
		caller:                 caller,
		relationUnitsWatcherId: result.RelationUnitsWatcherId,
		out: make(chan params.RelationUnitsChange),
	}
	go func() {
		defer w.tomb.Done()
		defer close(w.out)
		w.tomb.Kill(w.loop(result.Changes))
	}()
	return w
}

func (w *relationUnitsWatcher) loop(initialChanges params.RelationUnitsChange) error {
	changes := initialChanges
	w.newResult = func() interface{} { return new(params.RelationUnitsWatchResult) }
	w.call = func(request string, result interface{}) error {
		return w.caller.Call("RelationUnitsWatcher", w.relationUnitsWatcherId, request, nil, &result)
	}
	w.commonWatcher.init()
	go w.commonLoop()

	for {
		select {
		// Send the initial event or subsequent change.
		case w.out <- changes:
		case <-w.tomb.Dying():
			return nil
		}
		// Read the next change.
		data, ok := <-w.in
		if !ok {
			// The tomb is already killed with the correct error
			// at this point, so just return.
			return nil
		}
		changes = data.(*params.RelationUnitsWatchResult).Changes
	}
	return nil
}

// Changes returns a channel that will receive the changes to
// counterpart units in a relation. The first event on the channel
// holds the initial state of the relation in its Changed field.
func (w *relationUnitsWatcher) Changes() <-chan params.RelationUnitsChange {
	return w.out
}
<|endoftext|>


<commit_before>package geom

import (
	"fmt"
	"sort"
)

// GetConvexHull pnts sorted in ccw
func GetConvexHull(pnts []Pnt) []Pnt {
	sort.Sort(ByXThenY(pnts))
	count := len(pnts)
	p1 := pnts[0]
	pn := pnts[count-1]
	ePnts := make([]Pnt, 0)
	pnts1 := make([]Pnt, 0)
	pnts2 := make([]Pnt, 0)
	for i := 1; i < count-1; i++ {
		d := areaWithSymbol(p1, pn, pnts[i])
		if d > 0 {
			pnts1 = append(pnts1, pnts[i])
		} else if d < 0 {
			pnts2 = append(pnts2, pnts[i])
		}
	}
	ePnts = append(ePnts, p1)
	ePnts1 := convexHull(p1, pn, pnts1)
	ePnts = append(ePnts, ePnts1...)
	ePnts = append(ePnts, pn)
	ePnts2 := convexHull(pn, p1, pnts2)
	ePnts = append(ePnts, ePnts2...)
	return ePnts
}

func convexHull(p1, pn Pnt, pnts []Pnt) []Pnt {
	ePnts := make([]Pnt, 0)
	count := len(pnts)
	//fmt.Println("total... ", p1, pn, pnts)
	if count == 0 {
		return ePnts
	}
	if count == 1 {
		ePnts = append(ePnts, pnts[0])
		//fmt.Println("1 Pnt: ", pnts[0])
		return ePnts
	}
	dist0 := 0.0
	maxIndex := -1
	for i := 0; i < count; i++ {
		d := areaWithSymbol(p1, pn, pnts[i])
		d0 := d
		if d < 0 {
			d0 = -d
		}
		if d0 > dist0 {
			dist0 = d0
			maxIndex = i
		}
	}

	pmax := pnts[maxIndex]
	fmt.Println("pmax for ", p1, pn, ": ", pmax, len(pnts))

	pnts1, pnts2 := splitPnts(p1, pmax, pn, maxIndex, pnts)

	ps1 := convexHull(p1, pmax, pnts1)
	ePnts = append(ePnts, ps1...)
	ePnts = append(ePnts, pmax)
	ps2 := convexHull(pmax, pn, pnts2)
	ePnts = append(ePnts, ps2...)
	return ePnts
}

func splitPnts(p1, pmax, pn Pnt, maxIndex int, pnts []Pnt) ([]Pnt, []Pnt) {
	pnts1 := make([]Pnt, 0)
	pnts2 := make([]Pnt, 0)
	count := len(pnts)
	for i := 0; i < count; i++ {
		if i == maxIndex {
			continue
		}
		d := areaWithSymbol(p1, pmax, pnts[i])
		if d > 0 {
			pnts1 = append(pnts1, pnts[i])
		} else {
			d1 := areaWithSymbol(pmax, pn, pnts[i])
			if d1 > 0 {
				pnts2 = append(pnts2, pnts[i])
			}
		}
	}
	return pnts1, pnts2
}

func areaWithSymbol(p1, p2, p3 Pnt) float64 {
	x1 := p1.X
	y1 := p1.Y
	x2 := p2.X
	y2 := p2.Y
	x3 := p3.X
	y3 := p3.Y
	return x1*y2 + x3*y1 + x2*y3 - x3*y2 - x2*y1 - x1*y3
}

// GetConvexHullExtremePnts no sorting
func GetConvexHullExtremePnts(pnts []Pnt) []Pnt {

	count := len(pnts)
	ind1 := make([]int, 0)
	ind2 := make([]int, 0)
	for i := 0; i < count-1; i++ {
		x1 := pnts[i].X
		y1 := pnts[i].Y
		for j := i + 1; j < count; j++ {
			x2 := pnts[j].X
			y2 := pnts[j].Y
			a := y2 - y1
			b := x1 - x2
			c := x1*y2 - y1*x2
			dCount := 0
			ok := true
			d0 := 0.0
			for k := 0; k < count; k++ {
				if k == i || k == j {
					continue
				}
				x3 := pnts[k].X
				y3 := pnts[k].Y
				d := a*x3 + b*y3 - c
				if dCount == 0 {
					d0 = d
					dCount++
				} else if d0*d <= 0 { // not at the same side
					ok = false
					break
				}
			}
			if ok {
				ind1 = append(ind1, i)
				ind2 = append(ind2, j)
			}
		}
	}
	indices := make([]int, 0)
	indices1 := make(map[int]bool)
	indices2 := make(map[int]bool)
	indices = append(indices, ind1[0])
	indices = append(indices, ind2[0])
	indices1[0] = true
	indices2[0] = true
	for {
		canBreak := false
		for i := 0; i < len(ind1); i++ {
			_, has := indices1[i]
			if !has {
				if indices[len(indices)-1] == ind1[i] {
					iii := ind2[i]
					if iii == indices[0] {
						canBreak = true
						break
					}
					indices = append(indices, iii)
					indices2[i] = true
					break
				}
			}
			_, has = indices2[i]
			if !has {
				if indices[len(indices)-1] == ind2[i] {
					iii := ind1[i]
					if iii == indices[0] {
						canBreak = true
						break
					}
					indices = append(indices, iii)
					indices1[i] = true
					break
				}
			}
		}
		if canBreak {
			break
		}
	}
	ePnts := make([]Pnt, len(indices))
	for i := 0; i < len(indices); i++ {
		ePnts[i] = pnts[indices[i]]
	}
	return ePnts

}
<commit_msg>fix comment for brute-force convex-hull<commit_after>package geom

import (
	"fmt"
	"sort"
)

// GetConvexHull pnts sorted in ccw
func GetConvexHull(pnts []Pnt) []Pnt {
	sort.Sort(ByXThenY(pnts))
	count := len(pnts)
	p1 := pnts[0]
	pn := pnts[count-1]
	ePnts := make([]Pnt, 0)
	pnts1 := make([]Pnt, 0)
	pnts2 := make([]Pnt, 0)
	for i := 1; i < count-1; i++ {
		d := areaWithSymbol(p1, pn, pnts[i])
		if d > 0 {
			pnts1 = append(pnts1, pnts[i])
		} else if d < 0 {
			pnts2 = append(pnts2, pnts[i])
		}
	}
	ePnts = append(ePnts, p1)
	ePnts1 := convexHull(p1, pn, pnts1)
	ePnts = append(ePnts, ePnts1...)
	ePnts = append(ePnts, pn)
	ePnts2 := convexHull(pn, p1, pnts2)
	ePnts = append(ePnts, ePnts2...)
	return ePnts
}

func convexHull(p1, pn Pnt, pnts []Pnt) []Pnt {
	ePnts := make([]Pnt, 0)
	count := len(pnts)
	//fmt.Println("total... ", p1, pn, pnts)
	if count == 0 {
		return ePnts
	}
	if count == 1 {
		ePnts = append(ePnts, pnts[0])
		//fmt.Println("1 Pnt: ", pnts[0])
		return ePnts
	}
	dist0 := 0.0
	maxIndex := -1
	for i := 0; i < count; i++ {
		d := areaWithSymbol(p1, pn, pnts[i])
		d0 := d
		if d < 0 {
			d0 = -d
		}
		if d0 > dist0 {
			dist0 = d0
			maxIndex = i
		}
	}

	pmax := pnts[maxIndex]
	fmt.Println("pmax for ", p1, pn, ": ", pmax, len(pnts))

	pnts1, pnts2 := splitPnts(p1, pmax, pn, maxIndex, pnts)

	ps1 := convexHull(p1, pmax, pnts1)
	ePnts = append(ePnts, ps1...)
	ePnts = append(ePnts, pmax)
	ps2 := convexHull(pmax, pn, pnts2)
	ePnts = append(ePnts, ps2...)
	return ePnts
}

func splitPnts(p1, pmax, pn Pnt, maxIndex int, pnts []Pnt) ([]Pnt, []Pnt) {
	pnts1 := make([]Pnt, 0)
	pnts2 := make([]Pnt, 0)
	count := len(pnts)
	for i := 0; i < count; i++ {
		if i == maxIndex {
			continue
		}
		d := areaWithSymbol(p1, pmax, pnts[i])
		if d > 0 {
			pnts1 = append(pnts1, pnts[i])
		} else {
			d1 := areaWithSymbol(pmax, pn, pnts[i])
			if d1 > 0 {
				pnts2 = append(pnts2, pnts[i])
			}
		}
	}
	return pnts1, pnts2
}

func areaWithSymbol(p1, p2, p3 Pnt) float64 {
	x1 := p1.X
	y1 := p1.Y
	x2 := p2.X
	y2 := p2.Y
	x3 := p3.X
	y3 := p3.Y
	return x1*y2 + x3*y1 + x2*y3 - x3*y2 - x2*y1 - x1*y3
}

// GetConvexHullExtremePnts now pnts can linked by lines with indices, but no ccw guaranteed
func GetConvexHullExtremePnts(pnts []Pnt) []Pnt {

	count := len(pnts)
	ind1 := make([]int, 0)
	ind2 := make([]int, 0)
	for i := 0; i < count-1; i++ {
		x1 := pnts[i].X
		y1 := pnts[i].Y
		for j := i + 1; j < count; j++ {
			x2 := pnts[j].X
			y2 := pnts[j].Y
			a := y2 - y1
			b := x1 - x2
			c := x1*y2 - y1*x2
			dCount := 0
			ok := true
			d0 := 0.0
			for k := 0; k < count; k++ {
				if k == i || k == j {
					continue
				}
				x3 := pnts[k].X
				y3 := pnts[k].Y
				d := a*x3 + b*y3 - c
				if dCount == 0 {
					d0 = d
					dCount++
				} else if d0*d <= 0 { // not at the same side
					ok = false
					break
				}
			}
			if ok {
				ind1 = append(ind1, i)
				ind2 = append(ind2, j)
			}
		}
	}
	indices := make([]int, 0)
	indices1 := make(map[int]bool)
	indices2 := make(map[int]bool)
	indices = append(indices, ind1[0])
	indices = append(indices, ind2[0])
	indices1[0] = true
	indices2[0] = true
	for {
		canBreak := false
		for i := 0; i < len(ind1); i++ {
			_, has := indices1[i]
			if !has {
				if indices[len(indices)-1] == ind1[i] {
					iii := ind2[i]
					if iii == indices[0] {
						canBreak = true
						break
					}
					indices = append(indices, iii)
					indices2[i] = true
					break
				}
			}
			_, has = indices2[i]
			if !has {
				if indices[len(indices)-1] == ind2[i] {
					iii := ind1[i]
					if iii == indices[0] {
						canBreak = true
						break
					}
					indices = append(indices, iii)
					indices1[i] = true
					break
				}
			}
		}
		if canBreak {
			break
		}
	}
	ePnts := make([]Pnt, len(indices))
	for i := 0; i < len(indices); i++ {
		ePnts[i] = pnts[indices[i]]
	}
	return ePnts

}
<|endoftext|>