<commit_before>// Get the number of open files for a process and compare that against /proc/<pid>/limits and alert if
// over the given threshold.
//
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"flag"
	"fmt"
	"github.com/yieldbot/ybsensupluginfile/cmd/check-file-handles/Godeps/_workspace/src/github.com/yieldbot/ybsensuplugin/ybsensupluginutil"
	"github.com/yieldbot/ybsensupluginfile/cmd/check-file-handles/Godeps/_workspace/src/github.com/yieldbot/ybsensupluginfile/ybfilesys"
	// "os"
)

// Calculate if the value is over a threshold
func determineThreshold(limit float64, threshold float64, numFD float64) bool {
	alarm := true
	tLimit := threshold / float64(100) * limit

	if numFD > float64(tLimit) {
		alarm = true
	} else {
		alarm = false
	}
	return alarm
}

func main() {

	// set commandline flags
	AppPtr := flag.String("app", "sbin/init", "the process name")
	WarnPtr := flag.Int("warn", 75, "the alert warning threshold percentage")
	CritPtr := flag.Int("crit", 75, "the alert critical threshold percentage")
	DebugPtr := flag.Bool("debug", false, "print debugging info instead of an alert")
	JavaAppPtr := flag.Bool("java", false, "java apps process detection is different")

	flag.Parse()
	app := *AppPtr
	warnThreshold := *WarnPtr
	critThreshold := *CritPtr
	ybsensupluginutil.Debug = *DebugPtr
	ybfilesys.JavaApp = *JavaAppPtr

	var appPid string
	var sLimit, hLimit, openFd float64

	if app != "" {
		appPid = ybfilesys.GetPid(app)
		sLimit, hLimit, openFd = ybfilesys.GetFileHandles(appPid)
		if ybsensupluginutil.Debug {
			fmt.Printf("warning threshold: %v percent, critical threshold: %v percent\n", warnThreshold, critThreshold)
			fmt.Printf("this is the number of open files at the specific point in time: %v\n", openFd)
			fmt.Printf("app pid is: %v\n", appPid)
			fmt.Printf("This is the soft limit: %v\n", sLimit)
			fmt.Printf("This is the hard limit: %v\n", hLimit)
			ybsensupluginutil.Exit("ok")
		}
		if determineThreshold(hLimit, float64(critThreshold), openFd) {
			fmt.Printf("%v is over %v percent of the the open file handles hard limit of %v\n", app, critThreshold, hLimit)
			ybsensupluginutil.Exit("critical")
		} else if determineThreshold(sLimit, float64(warnThreshold), openFd) {
			fmt.Printf("%v is over %v percent of the open file handles soft limit of %v\n", app, warnThreshold, sLimit)
			ybsensupluginutil.Exit("warning")
		} else {
			fmt.Printf("There was an error calculating the thresholds. Check to make sure everything got convert to a float64.\n")
			fmt.Printf("If unsure of the use, consult the documentation for examples and requirements\n")
			ybsensupluginutil.Exit(42)
		}
	} else {
		fmt.Printf("Please enter a process name to check. \n")
		fmt.Printf("If unsure consult the documentation for examples and requirements\n")
		ybsensupluginutil.Exit(127)
	}
}
<commit_msg>comments<commit_after>// Get the number of open files for a process and compare that against /proc/<pid>/limits and alert if
// over the given threshold.
//
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"flag"
	"fmt"
	"github.com/yieldbot/ybsensupluginfile/cmd/check-file-handles/Godeps/_workspace/src/github.com/yieldbot/ybsensuplugin/ybsensupluginutil"
	"github.com/yieldbot/ybsensupluginfile/cmd/check-file-handles/Godeps/_workspace/src/github.com/yieldbot/ybsensupluginfile/ybfilesys"
	// "os"
)

// Calculate if the value is over a threshold
func determineThreshold(limit float64, threshold float64, numFD float64) bool {
	alarm := true
	tLimit := threshold / float64(100) * limit

	if numFD > float64(tLimit) {
		alarm = true
	} else {
		alarm = false
	}
	return alarm
}

func main() {

	// set commandline flags
	AppPtr := flag.String("app", "sbin/init", "the process name")
	WarnPtr := flag.Int("warn", 75, "the alert warning threshold percentage")
	CritPtr := flag.Int("crit", 75, "the alert critical threshold percentage")
	DebugPtr := flag.Bool("debug", false, "print debugging info instead of an alert")
	JavaAppPtr := flag.Bool("java", false, "java apps process detection is different")

	flag.Parse()
	app := *AppPtr
	warnThreshold := *WarnPtr
	critThreshold := *CritPtr
	ybsensupluginutil.Debug = *DebugPtr
	ybfilesys.JavaApp = *JavaAppPtr

	var appPid string
	var sLimit, hLimit, openFd float64

  // need to find a way to get the printf stuff into the sensu exit function
	if app != "" {
		appPid = ybfilesys.GetPid(app)
		sLimit, hLimit, openFd = ybfilesys.GetFileHandles(appPid)
		if ybsensupluginutil.Debug {
			fmt.Printf("warning threshold: %v percent, critical threshold: %v percent\n", warnThreshold, critThreshold)
			fmt.Printf("this is the number of open files at the specific point in time: %v\n", openFd)
			fmt.Printf("app pid is: %v\n", appPid)
			fmt.Printf("This is the soft limit: %v\n", sLimit)
			fmt.Printf("This is the hard limit: %v\n", hLimit)
			ybsensupluginutil.Exit("ok")
		}
		if determineThreshold(hLimit, float64(critThreshold), openFd) {
			fmt.Printf("%v is over %v percent of the the open file handles hard limit of %v\n", app, critThreshold, hLimit)
			ybsensupluginutil.Exit("critical")
		} else if determineThreshold(sLimit, float64(warnThreshold), openFd) {
			fmt.Printf("%v is over %v percent of the open file handles soft limit of %v\n", app, warnThreshold, sLimit)
			ybsensupluginutil.Exit("warning")
		} else {
			fmt.Printf("There was an error calculating the thresholds. Check to make sure everything got convert to a float64.\n")
			fmt.Printf("If unsure of the use, consult the documentation for examples and requirements\n")
			ybsensupluginutil.Exit(42)
		}
	} else {
		fmt.Printf("Please enter a process name to check. \n")
		fmt.Printf("If unsure consult the documentation for examples and requirements\n")
		ybsensupluginutil.Exit(127)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2022 The cert-manager Authors.

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

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

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

package migrate

import (
	"context"
	"fmt"

	"github.com/spf13/cobra"
	apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/jetstack/cert-manager/cmd/ctl/pkg/build"
	"github.com/jetstack/cert-manager/cmd/ctl/pkg/factory"
	acmeinstall "github.com/jetstack/cert-manager/internal/apis/acme/install"
	cminstall "github.com/jetstack/cert-manager/internal/apis/certmanager/install"
)

var (
	long = templates.LongDesc(i18n.T(`
Ensures resources in your Kubernetes cluster are persisted in the v1 API version.

This must be run prior to upgrading to ensure your cluster is ready to upgrade to cert-manager v1.7 and beyond.

This command must be run with a cluster running cert-manager v1.0 or greater.`))

	example = templates.Examples(i18n.T(build.WithTemplate(`
# Check the cert-manager installation is ready to be upgraded to v1.7
{{.BuildName}} upgrade migrate
`)))
)

var scheme = runtime.NewScheme()

func init() {
	apiextinstall.Install(scheme)
	cminstall.Install(scheme)
	acmeinstall.Install(scheme)
}

// Options is a struct to support renew command
type Options struct {
	genericclioptions.IOStreams
	*factory.Factory

	client client.Client
}

// NewOptions returns initialized Options
func NewOptions(ioStreams genericclioptions.IOStreams) *Options {
	return &Options{
		IOStreams: ioStreams,
	}
}

// NewCmdMigrate returns a cobra command for updating resources in an apiserver
// to force a new storage version to be used.
func NewCmdMigrate(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewOptions(ioStreams)
	cmd := &cobra.Command{
		Use:     "migrate",
		Short:   "Migrate all existing persisted cert-manager resources to the v1 API version",
		Long:    long,
		Example: example,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Validate(cmd, args))
			cmdutil.CheckErr(o.Complete())
			cmdutil.CheckErr(o.Run(ctx, args))
		},
	}

	o.Factory = factory.New(ctx, cmd)

	return cmd
}

// Validate validates the provided options
func (o *Options) Validate(cmd *cobra.Command, args []string) error {
	return nil
}

// Complete takes the command arguments and factory and infers any remaining options.
func (o *Options) Complete() error {
	var err error
	o.client, err = client.New(o.RESTConfig, client.Options{Scheme: scheme})
	if err != nil {
		return err
	}

	return nil
}

// Run executes renew command
func (o *Options) Run(ctx context.Context, args []string) error {
	// Check all cert-manager CRDs to ensure that they have their
	// storage version set to v1.
	allCRDNames := []string{
		"certificates.cert-manager.io",
		"certificaterequests.cert-manager.io",
		"issuers.cert-manager.io",
		"clusterissuers.cert-manager.io",
		"orders.acme.cert-manager.io",
		"challenges.acme.cert-manager.io",
	}

	fmt.Fprintln(o.Out, "Checking all cert-manager CustomResourceDefinitions have storage version set to 'v1'")
	allV1, crdsRequiringMigration, err := o.ensureCRDStorageVersionEquals(ctx, "v1", allCRDNames)
	if err != nil {
		return err
	}
	if !allV1 {
		fmt.Fprintln(o.ErrOut, "It looks like you are running a pre-1.0 version of cert-manager. Please upgrade cert-manager to v1.6 before upgrading to v1.7.")
		return fmt.Errorf("migration failed")
	}
	fmt.Fprintln(o.Out, "All CustomResourceDefinitions have 'v1' configured as the storage version.")

	/*
		fmt.Fprintln(o.Out, "Looking for CRDs that contain resources that require migrating to 'v1'...")
		crdsRequiringMigration, err := o.discoverCRDsRequiringMigration(ctx, "v1", allCRDNames)
		if err != nil {
			fmt.Fprintf(o.ErrOut, "Failed to determine resource types that require migration: %v\n", err)
			return err
		}
		if len(crdsRequiringMigration) == 0 {
			fmt.Fprintln(o.Out, "Nothing to do. cert-manager CRDs do not have 'status.storedVersions' containing old API versions. You may proceed to upgrade to cert-manager v1.7.")
			return nil
		}
	*/

	fmt.Fprintf(o.Out, "Found %d resource types that require migration:\n", len(crdsRequiringMigration))
	for _, crd := range crdsRequiringMigration {
		fmt.Fprintf(o.Out, " - %s\n", crd.Name)
	}

	for _, crd := range crdsRequiringMigration {
		fmt.Fprintf(o.Out, "Migrating %q objects in group %q - this may take a while...\n", crd.Spec.Names.Kind, crd.Spec.Group)

		if err := o.migrateResourcesForCRD(ctx, crd); err != nil {
			fmt.Fprintf(o.ErrOut, "Failed to migrate resource: %v\n", err)
			return err
		}
	}

	fmt.Fprintln(o.Out, "Patching CRD resources to set 'status.storedVersions' to 'v1'...")
	if err := o.patchCRDStoredVersions(ctx, crdsRequiringMigration); err != nil {
		fmt.Fprintf(o.ErrOut, "Failed to patch 'status.storedVersions' field: %v\n", err)
		return err
	}

	fmt.Fprintln(o.Out, "Successfully migrated all cert-manager resource types. It is now safe to proceed with upgrading to cert-manager v1.7.")
	return nil
}

func (o *Options) ensureCRDStorageVersionEquals(ctx context.Context, vers string, names []string) (bool, []*apiext.CustomResourceDefinition, error) {
	var crds []*apiext.CustomResourceDefinition
	for _, crdName := range names {
		crd := &apiext.CustomResourceDefinition{}
		if err := o.client.Get(ctx, client.ObjectKey{Name: crdName}, crd); err != nil {
			return false, nil, err
		}

		// Discover the storage version
		storageVersion := ""
		for _, v := range crd.Spec.Versions {
			if v.Storage {
				storageVersion = v.Name
				break
			}
		}

		if storageVersion != vers {
			fmt.Fprintf(o.Out, "CustomResourceDefinition object %q has storage version set to %q. You MUST upgrade to cert-manager v1.0-v1.6 before migrating resources for v1.7.\n", crdName, storageVersion)
			return false, nil, nil
		}

		crds = append(crds, crd)
	}

	return true, crds, nil
}

func (o *Options) discoverCRDsRequiringMigration(ctx context.Context, desiredStorageVersion string, names []string) ([]*apiext.CustomResourceDefinition, error) {
	var requireMigration []*apiext.CustomResourceDefinition
	for _, name := range names {
		crd := &apiext.CustomResourceDefinition{}
		if err := o.client.Get(ctx, client.ObjectKey{Name: name}, crd); err != nil {
			return nil, err
		}
		// If no versions are stored, there's nothing to migrate.
		if len(crd.Status.StoredVersions) == 0 {
			continue
		}
		// If more than one entry exists in `storedVersions` OR if the only element in there is not
		// the desired version, perform a migration.
		if len(crd.Status.StoredVersions) > 1 || crd.Status.StoredVersions[0] != desiredStorageVersion {
			requireMigration = append(requireMigration, crd)
		}
	}
	return requireMigration, nil
}

func (o *Options) migrateResourcesForCRD(ctx context.Context, crd *apiext.CustomResourceDefinition) error {
	list := &unstructured.UnstructuredList{}
	list.SetGroupVersionKind(schema.GroupVersionKind{
		Group:   crd.Spec.Group,
		Version: "v1",
		Kind:    crd.Spec.Names.ListKind,
	})
	if err := o.client.List(ctx, list); err != nil {
		return err
	}
	fmt.Fprintf(o.Out, " %d resources to migrate\n", len(list.Items))
	for _, obj := range list.Items {
		if err := o.client.Update(ctx, &obj); handleUpdateErr(err) != nil {
			return err
		}
	}
	return nil
}

// handleUpdateErr will absorb certain types of errors that we know can be skipped/passed on
// during a migration of a particular object.
func handleUpdateErr(err error) error {
	if err == nil {
		return nil
	}
	// If the resource no longer exists, don't return the error as the object no longer
	// needs updating to the new API version.
	if apierrors.IsNotFound(err) {
		return nil
	}
	// If there was a conflict, another client must have written the object already which
	// means we don't need to force an update.
	if apierrors.IsConflict(err) {
		return nil
	}
	return err
}

func (o *Options) patchCRDStoredVersions(ctx context.Context, crds []*apiext.CustomResourceDefinition) error {
	for _, crd := range crds {
		// fetch a fresh copy of the CRD to avoid any conflict errors
		freshCRD := &apiext.CustomResourceDefinition{}
		if err := o.client.Get(ctx, client.ObjectKey{Name: crd.Name}, freshCRD); err != nil {
			return err
		}

		// Set the `status.storedVersions` field to 'v1'
		freshCRD.Status.StoredVersions = []string{"v1"}

		if err := o.client.Status().Update(ctx, freshCRD); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Print start time and how long it took to migrate resources<commit_after>/*
Copyright 2022 The cert-manager Authors.

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

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

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

package migrate

import (
	"context"
	"fmt"
	"time"

	"github.com/spf13/cobra"
	apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/jetstack/cert-manager/cmd/ctl/pkg/build"
	"github.com/jetstack/cert-manager/cmd/ctl/pkg/factory"
	acmeinstall "github.com/jetstack/cert-manager/internal/apis/acme/install"
	cminstall "github.com/jetstack/cert-manager/internal/apis/certmanager/install"
)

var (
	long = templates.LongDesc(i18n.T(`
Ensures resources in your Kubernetes cluster are persisted in the v1 API version.

This must be run prior to upgrading to ensure your cluster is ready to upgrade to cert-manager v1.7 and beyond.

This command must be run with a cluster running cert-manager v1.0 or greater.`))

	example = templates.Examples(i18n.T(build.WithTemplate(`
# Check the cert-manager installation is ready to be upgraded to v1.7
{{.BuildName}} upgrade migrate
`)))
)

var scheme = runtime.NewScheme()

func init() {
	apiextinstall.Install(scheme)
	cminstall.Install(scheme)
	acmeinstall.Install(scheme)
}

// Options is a struct to support renew command
type Options struct {
	genericclioptions.IOStreams
	*factory.Factory

	client client.Client
}

// NewOptions returns initialized Options
func NewOptions(ioStreams genericclioptions.IOStreams) *Options {
	return &Options{
		IOStreams: ioStreams,
	}
}

// NewCmdMigrate returns a cobra command for updating resources in an apiserver
// to force a new storage version to be used.
func NewCmdMigrate(ctx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewOptions(ioStreams)
	cmd := &cobra.Command{
		Use:     "migrate",
		Short:   "Migrate all existing persisted cert-manager resources to the v1 API version",
		Long:    long,
		Example: example,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Validate(cmd, args))
			cmdutil.CheckErr(o.Complete())
			cmdutil.CheckErr(o.Run(ctx, args))
		},
	}

	o.Factory = factory.New(ctx, cmd)

	return cmd
}

// Validate validates the provided options
func (o *Options) Validate(cmd *cobra.Command, args []string) error {
	return nil
}

// Complete takes the command arguments and factory and infers any remaining options.
func (o *Options) Complete() error {
	var err error
	o.client, err = client.New(o.RESTConfig, client.Options{Scheme: scheme})
	if err != nil {
		return err
	}

	return nil
}

// Run executes renew command
func (o *Options) Run(ctx context.Context, args []string) error {
	// Check all cert-manager CRDs to ensure that they have their
	// storage version set to v1.
	allCRDNames := []string{
		"certificates.cert-manager.io",
		"certificaterequests.cert-manager.io",
		"issuers.cert-manager.io",
		"clusterissuers.cert-manager.io",
		"orders.acme.cert-manager.io",
		"challenges.acme.cert-manager.io",
	}

	fmt.Fprintln(o.Out, "Checking all cert-manager CustomResourceDefinitions have storage version set to 'v1'")
	allV1, crdsRequiringMigration, err := o.ensureCRDStorageVersionEquals(ctx, "v1", allCRDNames)
	if err != nil {
		return err
	}
	if !allV1 {
		fmt.Fprintln(o.ErrOut, "It looks like you are running a pre-1.0 version of cert-manager. Please upgrade cert-manager to v1.6 before upgrading to v1.7.")
		return fmt.Errorf("migration failed")
	}
	fmt.Fprintln(o.Out, "All CustomResourceDefinitions have 'v1' configured as the storage version.")

	/*
		fmt.Fprintln(o.Out, "Looking for CRDs that contain resources that require migrating to 'v1'...")
		crdsRequiringMigration, err := o.discoverCRDsRequiringMigration(ctx, "v1", allCRDNames)
		if err != nil {
			fmt.Fprintf(o.ErrOut, "Failed to determine resource types that require migration: %v\n", err)
			return err
		}
		if len(crdsRequiringMigration) == 0 {
			fmt.Fprintln(o.Out, "Nothing to do. cert-manager CRDs do not have 'status.storedVersions' containing old API versions. You may proceed to upgrade to cert-manager v1.7.")
			return nil
		}
	*/

	fmt.Fprintf(o.Out, "Found %d resource types that require migration:\n", len(crdsRequiringMigration))
	for _, crd := range crdsRequiringMigration {
		fmt.Fprintf(o.Out, " - %s\n", crd.Name)
	}

	for _, crd := range crdsRequiringMigration {
		if err := o.migrateResourcesForCRD(ctx, crd); err != nil {
			fmt.Fprintf(o.ErrOut, "Failed to migrate resource: %v\n", err)
			return err
		}
	}

	fmt.Fprintln(o.Out, "Patching CRD resources to set 'status.storedVersions' to 'v1'...")
	if err := o.patchCRDStoredVersions(ctx, crdsRequiringMigration); err != nil {
		fmt.Fprintf(o.ErrOut, "Failed to patch 'status.storedVersions' field: %v\n", err)
		return err
	}

	fmt.Fprintln(o.Out, "Successfully migrated all cert-manager resource types. It is now safe to proceed with upgrading to cert-manager v1.7.")
	return nil
}

func (o *Options) ensureCRDStorageVersionEquals(ctx context.Context, vers string, names []string) (bool, []*apiext.CustomResourceDefinition, error) {
	var crds []*apiext.CustomResourceDefinition
	for _, crdName := range names {
		crd := &apiext.CustomResourceDefinition{}
		if err := o.client.Get(ctx, client.ObjectKey{Name: crdName}, crd); err != nil {
			return false, nil, err
		}

		// Discover the storage version
		storageVersion := ""
		for _, v := range crd.Spec.Versions {
			if v.Storage {
				storageVersion = v.Name
				break
			}
		}

		if storageVersion != vers {
			fmt.Fprintf(o.Out, "CustomResourceDefinition object %q has storage version set to %q. You MUST upgrade to cert-manager v1.0-v1.6 before migrating resources for v1.7.\n", crdName, storageVersion)
			return false, nil, nil
		}

		crds = append(crds, crd)
	}

	return true, crds, nil
}

func (o *Options) discoverCRDsRequiringMigration(ctx context.Context, desiredStorageVersion string, names []string) ([]*apiext.CustomResourceDefinition, error) {
	var requireMigration []*apiext.CustomResourceDefinition
	for _, name := range names {
		crd := &apiext.CustomResourceDefinition{}
		if err := o.client.Get(ctx, client.ObjectKey{Name: name}, crd); err != nil {
			return nil, err
		}
		// If no versions are stored, there's nothing to migrate.
		if len(crd.Status.StoredVersions) == 0 {
			continue
		}
		// If more than one entry exists in `storedVersions` OR if the only element in there is not
		// the desired version, perform a migration.
		if len(crd.Status.StoredVersions) > 1 || crd.Status.StoredVersions[0] != desiredStorageVersion {
			requireMigration = append(requireMigration, crd)
		}
	}
	return requireMigration, nil
}

func (o *Options) migrateResourcesForCRD(ctx context.Context, crd *apiext.CustomResourceDefinition) error {
	startTime := time.Now()
	fmt.Fprintf(o.Out, "Migrating %q objects in group %q - this may take a while (started at %s)...\n", crd.Spec.Names.Kind, crd.Spec.Group, startTime.Format(time.Stamp))
	list := &unstructured.UnstructuredList{}
	list.SetGroupVersionKind(schema.GroupVersionKind{
		Group:   crd.Spec.Group,
		Version: "v1",
		Kind:    crd.Spec.Names.ListKind,
	})
	if err := o.client.List(ctx, list); err != nil {
		return err
	}
	fmt.Fprintf(o.Out, " %d resources to migrate\n", len(list.Items))
	for _, obj := range list.Items {
		if err := o.client.Update(ctx, &obj); handleUpdateErr(err) != nil {
			return err
		}
	}
	fmt.Fprintf(o.Out, " Successfully migrated %d %s objects in %s\n", len(list.Items), crd.Spec.Names.Kind, time.Now().Sub(startTime).Round(time.Second))
	return nil
}

// handleUpdateErr will absorb certain types of errors that we know can be skipped/passed on
// during a migration of a particular object.
func handleUpdateErr(err error) error {
	if err == nil {
		return nil
	}
	// If the resource no longer exists, don't return the error as the object no longer
	// needs updating to the new API version.
	if apierrors.IsNotFound(err) {
		return nil
	}
	// If there was a conflict, another client must have written the object already which
	// means we don't need to force an update.
	if apierrors.IsConflict(err) {
		return nil
	}
	return err
}

func (o *Options) patchCRDStoredVersions(ctx context.Context, crds []*apiext.CustomResourceDefinition) error {
	for _, crd := range crds {
		// fetch a fresh copy of the CRD to avoid any conflict errors
		freshCRD := &apiext.CustomResourceDefinition{}
		if err := o.client.Get(ctx, client.ObjectKey{Name: crd.Name}, freshCRD); err != nil {
			return err
		}

		// Set the `status.storedVersions` field to 'v1'
		freshCRD.Status.StoredVersions = []string{"v1"}

		if err := o.client.Status().Update(ctx, freshCRD); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 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 app does all of the work necessary to create a Kubernetes
// APIServer by binding together the API, master and APIServer infrastructure.
// It can be configured and called directly or via the hyperkube cache.
package app

import (
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/pborman/uuid"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options"
	"k8s.io/kubernetes/pkg/admission"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apiserver/authenticator"
	apiserveropenapi "k8s.io/kubernetes/pkg/apiserver/openapi"
	authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union"
	"k8s.io/kubernetes/pkg/auth/user"
	"k8s.io/kubernetes/pkg/controller/informers"
	"k8s.io/kubernetes/pkg/generated/openapi"
	"k8s.io/kubernetes/pkg/genericapiserver"
	"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
	genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
	"k8s.io/kubernetes/pkg/registry/cachesize"
	"k8s.io/kubernetes/pkg/registry/generic"
	"k8s.io/kubernetes/pkg/registry/generic/registry"
	"k8s.io/kubernetes/pkg/routes"
	"k8s.io/kubernetes/pkg/util/wait"
	authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
)

// NewAPIServerCommand creates a *cobra.Command object with default parameters
func NewAPIServerCommand() *cobra.Command {
	s := options.NewServerRunOptions()
	s.AddFlags(pflag.CommandLine)
	cmd := &cobra.Command{
		Use: "federation-apiserver",
		Long: `The Kubernetes federation API server validates and configures data
for the api objects which include pods, services, replicationcontrollers, and
others. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
		Run: func(cmd *cobra.Command, args []string) {
		},
	}
	return cmd
}

// Run runs the specified APIServer.  This should never exit.
func Run(s *options.ServerRunOptions) error {
	genericvalidation.VerifyEtcdServersList(s.ServerRunOptions)
	genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions)
	genericConfig := genericapiserver.NewConfig(). // create the new config
							ApplyOptions(s.ServerRunOptions). // apply the options selected
							Complete()                        // set default values based on the known values

	if err := genericConfig.MaybeGenerateServingCerts(); err != nil {
		glog.Fatalf("Failed to generate service certificate: %v", err)
	}

	// TODO: register cluster federation resources here.
	resourceConfig := genericapiserver.NewResourceConfig()

	if s.StorageConfig.DeserializationCacheSize == 0 {
		// When size of cache is not explicitly set, set it to 50000
		s.StorageConfig.DeserializationCacheSize = 50000
	}
	storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion()
	if err != nil {
		glog.Fatalf("error generating storage version map: %s", err)
	}
	storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
		s.StorageConfig, s.DefaultStorageMediaType, api.Codecs,
		genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
		[]unversioned.GroupVersionResource{}, resourceConfig, s.RuntimeConfig)
	if err != nil {
		glog.Fatalf("error in initializing storage factory: %s", err)
	}

	for _, override := range s.EtcdServersOverrides {
		tokens := strings.Split(override, "#")
		if len(tokens) != 2 {
			glog.Errorf("invalid value of etcd server overrides: %s", override)
			continue
		}

		apiresource := strings.Split(tokens[0], "/")
		if len(apiresource) != 2 {
			glog.Errorf("invalid resource definition: %s", tokens[0])
			continue
		}
		group := apiresource[0]
		resource := apiresource[1]
		groupResource := unversioned.GroupResource{Group: group, Resource: resource}

		servers := strings.Split(tokens[1], ";")
		storageFactory.SetEtcdLocation(groupResource, servers)
	}

	apiAuthenticator, err := authenticator.New(authenticator.AuthenticatorConfig{
		Anonymous:         s.AnonymousAuth,
		AnyToken:          s.EnableAnyToken,
		BasicAuthFile:     s.BasicAuthFile,
		ClientCAFile:      s.ClientCAFile,
		TokenAuthFile:     s.TokenAuthFile,
		OIDCIssuerURL:     s.OIDCIssuerURL,
		OIDCClientID:      s.OIDCClientID,
		OIDCCAFile:        s.OIDCCAFile,
		OIDCUsernameClaim: s.OIDCUsernameClaim,
		OIDCGroupsClaim:   s.OIDCGroupsClaim,
		KeystoneURL:       s.KeystoneURL,
	})
	if err != nil {
		glog.Fatalf("Invalid Authentication Config: %v", err)
	}

	privilegedLoopbackToken := uuid.NewRandom().String()
	selfClientConfig, err := s.NewSelfClientConfig(privilegedLoopbackToken)
	if err != nil {
		glog.Fatalf("Failed to create clientset: %v", err)
	}
	client, err := s.NewSelfClient(privilegedLoopbackToken)
	if err != nil {
		glog.Errorf("Failed to create clientset: %v", err)
	}
	sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute)

	authorizationConfig := authorizer.AuthorizationConfig{
		PolicyFile:                  s.AuthorizationPolicyFile,
		WebhookConfigFile:           s.AuthorizationWebhookConfigFile,
		WebhookCacheAuthorizedTTL:   s.AuthorizationWebhookCacheAuthorizedTTL,
		WebhookCacheUnauthorizedTTL: s.AuthorizationWebhookCacheUnauthorizedTTL,
		RBACSuperUser:               s.AuthorizationRBACSuperUser,
		InformerFactory:             sharedInformers,
	}
	authorizationModeNames := strings.Split(s.AuthorizationMode, ",")
	apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig)
	if err != nil {
		glog.Fatalf("Invalid Authorization Config: %v", err)
	}

	admissionControlPluginNames := strings.Split(s.AdmissionControl, ",")

	// TODO(dims): We probably need to add an option "EnableLoopbackToken"
	if apiAuthenticator != nil {
		var uid = uuid.NewRandom().String()
		tokens := make(map[string]*user.DefaultInfo)
		tokens[privilegedLoopbackToken] = &user.DefaultInfo{
			Name:   user.APIServerUser,
			UID:    uid,
			Groups: []string{user.SystemPrivilegedGroup},
		}

		tokenAuthenticator := authenticator.NewAuthenticatorFromTokens(tokens)
		apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator)

		tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup)
		apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer)
	}

	pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)

	admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer)
	if err != nil {
		glog.Fatalf("Failed to initialize plugins: %v", err)
	}
	genericConfig.LoopbackClientConfig = selfClientConfig
	genericConfig.Authenticator = apiAuthenticator
	genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
	genericConfig.Authorizer = apiAuthorizer
	genericConfig.AuthorizerRBACSuperUser = s.AuthorizationRBACSuperUser
	genericConfig.AdmissionControl = admissionController
	genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
	genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
	genericConfig.OpenAPIConfig.Definitions = openapi.OpenAPIDefinitions
	// Reusing api-server's GetOperationID function. if federation and api-server spec diverge and
	// this method does not provide good operation IDs for federation, we should create federation's own GetOperationID.
	genericConfig.OpenAPIConfig.GetOperationID = apiserveropenapi.GetOperationID
	genericConfig.EnableOpenAPISupport = true

	// TODO: Move this to generic api server (Need to move the command line flag).
	if s.EnableWatchCache {
		cachesize.InitializeWatchCacheSizes(s.TargetRAMMB)
		cachesize.SetWatchCacheSizes(s.WatchCacheSizes)
	}

	m, err := genericConfig.New()
	if err != nil {
		return err
	}

	routes.UIRedirect{}.Install(m.HandlerContainer)
	routes.Logs{}.Install(m.HandlerContainer)

	restOptionsFactory := restOptionsFactory{
		storageFactory:          storageFactory,
		deleteCollectionWorkers: s.DeleteCollectionWorkers,
	}
	if s.EnableWatchCache {
		restOptionsFactory.storageDecorator = registry.StorageWithCacher
	} else {
		restOptionsFactory.storageDecorator = generic.UndecoratedStorage
	}

	installFederationAPIs(m, restOptionsFactory)
	installCoreAPIs(s, m, restOptionsFactory)
	installExtensionsAPIs(m, restOptionsFactory)

	sharedInformers.Start(wait.NeverStop)
	m.Run()
	return nil
}

type restOptionsFactory struct {
	storageFactory          genericapiserver.StorageFactory
	storageDecorator        generic.StorageDecorator
	deleteCollectionWorkers int
}

func (f restOptionsFactory) NewFor(resource unversioned.GroupResource) generic.RESTOptions {
	config, err := f.storageFactory.NewConfig(resource)
	if err != nil {
		glog.Fatalf("Unable to find storage config for %v, due to %v", resource, err.Error())
	}
	return generic.RESTOptions{
		StorageConfig:           config,
		Decorator:               f.storageDecorator,
		DeleteCollectionWorkers: f.deleteCollectionWorkers,
		ResourcePrefix:          f.storageFactory.ResourcePrefix(resource),
	}
}
<commit_msg>make version an explicit choice so zero config and customized work<commit_after>/*
Copyright 2014 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 app does all of the work necessary to create a Kubernetes
// APIServer by binding together the API, master and APIServer infrastructure.
// It can be configured and called directly or via the hyperkube cache.
package app

import (
	"strings"
	"time"

	"github.com/golang/glog"
	"github.com/pborman/uuid"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"k8s.io/kubernetes/federation/cmd/federation-apiserver/app/options"
	"k8s.io/kubernetes/pkg/admission"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apiserver/authenticator"
	apiserveropenapi "k8s.io/kubernetes/pkg/apiserver/openapi"
	authorizerunion "k8s.io/kubernetes/pkg/auth/authorizer/union"
	"k8s.io/kubernetes/pkg/auth/user"
	"k8s.io/kubernetes/pkg/controller/informers"
	"k8s.io/kubernetes/pkg/generated/openapi"
	"k8s.io/kubernetes/pkg/genericapiserver"
	"k8s.io/kubernetes/pkg/genericapiserver/authorizer"
	genericvalidation "k8s.io/kubernetes/pkg/genericapiserver/validation"
	"k8s.io/kubernetes/pkg/registry/cachesize"
	"k8s.io/kubernetes/pkg/registry/generic"
	"k8s.io/kubernetes/pkg/registry/generic/registry"
	"k8s.io/kubernetes/pkg/routes"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/version"
	authenticatorunion "k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/union"
)

// NewAPIServerCommand creates a *cobra.Command object with default parameters
func NewAPIServerCommand() *cobra.Command {
	s := options.NewServerRunOptions()
	s.AddFlags(pflag.CommandLine)
	cmd := &cobra.Command{
		Use: "federation-apiserver",
		Long: `The Kubernetes federation API server validates and configures data
for the api objects which include pods, services, replicationcontrollers, and
others. The API Server services REST operations and provides the frontend to the
cluster's shared state through which all other components interact.`,
		Run: func(cmd *cobra.Command, args []string) {
		},
	}
	return cmd
}

// Run runs the specified APIServer.  This should never exit.
func Run(s *options.ServerRunOptions) error {
	genericvalidation.VerifyEtcdServersList(s.ServerRunOptions)
	genericapiserver.DefaultAndValidateRunOptions(s.ServerRunOptions)
	genericConfig := genericapiserver.NewConfig(). // create the new config
							ApplyOptions(s.ServerRunOptions). // apply the options selected
							Complete()                        // set default values based on the known values

	if err := genericConfig.MaybeGenerateServingCerts(); err != nil {
		glog.Fatalf("Failed to generate service certificate: %v", err)
	}

	// TODO: register cluster federation resources here.
	resourceConfig := genericapiserver.NewResourceConfig()

	if s.StorageConfig.DeserializationCacheSize == 0 {
		// When size of cache is not explicitly set, set it to 50000
		s.StorageConfig.DeserializationCacheSize = 50000
	}
	storageGroupsToEncodingVersion, err := s.StorageGroupsToEncodingVersion()
	if err != nil {
		glog.Fatalf("error generating storage version map: %s", err)
	}
	storageFactory, err := genericapiserver.BuildDefaultStorageFactory(
		s.StorageConfig, s.DefaultStorageMediaType, api.Codecs,
		genericapiserver.NewDefaultResourceEncodingConfig(), storageGroupsToEncodingVersion,
		[]unversioned.GroupVersionResource{}, resourceConfig, s.RuntimeConfig)
	if err != nil {
		glog.Fatalf("error in initializing storage factory: %s", err)
	}

	for _, override := range s.EtcdServersOverrides {
		tokens := strings.Split(override, "#")
		if len(tokens) != 2 {
			glog.Errorf("invalid value of etcd server overrides: %s", override)
			continue
		}

		apiresource := strings.Split(tokens[0], "/")
		if len(apiresource) != 2 {
			glog.Errorf("invalid resource definition: %s", tokens[0])
			continue
		}
		group := apiresource[0]
		resource := apiresource[1]
		groupResource := unversioned.GroupResource{Group: group, Resource: resource}

		servers := strings.Split(tokens[1], ";")
		storageFactory.SetEtcdLocation(groupResource, servers)
	}

	apiAuthenticator, err := authenticator.New(authenticator.AuthenticatorConfig{
		Anonymous:         s.AnonymousAuth,
		AnyToken:          s.EnableAnyToken,
		BasicAuthFile:     s.BasicAuthFile,
		ClientCAFile:      s.ClientCAFile,
		TokenAuthFile:     s.TokenAuthFile,
		OIDCIssuerURL:     s.OIDCIssuerURL,
		OIDCClientID:      s.OIDCClientID,
		OIDCCAFile:        s.OIDCCAFile,
		OIDCUsernameClaim: s.OIDCUsernameClaim,
		OIDCGroupsClaim:   s.OIDCGroupsClaim,
		KeystoneURL:       s.KeystoneURL,
	})
	if err != nil {
		glog.Fatalf("Invalid Authentication Config: %v", err)
	}

	privilegedLoopbackToken := uuid.NewRandom().String()
	selfClientConfig, err := s.NewSelfClientConfig(privilegedLoopbackToken)
	if err != nil {
		glog.Fatalf("Failed to create clientset: %v", err)
	}
	client, err := s.NewSelfClient(privilegedLoopbackToken)
	if err != nil {
		glog.Errorf("Failed to create clientset: %v", err)
	}
	sharedInformers := informers.NewSharedInformerFactory(client, 10*time.Minute)

	authorizationConfig := authorizer.AuthorizationConfig{
		PolicyFile:                  s.AuthorizationPolicyFile,
		WebhookConfigFile:           s.AuthorizationWebhookConfigFile,
		WebhookCacheAuthorizedTTL:   s.AuthorizationWebhookCacheAuthorizedTTL,
		WebhookCacheUnauthorizedTTL: s.AuthorizationWebhookCacheUnauthorizedTTL,
		RBACSuperUser:               s.AuthorizationRBACSuperUser,
		InformerFactory:             sharedInformers,
	}
	authorizationModeNames := strings.Split(s.AuthorizationMode, ",")
	apiAuthorizer, err := authorizer.NewAuthorizerFromAuthorizationConfig(authorizationModeNames, authorizationConfig)
	if err != nil {
		glog.Fatalf("Invalid Authorization Config: %v", err)
	}

	admissionControlPluginNames := strings.Split(s.AdmissionControl, ",")

	// TODO(dims): We probably need to add an option "EnableLoopbackToken"
	if apiAuthenticator != nil {
		var uid = uuid.NewRandom().String()
		tokens := make(map[string]*user.DefaultInfo)
		tokens[privilegedLoopbackToken] = &user.DefaultInfo{
			Name:   user.APIServerUser,
			UID:    uid,
			Groups: []string{user.SystemPrivilegedGroup},
		}

		tokenAuthenticator := authenticator.NewAuthenticatorFromTokens(tokens)
		apiAuthenticator = authenticatorunion.New(tokenAuthenticator, apiAuthenticator)

		tokenAuthorizer := authorizer.NewPrivilegedGroups(user.SystemPrivilegedGroup)
		apiAuthorizer = authorizerunion.New(tokenAuthorizer, apiAuthorizer)
	}

	pluginInitializer := admission.NewPluginInitializer(sharedInformers, apiAuthorizer)

	admissionController, err := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile, pluginInitializer)
	if err != nil {
		glog.Fatalf("Failed to initialize plugins: %v", err)
	}

	kubeVersion := version.Get()
	genericConfig.Version = &kubeVersion
	genericConfig.LoopbackClientConfig = selfClientConfig
	genericConfig.Authenticator = apiAuthenticator
	genericConfig.SupportsBasicAuth = len(s.BasicAuthFile) > 0
	genericConfig.Authorizer = apiAuthorizer
	genericConfig.AuthorizerRBACSuperUser = s.AuthorizationRBACSuperUser
	genericConfig.AdmissionControl = admissionController
	genericConfig.APIResourceConfigSource = storageFactory.APIResourceConfigSource
	genericConfig.MasterServiceNamespace = s.MasterServiceNamespace
	genericConfig.OpenAPIConfig.Definitions = openapi.OpenAPIDefinitions
	// Reusing api-server's GetOperationID function. if federation and api-server spec diverge and
	// this method does not provide good operation IDs for federation, we should create federation's own GetOperationID.
	genericConfig.OpenAPIConfig.GetOperationID = apiserveropenapi.GetOperationID
	genericConfig.EnableOpenAPISupport = true

	// TODO: Move this to generic api server (Need to move the command line flag).
	if s.EnableWatchCache {
		cachesize.InitializeWatchCacheSizes(s.TargetRAMMB)
		cachesize.SetWatchCacheSizes(s.WatchCacheSizes)
	}

	m, err := genericConfig.New()
	if err != nil {
		return err
	}

	routes.UIRedirect{}.Install(m.HandlerContainer)
	routes.Logs{}.Install(m.HandlerContainer)

	restOptionsFactory := restOptionsFactory{
		storageFactory:          storageFactory,
		deleteCollectionWorkers: s.DeleteCollectionWorkers,
	}
	if s.EnableWatchCache {
		restOptionsFactory.storageDecorator = registry.StorageWithCacher
	} else {
		restOptionsFactory.storageDecorator = generic.UndecoratedStorage
	}

	installFederationAPIs(m, restOptionsFactory)
	installCoreAPIs(s, m, restOptionsFactory)
	installExtensionsAPIs(m, restOptionsFactory)

	sharedInformers.Start(wait.NeverStop)
	m.Run()
	return nil
}

type restOptionsFactory struct {
	storageFactory          genericapiserver.StorageFactory
	storageDecorator        generic.StorageDecorator
	deleteCollectionWorkers int
}

func (f restOptionsFactory) NewFor(resource unversioned.GroupResource) generic.RESTOptions {
	config, err := f.storageFactory.NewConfig(resource)
	if err != nil {
		glog.Fatalf("Unable to find storage config for %v, due to %v", resource, err.Error())
	}
	return generic.RESTOptions{
		StorageConfig:           config,
		Decorator:               f.storageDecorator,
		DeleteCollectionWorkers: f.deleteCollectionWorkers,
		ResourcePrefix:          f.storageFactory.ResourcePrefix(resource),
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	goflag "flag"
	"fmt"
	"io"
	"math/rand"
	"os"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	utilflag "k8s.io/component-base/cli/flag"
	"k8s.io/component-base/logs"
	"k8s.io/kubectl/pkg/util/templates"

	"github.com/openshift/library-go/pkg/serviceability"
	"github.com/openshift/origin/pkg/monitor"
	testginkgo "github.com/openshift/origin/pkg/test/ginkgo"
	exutil "github.com/openshift/origin/test/extended/util"
)

func main() {
	logs.InitLogs()
	defer logs.FlushLogs()

	rand.Seed(time.Now().UTC().UnixNano())

	pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)

	root := &cobra.Command{
		Long: templates.LongDesc(`
		OpenShift Tests

		This command verifies behavior of an OpenShift cluster by running remote tests against
		the cluster API that exercise functionality. In general these tests may be disruptive
		or require elevated privileges - see the descriptions of each test suite.
		`),
	}

	root.AddCommand(
		newRunCommand(),
		newRunUpgradeCommand(),
		newRunTestCommand(),
		newRunMonitorCommand(),
	)

	pflag.CommandLine = pflag.NewFlagSet("empty", pflag.ExitOnError)
	flag.CommandLine = flag.NewFlagSet("empty", flag.ExitOnError)
	exutil.InitStandardFlags()

	if err := func() error {
		defer serviceability.Profile(os.Getenv("OPENSHIFT_PROFILE")).Stop()
		return root.Execute()
	}(); err != nil {
		if ex, ok := err.(testginkgo.ExitError); ok {
			os.Exit(ex.Code)
		}
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

func newRunMonitorCommand() *cobra.Command {
	monitorOpt := &monitor.Options{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}
	cmd := &cobra.Command{
		Use:   "run-monitor",
		Short: "Continuously verify the cluster is functional",
		Long: templates.LongDesc(`
		Run a continuous verification process

		`),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return monitorOpt.Run()
		},
	}
	return cmd
}

func newRunCommand() *cobra.Command {
	opt := &testginkgo.Options{
		Suites: staticSuites,
	}

	cmd := &cobra.Command{
		Use:   "run SUITE",
		Short: "Run a test suite",
		Long: templates.LongDesc(`
		Run a test suite against an OpenShift server

		This command will run one of the following suites against a cluster identified by the current
		KUBECONFIG file. See the suite description for more on what actions the suite will take.

		If you specify the --dry-run argument, the names of each individual test that is part of the
		suite will be printed, one per line. You may filter this list and pass it back to the run
		command with the --file argument. You may also pipe a list of test names, one per line, on
		standard input by passing "-f -".

		`) + testginkgo.SuitesString(opt.Suites, "\n\nAvailable test suites:\n\n"),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return mirrorToFile(opt, func() error {
				config, err := decodeProvider(opt.Provider, opt.DryRun, true)
				if err != nil {
					return err
				}
				opt.Provider = config.ToJSONString()
				matchFn, err := initializeTestFramework(exutil.TestContext, config, opt.DryRun)
				if err != nil {
					return err
				}
				opt.MatchFn = matchFn
				return opt.Run(args)
			})
		},
	}
	bindOptions(opt, cmd.Flags())
	return cmd
}

func newRunUpgradeCommand() *cobra.Command {
	opt := &testginkgo.Options{Suites: upgradeSuites}
	upgradeOpt := &UpgradeOptions{}

	cmd := &cobra.Command{
		Use:   "run-upgrade SUITE",
		Short: "Run an upgrade suite",
		Long: templates.LongDesc(`
		Run an upgrade test suite against an OpenShift server

		This command will run one of the following suites against a cluster identified by the current
		KUBECONFIG file. See the suite description for more on what actions the suite will take.

		If you specify the --dry-run argument, the actions the suite will take will be printed to the
		output.

		Supported options:

		* abort-at=NUMBER - Set to a number between 0 and 100 to control the percent of operators
		at which to stop the current upgrade and roll back to the current version.
		* disrupt-reboot=POLICY - During upgrades, periodically reboot master nodes. If set to 'graceful'
		the reboot will allow the node to shut down services in an orderly fashion. If set to 'force' the
		machine will terminate immediately without clean shutdown.

		`) + testginkgo.SuitesString(opt.Suites, "\n\nAvailable upgrade suites:\n\n"),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return mirrorToFile(opt, func() error {
				if len(upgradeOpt.ToImage) == 0 {
					return fmt.Errorf("--to-image must be specified to run an upgrade test")
				}

				if len(args) > 0 {
					for _, suite := range opt.Suites {
						if suite.Name == args[0] {
							upgradeOpt.Suite = suite.Name
							upgradeOpt.JUnitDir = opt.JUnitDir
							value := upgradeOpt.ToEnv()
							if _, err := initUpgrade(value); err != nil {
								return err
							}
							opt.SuiteOptions = value
							break
						}
					}
				}

				config, err := decodeProvider(opt.Provider, opt.DryRun, true)
				if err != nil {
					return err
				}
				opt.Provider = config.ToJSONString()
				matchFn, err := initializeTestFramework(exutil.TestContext, config, opt.DryRun)
				if err != nil {
					return err
				}
				opt.MatchFn = matchFn
				return opt.Run(args)
			})
		},
	}

	bindOptions(opt, cmd.Flags())
	bindUpgradeOptions(upgradeOpt, cmd.Flags())
	return cmd
}

func newRunTestCommand() *cobra.Command {
	testOpt := &testginkgo.TestOptions{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}

	cmd := &cobra.Command{
		Use:   "run-test NAME",
		Short: "Run a single test by name",
		Long: templates.LongDesc(`
		Execute a single test

		This executes a single test by name. It is used by the run command during suite execution but may also
		be used to test in isolation while developing new tests.
		`),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			upgradeOpts, err := initUpgrade(os.Getenv("TEST_SUITE_OPTIONS"))
			if err != nil {
				return err
			}
			config, err := decodeProvider(os.Getenv("TEST_PROVIDER"), testOpt.DryRun, false)
			if err != nil {
				return err
			}
			if _, err := initializeTestFramework(exutil.TestContext, config, testOpt.DryRun); err != nil {
				return err
			}
			exutil.TestContext.ReportDir = upgradeOpts.JUnitDir

			return testOpt.Run(args)
		},
	}
	cmd.Flags().BoolVar(&testOpt.DryRun, "dry-run", testOpt.DryRun, "Print the test to run without executing them.")
	return cmd
}

// mirrorToFile ensures a copy of all output goes to the provided OutFile, including
// any error returned from fn. The function returns fn() or any error encountered while
// attempting to open the file.
func mirrorToFile(opt *testginkgo.Options, fn func() error) error {
	if opt.Out == nil {
		opt.Out = os.Stdout
	}
	if opt.ErrOut == nil {
		opt.ErrOut = os.Stderr
	}
	if len(opt.OutFile) == 0 {
		return fn()
	}

	f, err := os.OpenFile(opt.OutFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640)
	if err != nil {
		return err
	}
	opt.Out = io.MultiWriter(opt.Out, f)
	opt.ErrOut = io.MultiWriter(opt.ErrOut, f)
	exitErr := fn()
	if exitErr != nil {
		fmt.Fprintf(f, "error: %s", exitErr)
	}
	if err := f.Close(); err != nil {
		fmt.Fprintf(opt.ErrOut, "error: Unable to close output file\n")
	}
	return exitErr
}

func bindOptions(opt *testginkgo.Options, flags *pflag.FlagSet) {
	flags.BoolVar(&opt.DryRun, "dry-run", opt.DryRun, "Print the tests to run without executing them.")
	flags.BoolVar(&opt.PrintCommands, "print-commands", opt.PrintCommands, "Print the sub-commands that would be executed instead.")
	flags.StringVar(&opt.JUnitDir, "junit-dir", opt.JUnitDir, "The directory to write test reports to.")
	flags.StringVar(&opt.Provider, "provider", opt.Provider, "The cluster infrastructure provider. Will automatically default to the correct value.")
	flags.StringVarP(&opt.TestFile, "file", "f", opt.TestFile, "Create a suite from the newline-delimited test names in this file.")
	flags.StringVar(&opt.Regex, "run", opt.Regex, "Regular expression of tests to run.")
	flags.StringVarP(&opt.OutFile, "output-file", "o", opt.OutFile, "Write all test output to this file.")
	flags.IntVar(&opt.Count, "count", opt.Count, "Run each test a specified number of times. Defaults to 1 or the suite's preferred value.")
	flags.DurationVar(&opt.Timeout, "timeout", opt.Timeout, "Set the maximum time a test can run before being aborted. This is read from the suite by default, but will be 10 minutes otherwise.")
	flags.BoolVar(&opt.IncludeSuccessOutput, "include-success", opt.IncludeSuccessOutput, "Print output from successful tests.")
}
<commit_msg>Make parallelism configurable<commit_after>package main

import (
	"flag"
	goflag "flag"
	"fmt"
	"io"
	"math/rand"
	"os"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	utilflag "k8s.io/component-base/cli/flag"
	"k8s.io/component-base/logs"
	"k8s.io/kubectl/pkg/util/templates"

	"github.com/openshift/library-go/pkg/serviceability"
	"github.com/openshift/origin/pkg/monitor"
	testginkgo "github.com/openshift/origin/pkg/test/ginkgo"
	exutil "github.com/openshift/origin/test/extended/util"
)

func main() {
	logs.InitLogs()
	defer logs.FlushLogs()

	rand.Seed(time.Now().UTC().UnixNano())

	pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)

	root := &cobra.Command{
		Long: templates.LongDesc(`
		OpenShift Tests

		This command verifies behavior of an OpenShift cluster by running remote tests against
		the cluster API that exercise functionality. In general these tests may be disruptive
		or require elevated privileges - see the descriptions of each test suite.
		`),
	}

	root.AddCommand(
		newRunCommand(),
		newRunUpgradeCommand(),
		newRunTestCommand(),
		newRunMonitorCommand(),
	)

	pflag.CommandLine = pflag.NewFlagSet("empty", pflag.ExitOnError)
	flag.CommandLine = flag.NewFlagSet("empty", flag.ExitOnError)
	exutil.InitStandardFlags()

	if err := func() error {
		defer serviceability.Profile(os.Getenv("OPENSHIFT_PROFILE")).Stop()
		return root.Execute()
	}(); err != nil {
		if ex, ok := err.(testginkgo.ExitError); ok {
			os.Exit(ex.Code)
		}
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

func newRunMonitorCommand() *cobra.Command {
	monitorOpt := &monitor.Options{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}
	cmd := &cobra.Command{
		Use:   "run-monitor",
		Short: "Continuously verify the cluster is functional",
		Long: templates.LongDesc(`
		Run a continuous verification process

		`),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return monitorOpt.Run()
		},
	}
	return cmd
}

func newRunCommand() *cobra.Command {
	opt := &testginkgo.Options{
		Suites: staticSuites,
	}

	cmd := &cobra.Command{
		Use:   "run SUITE",
		Short: "Run a test suite",
		Long: templates.LongDesc(`
		Run a test suite against an OpenShift server

		This command will run one of the following suites against a cluster identified by the current
		KUBECONFIG file. See the suite description for more on what actions the suite will take.

		If you specify the --dry-run argument, the names of each individual test that is part of the
		suite will be printed, one per line. You may filter this list and pass it back to the run
		command with the --file argument. You may also pipe a list of test names, one per line, on
		standard input by passing "-f -".

		`) + testginkgo.SuitesString(opt.Suites, "\n\nAvailable test suites:\n\n"),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return mirrorToFile(opt, func() error {
				config, err := decodeProvider(opt.Provider, opt.DryRun, true)
				if err != nil {
					return err
				}
				opt.Provider = config.ToJSONString()
				matchFn, err := initializeTestFramework(exutil.TestContext, config, opt.DryRun)
				if err != nil {
					return err
				}
				opt.MatchFn = matchFn
				return opt.Run(args)
			})
		},
	}
	bindOptions(opt, cmd.Flags())
	return cmd
}

func newRunUpgradeCommand() *cobra.Command {
	opt := &testginkgo.Options{Suites: upgradeSuites}
	upgradeOpt := &UpgradeOptions{}

	cmd := &cobra.Command{
		Use:   "run-upgrade SUITE",
		Short: "Run an upgrade suite",
		Long: templates.LongDesc(`
		Run an upgrade test suite against an OpenShift server

		This command will run one of the following suites against a cluster identified by the current
		KUBECONFIG file. See the suite description for more on what actions the suite will take.

		If you specify the --dry-run argument, the actions the suite will take will be printed to the
		output.

		Supported options:

		* abort-at=NUMBER - Set to a number between 0 and 100 to control the percent of operators
		at which to stop the current upgrade and roll back to the current version.
		* disrupt-reboot=POLICY - During upgrades, periodically reboot master nodes. If set to 'graceful'
		the reboot will allow the node to shut down services in an orderly fashion. If set to 'force' the
		machine will terminate immediately without clean shutdown.

		`) + testginkgo.SuitesString(opt.Suites, "\n\nAvailable upgrade suites:\n\n"),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return mirrorToFile(opt, func() error {
				if len(upgradeOpt.ToImage) == 0 {
					return fmt.Errorf("--to-image must be specified to run an upgrade test")
				}

				if len(args) > 0 {
					for _, suite := range opt.Suites {
						if suite.Name == args[0] {
							upgradeOpt.Suite = suite.Name
							upgradeOpt.JUnitDir = opt.JUnitDir
							value := upgradeOpt.ToEnv()
							if _, err := initUpgrade(value); err != nil {
								return err
							}
							opt.SuiteOptions = value
							break
						}
					}
				}

				config, err := decodeProvider(opt.Provider, opt.DryRun, true)
				if err != nil {
					return err
				}
				opt.Provider = config.ToJSONString()
				matchFn, err := initializeTestFramework(exutil.TestContext, config, opt.DryRun)
				if err != nil {
					return err
				}
				opt.MatchFn = matchFn
				return opt.Run(args)
			})
		},
	}

	bindOptions(opt, cmd.Flags())
	bindUpgradeOptions(upgradeOpt, cmd.Flags())
	return cmd
}

func newRunTestCommand() *cobra.Command {
	testOpt := &testginkgo.TestOptions{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}

	cmd := &cobra.Command{
		Use:   "run-test NAME",
		Short: "Run a single test by name",
		Long: templates.LongDesc(`
		Execute a single test

		This executes a single test by name. It is used by the run command during suite execution but may also
		be used to test in isolation while developing new tests.
		`),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			upgradeOpts, err := initUpgrade(os.Getenv("TEST_SUITE_OPTIONS"))
			if err != nil {
				return err
			}
			config, err := decodeProvider(os.Getenv("TEST_PROVIDER"), testOpt.DryRun, false)
			if err != nil {
				return err
			}
			if _, err := initializeTestFramework(exutil.TestContext, config, testOpt.DryRun); err != nil {
				return err
			}
			exutil.TestContext.ReportDir = upgradeOpts.JUnitDir

			return testOpt.Run(args)
		},
	}
	cmd.Flags().BoolVar(&testOpt.DryRun, "dry-run", testOpt.DryRun, "Print the test to run without executing them.")
	return cmd
}

// mirrorToFile ensures a copy of all output goes to the provided OutFile, including
// any error returned from fn. The function returns fn() or any error encountered while
// attempting to open the file.
func mirrorToFile(opt *testginkgo.Options, fn func() error) error {
	if opt.Out == nil {
		opt.Out = os.Stdout
	}
	if opt.ErrOut == nil {
		opt.ErrOut = os.Stderr
	}
	if len(opt.OutFile) == 0 {
		return fn()
	}

	f, err := os.OpenFile(opt.OutFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640)
	if err != nil {
		return err
	}
	opt.Out = io.MultiWriter(opt.Out, f)
	opt.ErrOut = io.MultiWriter(opt.ErrOut, f)
	exitErr := fn()
	if exitErr != nil {
		fmt.Fprintf(f, "error: %s", exitErr)
	}
	if err := f.Close(); err != nil {
		fmt.Fprintf(opt.ErrOut, "error: Unable to close output file\n")
	}
	return exitErr
}

func bindOptions(opt *testginkgo.Options, flags *pflag.FlagSet) {
	flags.BoolVar(&opt.DryRun, "dry-run", opt.DryRun, "Print the tests to run without executing them.")
	flags.BoolVar(&opt.PrintCommands, "print-commands", opt.PrintCommands, "Print the sub-commands that would be executed instead.")
	flags.StringVar(&opt.JUnitDir, "junit-dir", opt.JUnitDir, "The directory to write test reports to.")
	flags.StringVar(&opt.Provider, "provider", opt.Provider, "The cluster infrastructure provider. Will automatically default to the correct value.")
	flags.StringVarP(&opt.TestFile, "file", "f", opt.TestFile, "Create a suite from the newline-delimited test names in this file.")
	flags.StringVar(&opt.Regex, "run", opt.Regex, "Regular expression of tests to run.")
	flags.StringVarP(&opt.OutFile, "output-file", "o", opt.OutFile, "Write all test output to this file.")
	flags.IntVar(&opt.Count, "count", opt.Count, "Run each test a specified number of times. Defaults to 1 or the suite's preferred value.")
	flags.DurationVar(&opt.Timeout, "timeout", opt.Timeout, "Set the maximum time a test can run before being aborted. This is read from the suite by default, but will be 10 minutes otherwise.")
	flags.BoolVar(&opt.IncludeSuccessOutput, "include-success", opt.IncludeSuccessOutput, "Print output from successful tests.")
	flags.IntVar(&opt.Parallelism, "max-parallel-tests", opt.Parallelism, "Maximum number of tests running in parallel. 0 defaults to test suite recommended value, which is different in each suite.")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"math/rand"
	"os"
	"time"

	"github.com/onsi/gomega"

	"github.com/golang/glog"
	"github.com/onsi/ginkgo"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"k8s.io/apiserver/pkg/util/logs"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	e2e "k8s.io/kubernetes/test/e2e/framework"

	"github.com/openshift/library-go/pkg/serviceability"
	"github.com/openshift/origin/pkg/cmd/flagtypes"
	"github.com/openshift/origin/pkg/monitor"
	testginkgo "github.com/openshift/origin/pkg/test/ginkgo"
	exutil "github.com/openshift/origin/test/extended/util"
)

func main() {
	logs.InitLogs()
	defer logs.FlushLogs()

	rand.Seed(time.Now().UTC().UnixNano())

	root := &cobra.Command{
		Long: templates.LongDesc(`
		OpenShift Tests

		This command verifies behavior of an OpenShift cluster by running remote tests against
		the cluster API that exercise functionality. In general these tests may be disruptive
		or require elevated privileges - see the descriptions of each test suite.
		`),
	}
	flagtypes.GLog(root.PersistentFlags())

	suites := staticSuites

	suiteOpt := &testginkgo.Options{
		Suites: suites,
	}
	cmd := &cobra.Command{
		Use:   "run SUITE",
		Short: "Run a test suite",
		Long: templates.LongDesc(`
		Run a test suite against an OpenShift server

		This command will run one of the following suites against a cluster identified by the current
		KUBECONFIG file. See the suite description for more on what actions the suite will take.

		If you specify the --dry-run argument, the names of each individual test that is part of the
		suite will be printed, one per line. You may filter this list and pass it back to the run
		command with the --file argument. You may also pipe a list of test names, one per line, on
		standard input by passing "-f -".

		`) + testginkgo.SuitesString(suites, "\n\nAvailable test suites:\n\n"),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			var exitErr error
			var out, errOut io.Writer = os.Stdout, os.Stderr
			if len(suiteOpt.OutFile) > 0 {
				f, err := os.OpenFile(suiteOpt.OutFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640)
				if err != nil {
					return err
				}
				defer func() {
					if exitErr != nil {
						fmt.Fprintf(f, "error: %s", exitErr)
					}
					if err := f.Close(); err != nil {
						fmt.Fprintf(os.Stderr, "error: Unable to close output file\n")
					}
				}()
				out = io.MultiWriter(out, f)
				errOut = io.MultiWriter(errOut, f)
			}
			suiteOpt.Out, suiteOpt.ErrOut = out, errOut

			if exitErr = initProvider(suiteOpt.Provider); exitErr != nil {
				return exitErr
			}
			os.Setenv("TEST_PROVIDER", suiteOpt.Provider)
			exitErr = suiteOpt.Run(args)
			return exitErr
		},
	}
	cmd.Flags().BoolVar(&suiteOpt.DryRun, "dry-run", suiteOpt.DryRun, "Print the tests to run without executing them.")
	cmd.Flags().StringVar(&suiteOpt.JUnitDir, "junit-dir", suiteOpt.JUnitDir, "The directory to write test reports to.")
	cmd.Flags().StringVar(&suiteOpt.Provider, "provider", suiteOpt.Provider, "The cluster infrastructure provider. Will automatically default to the correct value.")
	cmd.Flags().StringVarP(&suiteOpt.TestFile, "file", "f", suiteOpt.TestFile, "Create a suite from the newline-delimited test names in this file.")
	cmd.Flags().StringVarP(&suiteOpt.OutFile, "output-file", "o", suiteOpt.OutFile, "Write all test output to this file.")
	cmd.Flags().DurationVar(&suiteOpt.Timeout, "timeout", suiteOpt.Timeout, "Set the maximum time a test can run before being aborted. This is read from the suite by default, but will be 10 minutes otherwise.")
	cmd.Flags().BoolVar(&suiteOpt.IncludeSuccessOutput, "include-success", suiteOpt.IncludeSuccessOutput, "Print output from successful tests.")
	root.AddCommand(cmd)

	testOpt := &testginkgo.TestOptions{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}
	cmd = &cobra.Command{
		Use:   "run-test NAME",
		Short: "Run a single test by name",
		Long: templates.LongDesc(`
		Execute a single test

		This executes a single test by name. It is used by the run command during suite execution but may also
		be used to test in isolation while developing new tests.
		`),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := initProvider(os.Getenv("TEST_PROVIDER")); err != nil {
				return err
			}
			return testOpt.Run(args)
		},
	}
	cmd.Flags().BoolVar(&testOpt.DryRun, "dry-run", testOpt.DryRun, "Print the test to run without executing them.")
	root.AddCommand(cmd)

	monitorOpt := &monitor.Options{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}
	cmd = &cobra.Command{
		Use:   "run-monitor",
		Short: "Continuously verify the cluster is functional",
		Long: templates.LongDesc(`
		Run a continuous verification process

		`),

		SilenceUsage: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return monitorOpt.Run()
		},
	}
	root.AddCommand(cmd)

	pflag.CommandLine = pflag.NewFlagSet("empty", pflag.ExitOnError)
	flag.CommandLine = flag.NewFlagSet("empty", flag.ExitOnError)
	exutil.InitStandardFlags()

	if err := func() error {
		defer serviceability.Profile(os.Getenv("OPENSHIFT_PROFILE")).Stop()
		return root.Execute()
	}(); err != nil {
		if ex, ok := err.(testginkgo.ExitError); ok {
			os.Exit(ex.Code)
		}
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

func initProvider(provider string) error {
	// record the exit error to the output file
	if err := decodeProviderTo(provider, exutil.TestContext); err != nil {
		return err
	}
	exutil.TestContext.AllowedNotReadyNodes = 100
	exutil.TestContext.MaxNodesToGather = 0

	exutil.AnnotateTestSuite()
	exutil.InitTest()
	gomega.RegisterFailHandler(ginkgo.Fail)

	// TODO: infer SSH keys from the cluster
	return nil
}

func decodeProviderTo(provider string, testContext *e2e.TestContextType) error {
	switch provider {
	case "":
		if _, ok := os.LookupEnv("KUBE_SSH_USER"); ok {
			if _, ok := os.LookupEnv("LOCAL_SSH_KEY"); ok {
				testContext.Provider = "local"
			}
		}
		// TODO: detect which provider the cluster is running and use that as a default.
	default:
		var providerInfo struct{ Type string }
		if err := json.Unmarshal([]byte(provider), &providerInfo); err != nil {
			return fmt.Errorf("provider must be a JSON object with the 'type' key at a minimum: %v", err)
		}
		if len(providerInfo.Type) == 0 {
			return fmt.Errorf("provider must be a JSON object with the 'type' key")
		}
		testContext.Provider = providerInfo.Type
		if err := json.Unmarshal([]byte(provider), &testContext.CloudConfig); err != nil {
			return fmt.Errorf("provider must decode into the cloud config object: %v", err)
		}
	}
	glog.V(2).Infof("Provider %s: %#v", testContext.Provider, testContext.CloudConfig)
	return nil
}
<commit_msg>Add VIPERCONFIG to initProvider for openshift-tests<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"math/rand"
	"os"
	"time"

	"github.com/onsi/gomega"

	"github.com/golang/glog"
	"github.com/onsi/ginkgo"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"k8s.io/apiserver/pkg/util/logs"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	e2e "k8s.io/kubernetes/test/e2e/framework"

	"github.com/openshift/library-go/pkg/serviceability"
	"github.com/openshift/origin/pkg/cmd/flagtypes"
	"github.com/openshift/origin/pkg/monitor"
	testginkgo "github.com/openshift/origin/pkg/test/ginkgo"
	exutil "github.com/openshift/origin/test/extended/util"
)

func main() {
	logs.InitLogs()
	defer logs.FlushLogs()

	rand.Seed(time.Now().UTC().UnixNano())

	root := &cobra.Command{
		Long: templates.LongDesc(`
		OpenShift Tests

		This command verifies behavior of an OpenShift cluster by running remote tests against
		the cluster API that exercise functionality. In general these tests may be disruptive
		or require elevated privileges - see the descriptions of each test suite.
		`),
	}
	flagtypes.GLog(root.PersistentFlags())

	suites := staticSuites

	suiteOpt := &testginkgo.Options{
		Suites: suites,
	}
	cmd := &cobra.Command{
		Use:   "run SUITE",
		Short: "Run a test suite",
		Long: templates.LongDesc(`
		Run a test suite against an OpenShift server

		This command will run one of the following suites against a cluster identified by the current
		KUBECONFIG file. See the suite description for more on what actions the suite will take.

		If you specify the --dry-run argument, the names of each individual test that is part of the
		suite will be printed, one per line. You may filter this list and pass it back to the run
		command with the --file argument. You may also pipe a list of test names, one per line, on
		standard input by passing "-f -".

		`) + testginkgo.SuitesString(suites, "\n\nAvailable test suites:\n\n"),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			var exitErr error
			var out, errOut io.Writer = os.Stdout, os.Stderr
			if len(suiteOpt.OutFile) > 0 {
				f, err := os.OpenFile(suiteOpt.OutFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640)
				if err != nil {
					return err
				}
				defer func() {
					if exitErr != nil {
						fmt.Fprintf(f, "error: %s", exitErr)
					}
					if err := f.Close(); err != nil {
						fmt.Fprintf(os.Stderr, "error: Unable to close output file\n")
					}
				}()
				out = io.MultiWriter(out, f)
				errOut = io.MultiWriter(errOut, f)
			}
			suiteOpt.Out, suiteOpt.ErrOut = out, errOut

			if exitErr = initProvider(suiteOpt.Provider); exitErr != nil {
				return exitErr
			}
			os.Setenv("TEST_PROVIDER", suiteOpt.Provider)
			exitErr = suiteOpt.Run(args)
			return exitErr
		},
	}
	cmd.Flags().BoolVar(&suiteOpt.DryRun, "dry-run", suiteOpt.DryRun, "Print the tests to run without executing them.")
	cmd.Flags().StringVar(&suiteOpt.JUnitDir, "junit-dir", suiteOpt.JUnitDir, "The directory to write test reports to.")
	cmd.Flags().StringVar(&suiteOpt.Provider, "provider", suiteOpt.Provider, "The cluster infrastructure provider. Will automatically default to the correct value.")
	cmd.Flags().StringVarP(&suiteOpt.TestFile, "file", "f", suiteOpt.TestFile, "Create a suite from the newline-delimited test names in this file.")
	cmd.Flags().StringVarP(&suiteOpt.OutFile, "output-file", "o", suiteOpt.OutFile, "Write all test output to this file.")
	cmd.Flags().DurationVar(&suiteOpt.Timeout, "timeout", suiteOpt.Timeout, "Set the maximum time a test can run before being aborted. This is read from the suite by default, but will be 10 minutes otherwise.")
	cmd.Flags().BoolVar(&suiteOpt.IncludeSuccessOutput, "include-success", suiteOpt.IncludeSuccessOutput, "Print output from successful tests.")
	root.AddCommand(cmd)

	testOpt := &testginkgo.TestOptions{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}
	cmd = &cobra.Command{
		Use:   "run-test NAME",
		Short: "Run a single test by name",
		Long: templates.LongDesc(`
		Execute a single test

		This executes a single test by name. It is used by the run command during suite execution but may also
		be used to test in isolation while developing new tests.
		`),

		SilenceUsage:  true,
		SilenceErrors: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := initProvider(os.Getenv("TEST_PROVIDER")); err != nil {
				return err
			}
			return testOpt.Run(args)
		},
	}
	cmd.Flags().BoolVar(&testOpt.DryRun, "dry-run", testOpt.DryRun, "Print the test to run without executing them.")
	root.AddCommand(cmd)

	monitorOpt := &monitor.Options{
		Out:    os.Stdout,
		ErrOut: os.Stderr,
	}
	cmd = &cobra.Command{
		Use:   "run-monitor",
		Short: "Continuously verify the cluster is functional",
		Long: templates.LongDesc(`
		Run a continuous verification process

		`),

		SilenceUsage: true,
		RunE: func(cmd *cobra.Command, args []string) error {
			return monitorOpt.Run()
		},
	}
	root.AddCommand(cmd)

	pflag.CommandLine = pflag.NewFlagSet("empty", pflag.ExitOnError)
	flag.CommandLine = flag.NewFlagSet("empty", flag.ExitOnError)
	exutil.InitStandardFlags()

	if err := func() error {
		defer serviceability.Profile(os.Getenv("OPENSHIFT_PROFILE")).Stop()
		return root.Execute()
	}(); err != nil {
		if ex, ok := err.(testginkgo.ExitError); ok {
			os.Exit(ex.Code)
		}
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

func initProvider(provider string) error {
	// record the exit error to the output file
	if err := decodeProviderTo(provider, exutil.TestContext); err != nil {
		return err
	}
	exutil.TestContext.AllowedNotReadyNodes = 100
	exutil.TestContext.MaxNodesToGather = 0
	exutil.TestContext.Viper = os.Getenv("VIPERCONFIG")

	exutil.AnnotateTestSuite()
	exutil.InitTest()
	gomega.RegisterFailHandler(ginkgo.Fail)

	// TODO: infer SSH keys from the cluster
	return nil
}

func decodeProviderTo(provider string, testContext *e2e.TestContextType) error {
	switch provider {
	case "":
		if _, ok := os.LookupEnv("KUBE_SSH_USER"); ok {
			if _, ok := os.LookupEnv("LOCAL_SSH_KEY"); ok {
				testContext.Provider = "local"
			}
		}
		// TODO: detect which provider the cluster is running and use that as a default.
	default:
		var providerInfo struct{ Type string }
		if err := json.Unmarshal([]byte(provider), &providerInfo); err != nil {
			return fmt.Errorf("provider must be a JSON object with the 'type' key at a minimum: %v", err)
		}
		if len(providerInfo.Type) == 0 {
			return fmt.Errorf("provider must be a JSON object with the 'type' key")
		}
		testContext.Provider = providerInfo.Type
		if err := json.Unmarshal([]byte(provider), &testContext.CloudConfig); err != nil {
			return fmt.Errorf("provider must decode into the cloud config object: %v", err)
		}
	}
	glog.V(2).Infof("Provider %s: %#v", testContext.Provider, testContext.CloudConfig)
	return nil
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2018 vLife Systems Ltd <http://vlifesystems.com>
// Licensed under an MIT licence.  Please see LICENSE.md for details.

package html

import (
	"fmt"
	"sync"
	"time"

	"github.com/vlifesystems/rulehunter/config"
	"github.com/vlifesystems/rulehunter/logger"
	"github.com/vlifesystems/rulehunter/progress"
	"github.com/vlifesystems/rulehunter/quitter"
)

// Builder represents an html website builder
type Builder struct {
	cfg       *config.Config
	pm        *progress.Monitor
	log       logger.Logger
	isRunning bool
	sync.Mutex
}

func New(
	cfg *config.Config,
	pm *progress.Monitor,
	l logger.Logger,
) *Builder {
	return &Builder{
		cfg:       cfg,
		pm:        pm,
		log:       l,
		isRunning: false,
	}
}

// This should be run as a goroutine and it will periodically generate html
func (b *Builder) Run(q *quitter.Quitter) {
	q.Add()
	defer q.Done()
	b.isRunning = true
	defer func() {
		b.Lock()
		defer b.Unlock()
		b.isRunning = false
	}()
	if err := b.generateAll(); err != nil {
		b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
	}

	oldExperiments := b.pm.GetExperiments()

	tickChan := time.NewTicker(time.Second * 5).C
	for {
		select {
		case <-tickChan:
			currentExperiments := b.pm.GetExperiments()
			if !areReportsUptodate(oldExperiments, currentExperiments) {
				if err := b.generateReports(); err != nil {
					b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
				}
			}
			if !isProgressUptodate(oldExperiments, currentExperiments) {
				if err := b.generateProgress(); err != nil {
					b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
				}
			}
			oldExperiments = currentExperiments
		case <-q.C:
			if err := b.generateAll(); err != nil {
				b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
			}
			return
		}
	}
}

// Running returns whether the html builder is running
func (b *Builder) Running() bool {
	b.Lock()
	defer b.Unlock()
	return b.isRunning
}

type generator func(*config.Config, *progress.Monitor) error

func (b *Builder) generateAll() error {
	generators := []generator{
		generateActivityPage,
		generateFront,
		generateReports,
		generateTagPages,
		generateCategoryPages,
	}
	return b.generate(generators)
}

func (b *Builder) generateProgress() error {
	generators := []generator{
		generateActivityPage,
		generateFront,
	}
	return b.generate(generators)
}

func (b *Builder) generateReports() error {
	generators := []generator{
		generateActivityPage,
		generateFront,
		generateReports,
		generateTagPages,
		generateCategoryPages,
	}
	return b.generate(generators)
}

func (b *Builder) generate(generators []generator) error {
	for _, g := range generators {
		if err := g(b.cfg, b.pm); err != nil {
			return err
		}
	}
	return nil
}

func areReportsUptodate(
	oldExperiments, currentExperiments []*progress.Experiment,
) bool {
	for _, ce := range currentExperiments {
		found := false
		for _, oe := range oldExperiments {
			if ce.Filename == oe.Filename {
				found = true
				if ce.Status.State == progress.Success &&
					ce.Status.Stamp.After(oe.Status.Stamp) {
					return false
				}
			}
		}
		if !found && ce.Status.State == progress.Success {
			return false
		}
	}
	return true
}

func isProgressUptodate(
	oldExperiments, currentExperiments []*progress.Experiment,
) bool {
	if len(currentExperiments) != len(oldExperiments) {
		return false
	}
	for _, ce := range currentExperiments {
		for _, oe := range oldExperiments {
			if !ce.IsEqual(oe) {
				return false
			}
		}
	}
	return true
}
<commit_msg>Only update html reports if changed in last 10 seconds<commit_after>// Copyright (C) 2016-2018 vLife Systems Ltd <http://vlifesystems.com>
// Licensed under an MIT licence.  Please see LICENSE.md for details.

package html

import (
	"fmt"
	"sync"
	"time"

	"github.com/vlifesystems/rulehunter/config"
	"github.com/vlifesystems/rulehunter/logger"
	"github.com/vlifesystems/rulehunter/progress"
	"github.com/vlifesystems/rulehunter/quitter"
)

// Builder represents an html website builder
type Builder struct {
	cfg       *config.Config
	pm        *progress.Monitor
	log       logger.Logger
	isRunning bool
	sync.Mutex
}

func New(
	cfg *config.Config,
	pm *progress.Monitor,
	l logger.Logger,
) *Builder {
	return &Builder{
		cfg:       cfg,
		pm:        pm,
		log:       l,
		isRunning: false,
	}
}

// This should be run as a goroutine and it will periodically generate html
func (b *Builder) Run(q *quitter.Quitter) {
	q.Add()
	defer q.Done()
	b.isRunning = true
	defer func() {
		b.Lock()
		defer b.Unlock()
		b.isRunning = false
	}()
	if err := b.generateAll(); err != nil {
		b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
	}

	oldExperiments := b.pm.GetExperiments()

	tickChan := time.NewTicker(time.Second * 5).C
	for {
		select {
		case <-tickChan:
			currentExperiments := b.pm.GetExperiments()
			if !areReportsUptodate(oldExperiments, currentExperiments) {
				if err := b.generateReports(); err != nil {
					b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
				}
			}
			if !isProgressUptodate(oldExperiments, currentExperiments) {
				if err := b.generateProgress(); err != nil {
					b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
				}
			}
			oldExperiments = currentExperiments
		case <-q.C:
			if err := b.generateAll(); err != nil {
				b.log.Error(fmt.Errorf("Couldn't generate html: %s", err))
			}
			return
		}
	}
}

// Running returns whether the html builder is running
func (b *Builder) Running() bool {
	b.Lock()
	defer b.Unlock()
	return b.isRunning
}

type generator func(*config.Config, *progress.Monitor) error

func (b *Builder) generateAll() error {
	generators := []generator{
		generateActivityPage,
		generateFront,
		generateReports,
		generateTagPages,
		generateCategoryPages,
	}
	return b.generate(generators)
}

func (b *Builder) generateProgress() error {
	generators := []generator{
		generateActivityPage,
		generateFront,
	}
	return b.generate(generators)
}

func (b *Builder) generateReports() error {
	generators := []generator{
		generateActivityPage,
		generateFront,
		generateReports,
		generateTagPages,
		generateCategoryPages,
	}
	return b.generate(generators)
}

func (b *Builder) generate(generators []generator) error {
	for _, g := range generators {
		if err := g(b.cfg, b.pm); err != nil {
			return err
		}
	}
	return nil
}

func areReportsUptodate(
	oldExperiments, currentExperiments []*progress.Experiment,
) bool {
	for _, ce := range currentExperiments {
		if ce.Status.State == progress.Success &&
			time.Since(ce.Status.Stamp).Seconds() < 10 {
			return false
		}
	}
	return true
}

func isProgressUptodate(
	oldExperiments, currentExperiments []*progress.Experiment,
) bool {
	if len(currentExperiments) != len(oldExperiments) {
		return false
	}
	for _, ce := range currentExperiments {
		for _, oe := range oldExperiments {
			if !ce.IsEqual(oe) {
				return false
			}
		}
	}
	return true
}
<|endoftext|>


<commit_before>package file

import (
	"github.com/luopengift/golibs/logger"
	"os"
	"syscall"
)

type File struct {
	name  string
	model int
	inode uint64
	fd    *os.File
	seek  int64
}

func NewFile(name string, model int) *File {
	file := &File{name: name, model: model}
	file.Open()
	return file
}

func (self *File) Open() (err error) {
	self.fd, err = os.OpenFile(self.name, self.model, 0660)
	if err != nil {
		logger.Error("<file %s can not open>:%v", self.name, err)
		return err
	}

	self.inode, err = self.Inode()
	if err != nil {
		logger.Error("< %s can not get inode>:%v", self.name, err)
		return err
	}
	return nil
}

func (self *File) Close() error {
	return self.fd.Close()
}

func Inode(name string) (uint64, error) {
	if stat, err := os.Stat(name); err != nil {
		return 0, err
	} else {
		inode := stat.Sys().(*syscall.Stat_t).Ino
		return inode, nil
	}
}

func (self *File) Inode() (uint64, error) {
	inode, err := Inode(self.name)
	return inode, err
}
<commit_msg>update file<commit_after>package file

import (
	"github.com/luopengift/golibs/logger"
	"io/ioutil"
	"os"
	"syscall"
)

type File struct {
	name  string
	model int
	inode uint64
	fd    *os.File
	seek  int64
}

func NewFile(name string, model int) *File {
	file := &File{name: name, model: model}
	file.Open()
	return file
}

func (self *File) Open() (err error) {
	self.fd, err = os.OpenFile(self.name, self.model, 0660)
	if err != nil {
		logger.Error("<file %s can not open>:%v", self.name, err)
		return err
	}

	self.inode, err = self.Inode()
	if err != nil {
		logger.Error("< %s can not get inode>:%v", self.name, err)
		return err
	}
	return nil
}

func (self *File) Close() error {
	return self.fd.Close()
}

func (self *File) Fd() *os.File {
	return self.fd
}

func (self *File) ReadAll() (file []byte, err error) {
	file, err = ioutil.ReadAll(self.fd)
	return
}

func Inode(name string) (uint64, error) {
	if stat, err := os.Stat(name); err != nil {
		return 0, err
	} else {
		inode := stat.Sys().(*syscall.Stat_t).Ino
		return inode, nil
	}
}

func (self *File) Inode() (uint64, error) {
	inode, err := Inode(self.name)
	return inode, err
}
<|endoftext|>


<commit_before>package main

import (
    // "bitly/simplejson"
    "flag"
    "fmt"
    "bufio"
    "os"
    "strings"
    "io"
)

var pubsub = flag.String("pubsub", "", "Pubsub to write to")

func main() {
    flag.Parse()
    reader := bufio.NewReader(os.Stdin)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            if err != io.EOF {
                fmt.Println(fmt.Sprintf("ERROR: %s", err))
            }
            break
        }
        line = strings.TrimSpace(line)
        fmt.Println(fmt.Sprintf(">> %s", line))
    }
}
<commit_msg>start putting together stuff to actually publish, but still not working. maybe buffer error?<commit_after>package main

import (
    // "bitly/simplejson"
    "flag"
    "fmt"
    "bufio"
    "os"
    "strings"
    "io"
    "net/http"
    "bytes"
    "log"
)

var pubsub = flag.String("pubsub", "", "Pubsub to write to")

type Publisher interface {
    Publish(string) error
}

type PublisherInfo struct { // ha! this is what happens when your language makes you use interfaces
    httpclient *http.Client
    addr string
}

type PubsubPublisher struct {
    PublisherInfo
}

func (p *PubsubPublisher) Publish(msg string) error {
    log.Println("Called publish")
    endpoint := fmt.Sprintf("%s/pub", p.addr)
    var buffer bytes.Buffer
    buffer.Write([]byte(msg))
    resp, err := http.Post(endpoint, "application/json", &buffer)
    defer resp.Body.Close()
    return err
}

func PublishLoop(pub Publisher, publishMsgs chan string) {
    for {
        msg := <-publishMsgs
        log.Println("Publishing message: ", msg)

        err := pub.Publish(msg)
        if err != nil {
            log.Println("ERROR publishing: ", err)
            break
        }
    }
}

func main() {
    flag.Parse()
    var publisher Publisher
    if len(*pubsub) > 0 {
        log.Println("Pubsub")
        publisher = &PubsubPublisher{PublisherInfo{&http.Client{}, *pubsub}}
    }

    msgsChan := make(chan string, 1) // TODO - decide how much we wish to buffer here
    go PublishLoop(publisher, msgsChan)
    reader := bufio.NewReader(os.Stdin)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            if err != io.EOF {
                log.Println(fmt.Sprintf("ERROR: %s", err))
            }
            break
        }
        line = strings.TrimSpace(line)
        msgsChan <- line
    }
}
<|endoftext|>


<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 file

import (
	"os"
	"path/filepath"
	"sort"
	"testing"

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

func RecoverEnv(wd, tmpDir string) {
	os.Chdir(wd)
	os.RemoveAll(tmpDir)
}

func TestFileUtils(t *testing.T) {
	fs := &afero.Afero{Fs: afero.NewOsFs()}
	// Create tmp dir
	tmpDir, err := fs.TempDir(os.TempDir(), "util_file_test_")
	if err != nil {
		t.Fatal("Failed to test: failed to create temp dir.")
	}

	// create tmp file
	tmpFile, err := fs.TempFile(tmpDir, "test_file_exists_")
	if err != nil {
		t.Fatal("Failed to test: failed to create temp file.")
	}

	// create tmp sym link
	tmpSymlinkName := filepath.Join(tmpDir, "test_file_exists_sym_link")
	err = os.Symlink(tmpFile.Name(), tmpSymlinkName)
	if err != nil {
		t.Fatal("Failed to test: failed to create sym link.")
	}

	// create tmp sub dir
	tmpSubDir, err := fs.TempDir(tmpDir, "sub_")
	if err != nil {
		t.Fatal("Failed to test: failed to create temp sub dir.")
	}

	// record the current dir
	currentDir, err := os.Getwd()
	if err != nil {
		t.Fatal("Failed to test: failed to get current dir.")
	}

	// change the work dir to temp dir
	err = os.Chdir(tmpDir)
	if err != nil {
		t.Fatal("Failed to test: failed to change work dir.")
	}

	// recover test enviroment
	defer RecoverEnv(currentDir, tmpDir)

	t.Run("TestFileExists", func(t *testing.T) {
		tests := []struct {
			name          string
			fileName      string
			expectedError bool
			expectedValue bool
		}{
			{"file_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), false, false},
			{"file_exists", tmpFile.Name(), false, true},
		}

		for _, test := range tests {
			realValued, realError := FileExists(test.fileName)
			if test.expectedError {
				assert.Errorf(t, realError, "Failed to test with '%s': %s", test.fileName, test.name)
			} else {
				assert.EqualValuesf(t, test.expectedValue, realValued, "Failed to test with '%s': %s", test.fileName, test.name)
			}
		}
	})

	t.Run("TestFileOrSymlinkExists", func(t *testing.T) {
		tests := []struct {
			name          string
			fileName      string
			expectedError bool
			expectedValue bool
		}{
			{"file_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), false, false},
			{"file_exists", tmpFile.Name(), false, true},
			{"symlink_exists", tmpSymlinkName, false, true},
		}

		for _, test := range tests {
			realValued, realError := FileOrSymlinkExists(test.fileName)
			if test.expectedError {
				assert.Errorf(t, realError, "Failed to test with '%s': %s", test.fileName, test.name)
			} else {
				assert.EqualValuesf(t, test.expectedValue, realValued, "Failed to test with '%s': %s", test.fileName, test.name)
			}
		}
	})

	t.Run("TestReadDirNoStat", func(t *testing.T) {
		_, tmpFileSimpleName := filepath.Split(tmpFile.Name())
		_, tmpSymlinkSimpleName := filepath.Split(tmpSymlinkName)
		_, tmpSubDirSimpleName := filepath.Split(tmpSubDir)

		tests := []struct {
			name          string
			dirName       string
			expectedError bool
			expectedValue []string
		}{
			{"dir_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), true, []string{}},
			{"dir_is_empty", "", false, []string{tmpFileSimpleName, tmpSymlinkSimpleName, tmpSubDirSimpleName}},
			{"dir_exists", tmpDir, false, []string{tmpFileSimpleName, tmpSymlinkSimpleName, tmpSubDirSimpleName}},
		}

		for _, test := range tests {
			realValued, realError := ReadDirNoStat(test.dirName)

			// execute sort action before compare
			sort.Strings(realValued)
			sort.Strings(test.expectedValue)

			if test.expectedError {
				assert.Errorf(t, realError, "Failed to test with '%s': %s", test.dirName, test.name)
			} else {
				assert.EqualValuesf(t, test.expectedValue, realValued, "Failed to test with '%s': %s", test.dirName, test.name)
			}
		}
	})
}
<commit_msg>fix all the typos across the project<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 file

import (
	"os"
	"path/filepath"
	"sort"
	"testing"

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

func RecoverEnv(wd, tmpDir string) {
	os.Chdir(wd)
	os.RemoveAll(tmpDir)
}

func TestFileUtils(t *testing.T) {
	fs := &afero.Afero{Fs: afero.NewOsFs()}
	// Create tmp dir
	tmpDir, err := fs.TempDir(os.TempDir(), "util_file_test_")
	if err != nil {
		t.Fatal("Failed to test: failed to create temp dir.")
	}

	// create tmp file
	tmpFile, err := fs.TempFile(tmpDir, "test_file_exists_")
	if err != nil {
		t.Fatal("Failed to test: failed to create temp file.")
	}

	// create tmp sym link
	tmpSymlinkName := filepath.Join(tmpDir, "test_file_exists_sym_link")
	err = os.Symlink(tmpFile.Name(), tmpSymlinkName)
	if err != nil {
		t.Fatal("Failed to test: failed to create sym link.")
	}

	// create tmp sub dir
	tmpSubDir, err := fs.TempDir(tmpDir, "sub_")
	if err != nil {
		t.Fatal("Failed to test: failed to create temp sub dir.")
	}

	// record the current dir
	currentDir, err := os.Getwd()
	if err != nil {
		t.Fatal("Failed to test: failed to get current dir.")
	}

	// change the work dir to temp dir
	err = os.Chdir(tmpDir)
	if err != nil {
		t.Fatal("Failed to test: failed to change work dir.")
	}

	// recover test environment
	defer RecoverEnv(currentDir, tmpDir)

	t.Run("TestFileExists", func(t *testing.T) {
		tests := []struct {
			name          string
			fileName      string
			expectedError bool
			expectedValue bool
		}{
			{"file_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), false, false},
			{"file_exists", tmpFile.Name(), false, true},
		}

		for _, test := range tests {
			realValued, realError := FileExists(test.fileName)
			if test.expectedError {
				assert.Errorf(t, realError, "Failed to test with '%s': %s", test.fileName, test.name)
			} else {
				assert.EqualValuesf(t, test.expectedValue, realValued, "Failed to test with '%s': %s", test.fileName, test.name)
			}
		}
	})

	t.Run("TestFileOrSymlinkExists", func(t *testing.T) {
		tests := []struct {
			name          string
			fileName      string
			expectedError bool
			expectedValue bool
		}{
			{"file_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), false, false},
			{"file_exists", tmpFile.Name(), false, true},
			{"symlink_exists", tmpSymlinkName, false, true},
		}

		for _, test := range tests {
			realValued, realError := FileOrSymlinkExists(test.fileName)
			if test.expectedError {
				assert.Errorf(t, realError, "Failed to test with '%s': %s", test.fileName, test.name)
			} else {
				assert.EqualValuesf(t, test.expectedValue, realValued, "Failed to test with '%s': %s", test.fileName, test.name)
			}
		}
	})

	t.Run("TestReadDirNoStat", func(t *testing.T) {
		_, tmpFileSimpleName := filepath.Split(tmpFile.Name())
		_, tmpSymlinkSimpleName := filepath.Split(tmpSymlinkName)
		_, tmpSubDirSimpleName := filepath.Split(tmpSubDir)

		tests := []struct {
			name          string
			dirName       string
			expectedError bool
			expectedValue []string
		}{
			{"dir_not_exists", filepath.Join(tmpDir, "file_not_exist_case"), true, []string{}},
			{"dir_is_empty", "", false, []string{tmpFileSimpleName, tmpSymlinkSimpleName, tmpSubDirSimpleName}},
			{"dir_exists", tmpDir, false, []string{tmpFileSimpleName, tmpSymlinkSimpleName, tmpSubDirSimpleName}},
		}

		for _, test := range tests {
			realValued, realError := ReadDirNoStat(test.dirName)

			// execute sort action before compare
			sort.Strings(realValued)
			sort.Strings(test.expectedValue)

			if test.expectedError {
				assert.Errorf(t, realError, "Failed to test with '%s': %s", test.dirName, test.name)
			} else {
				assert.EqualValuesf(t, test.expectedValue, realValued, "Failed to test with '%s': %s", test.dirName, test.name)
			}
		}
	})
}
<|endoftext|>