<commit_before>package certificates

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/golang/glog"
	corev1 "k8s.io/api/core/v1"
	extv1beta1 "k8s.io/api/extensions/v1beta1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	coreinformers "k8s.io/client-go/informers/core/v1"
	extinformers "k8s.io/client-go/informers/extensions/v1beta1"
	"k8s.io/client-go/kubernetes"
	corelisters "k8s.io/client-go/listers/core/v1"
	extlisters "k8s.io/client-go/listers/extensions/v1beta1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"

	clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
	cminformers "github.com/jetstack/cert-manager/pkg/client/informers/externalversions/certmanager/v1alpha1"
	cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1alpha1"
	controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
	"github.com/jetstack/cert-manager/pkg/issuer"
	"github.com/jetstack/cert-manager/pkg/scheduler"
	"github.com/jetstack/cert-manager/pkg/util"
)

type Controller struct {
	client        kubernetes.Interface
	cmClient      clientset.Interface
	issuerFactory issuer.Factory
	recorder      record.EventRecorder

	// To allow injection for testing.
	syncHandler func(ctx context.Context, key string) error

	issuerLister        cmlisters.IssuerLister
	clusterIssuerLister cmlisters.ClusterIssuerLister
	certificateLister   cmlisters.CertificateLister
	secretLister        corelisters.SecretLister
	ingressLister       extlisters.IngressLister

	queue              workqueue.RateLimitingInterface
	scheduledWorkQueue scheduler.ScheduledWorkQueue
	workerWg           sync.WaitGroup
	syncedFuncs        []cache.InformerSynced
}

// New returns a new Certificates controller. It sets up the informer handler
// functions for all the types it watches.
func New(
	certificatesInformer cminformers.CertificateInformer,
	issuersInformer cminformers.IssuerInformer,
	clusterIssuersInformer cminformers.ClusterIssuerInformer,
	secretsInformer coreinformers.SecretInformer,
	ingressInformer extinformers.IngressInformer,
	podsInformer coreinformers.PodInformer,
	serviceInformer coreinformers.ServiceInformer,
	client kubernetes.Interface,
	cmClient clientset.Interface,
	issuerFactory issuer.Factory,
	recorder record.EventRecorder,
) *Controller {
	ctrl := &Controller{client: client, cmClient: cmClient, issuerFactory: issuerFactory, recorder: recorder}
	ctrl.syncHandler = ctrl.processNextWorkItem
	ctrl.queue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "certificates")
	// Create a scheduled work queue that calls the ctrl.queue.Add method for
	// each object in the queue. This is used to schedule re-checks of
	// Certificate resources when they get near to expiry
	ctrl.scheduledWorkQueue = scheduler.NewScheduledWorkQueue(ctrl.queue.Add)

	certificatesInformer.Informer().AddEventHandler(&controllerpkg.QueuingEventHandler{Queue: ctrl.queue})
	ctrl.certificateLister = certificatesInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, certificatesInformer.Informer().HasSynced)

	ctrl.issuerLister = issuersInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, issuersInformer.Informer().HasSynced)

	// clusterIssuersInformer may be nil if cert-manager is scoped to a single
	// namespace
	if clusterIssuersInformer != nil {
		ctrl.clusterIssuerLister = clusterIssuersInformer.Lister()
		ctrl.syncedFuncs = append(ctrl.syncedFuncs, clusterIssuersInformer.Informer().HasSynced)
	}

	secretsInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{WorkFunc: ctrl.secretDeleted})
	ctrl.secretLister = secretsInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, secretsInformer.Informer().HasSynced)

	ingressInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{WorkFunc: ctrl.ingressDeleted})
	ctrl.ingressLister = ingressInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, ingressInformer.Informer().HasSynced)

	ctrl.syncedFuncs = append(ctrl.syncedFuncs, podsInformer.Informer().HasSynced)
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, secretsInformer.Informer().HasSynced)

	return ctrl
}

// TODO: replace with generic handleObjet function (like Navigator)
func (c *Controller) secretDeleted(obj interface{}) {
	var secret *corev1.Secret
	var ok bool
	secret, ok = obj.(*corev1.Secret)
	if !ok {
		runtime.HandleError(fmt.Errorf("Object is not a Secret object %#v", obj))
		return
	}
	crts, err := c.certificatesForSecret(secret)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up Certificates observing Secret: %s/%s", secret.Namespace, secret.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *Controller) ingressDeleted(obj interface{}) {
	ingress, ok := obj.(*extv1beta1.Ingress)
	if !ok {
		runtime.HandleError(fmt.Errorf("Object is not an Ingress object %#v", obj))
		return
	}
	crts, err := c.certificatesForIngress(ingress)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up certificates observing Ingress: %s/%s", ingress.Namespace, ingress.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *Controller) Run(workers int, stopCh <-chan struct{}) error {
	glog.V(4).Infof("Starting %s control loop", ControllerName)
	// wait for all the informer caches we depend to sync
	if !cache.WaitForCacheSync(stopCh, c.syncedFuncs...) {
		return fmt.Errorf("error waiting for informer caches to sync")
	}

	glog.V(4).Infof("Synced all caches for %s control loop", ControllerName)

	for i := 0; i < workers; i++ {
		c.workerWg.Add(1)
		// TODO (@munnerz): make time.Second duration configurable
		go wait.Until(func() { c.worker(stopCh) }, time.Second, stopCh)
	}
	<-stopCh
	glog.V(4).Infof("Shutting down queue as workqueue signaled shutdown")
	c.queue.ShutDown()
	glog.V(4).Infof("Waiting for workers to exit...")
	c.workerWg.Wait()
	glog.V(4).Infof("Workers exited.")
	return nil
}

func (c *Controller) worker(stopCh <-chan struct{}) {
	defer c.workerWg.Done()
	glog.V(4).Infof("Starting %q worker", ControllerName)
	for {
		obj, shutdown := c.queue.Get()
		if shutdown {
			break
		}

		var key string
		err := func(obj interface{}) error {
			defer c.queue.Done(obj)
			var ok bool
			if key, ok = obj.(string); !ok {
				return nil
			}
			ctx, cancel := context.WithCancel(context.Background())
			defer cancel()
			ctx = util.ContextWithStopCh(ctx, stopCh)
			glog.Infof("%s controller: syncing item '%s'", ControllerName, key)
			if err := c.syncHandler(ctx, key); err != nil {
				return err
			}
			c.queue.Forget(obj)
			return nil
		}(obj)

		if err != nil {
			glog.Errorf("%s controller: Re-queuing item %q due to error processing: %s", ControllerName, key, err.Error())
			c.queue.AddRateLimited(obj)
			continue
		}

		glog.Infof("%s controller: Finished processing work item %q", ControllerName, key)
	}
	glog.V(4).Infof("Exiting %q worker loop", ControllerName)
}

func (c *Controller) processNextWorkItem(ctx context.Context, key string) error {
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		runtime.HandleError(fmt.Errorf("invalid resource key: %s", key))
		return nil
	}

	crt, err := c.certificateLister.Certificates(namespace).Get(name)

	if err != nil {
		if k8sErrors.IsNotFound(err) {
			c.scheduledWorkQueue.Forget(key)
			runtime.HandleError(fmt.Errorf("certificate '%s' in work queue no longer exists", key))
			return nil
		}

		return err
	}

	return c.Sync(ctx, crt)
}

var keyFunc = controllerpkg.KeyFunc

const (
	ControllerName = "certificates"
)

func init() {
	controllerpkg.Register(ControllerName, func(ctx *controllerpkg.Context) controllerpkg.Interface {
		var clusterIssuerInformer cminformers.ClusterIssuerInformer
		if ctx.Namespace == "" {
			clusterIssuerInformer = ctx.SharedInformerFactory.Certmanager().V1alpha1().ClusterIssuers()
		}
		return New(
			ctx.SharedInformerFactory.Certmanager().V1alpha1().Certificates(),
			ctx.SharedInformerFactory.Certmanager().V1alpha1().Issuers(),
			clusterIssuerInformer,
			ctx.KubeSharedInformerFactory.Core().V1().Secrets(),
			ctx.KubeSharedInformerFactory.Extensions().V1beta1().Ingresses(),
			ctx.KubeSharedInformerFactory.Core().V1().Pods(),
			ctx.KubeSharedInformerFactory.Core().V1().Services(),
			ctx.Client,
			ctx.CMClient,
			ctx.IssuerFactory,
			ctx.Recorder,
		).Run
	})
}
<commit_msg>Add comment explaining new HasSynced usages<commit_after>package certificates

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/golang/glog"
	corev1 "k8s.io/api/core/v1"
	extv1beta1 "k8s.io/api/extensions/v1beta1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	coreinformers "k8s.io/client-go/informers/core/v1"
	extinformers "k8s.io/client-go/informers/extensions/v1beta1"
	"k8s.io/client-go/kubernetes"
	corelisters "k8s.io/client-go/listers/core/v1"
	extlisters "k8s.io/client-go/listers/extensions/v1beta1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"

	clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
	cminformers "github.com/jetstack/cert-manager/pkg/client/informers/externalversions/certmanager/v1alpha1"
	cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1alpha1"
	controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
	"github.com/jetstack/cert-manager/pkg/issuer"
	"github.com/jetstack/cert-manager/pkg/scheduler"
	"github.com/jetstack/cert-manager/pkg/util"
)

type Controller struct {
	client        kubernetes.Interface
	cmClient      clientset.Interface
	issuerFactory issuer.Factory
	recorder      record.EventRecorder

	// To allow injection for testing.
	syncHandler func(ctx context.Context, key string) error

	issuerLister        cmlisters.IssuerLister
	clusterIssuerLister cmlisters.ClusterIssuerLister
	certificateLister   cmlisters.CertificateLister
	secretLister        corelisters.SecretLister
	ingressLister       extlisters.IngressLister

	queue              workqueue.RateLimitingInterface
	scheduledWorkQueue scheduler.ScheduledWorkQueue
	workerWg           sync.WaitGroup
	syncedFuncs        []cache.InformerSynced
}

// New returns a new Certificates controller. It sets up the informer handler
// functions for all the types it watches.
func New(
	certificatesInformer cminformers.CertificateInformer,
	issuersInformer cminformers.IssuerInformer,
	clusterIssuersInformer cminformers.ClusterIssuerInformer,
	secretsInformer coreinformers.SecretInformer,
	ingressInformer extinformers.IngressInformer,
	podsInformer coreinformers.PodInformer,
	serviceInformer coreinformers.ServiceInformer,
	client kubernetes.Interface,
	cmClient clientset.Interface,
	issuerFactory issuer.Factory,
	recorder record.EventRecorder,
) *Controller {
	ctrl := &Controller{client: client, cmClient: cmClient, issuerFactory: issuerFactory, recorder: recorder}
	ctrl.syncHandler = ctrl.processNextWorkItem
	ctrl.queue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "certificates")
	// Create a scheduled work queue that calls the ctrl.queue.Add method for
	// each object in the queue. This is used to schedule re-checks of
	// Certificate resources when they get near to expiry
	ctrl.scheduledWorkQueue = scheduler.NewScheduledWorkQueue(ctrl.queue.Add)

	certificatesInformer.Informer().AddEventHandler(&controllerpkg.QueuingEventHandler{Queue: ctrl.queue})
	ctrl.certificateLister = certificatesInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, certificatesInformer.Informer().HasSynced)

	ctrl.issuerLister = issuersInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, issuersInformer.Informer().HasSynced)

	// clusterIssuersInformer may be nil if cert-manager is scoped to a single
	// namespace
	if clusterIssuersInformer != nil {
		ctrl.clusterIssuerLister = clusterIssuersInformer.Lister()
		ctrl.syncedFuncs = append(ctrl.syncedFuncs, clusterIssuersInformer.Informer().HasSynced)
	}

	secretsInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{WorkFunc: ctrl.secretDeleted})
	ctrl.secretLister = secretsInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, secretsInformer.Informer().HasSynced)

	ingressInformer.Informer().AddEventHandler(&controllerpkg.BlockingEventHandler{WorkFunc: ctrl.ingressDeleted})
	ctrl.ingressLister = ingressInformer.Lister()
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, ingressInformer.Informer().HasSynced)

	// We also add pod and secret informers to the list of informers to sync.
	// They are not actually used directly by the Certificates controller,
	// however the ACME HTTP challenge solver *does* require a Pod and Secret
	// lister, and due to the way the instantiation of issuers is performed it
	// is far more performant to perform the sync here.
	// We should consider moving this into pkg/issuer/acme at some point, some how.
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, podsInformer.Informer().HasSynced)
	ctrl.syncedFuncs = append(ctrl.syncedFuncs, secretsInformer.Informer().HasSynced)

	return ctrl
}

// TODO: replace with generic handleObjet function (like Navigator)
func (c *Controller) secretDeleted(obj interface{}) {
	var secret *corev1.Secret
	var ok bool
	secret, ok = obj.(*corev1.Secret)
	if !ok {
		runtime.HandleError(fmt.Errorf("Object is not a Secret object %#v", obj))
		return
	}
	crts, err := c.certificatesForSecret(secret)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up Certificates observing Secret: %s/%s", secret.Namespace, secret.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *Controller) ingressDeleted(obj interface{}) {
	ingress, ok := obj.(*extv1beta1.Ingress)
	if !ok {
		runtime.HandleError(fmt.Errorf("Object is not an Ingress object %#v", obj))
		return
	}
	crts, err := c.certificatesForIngress(ingress)
	if err != nil {
		runtime.HandleError(fmt.Errorf("Error looking up certificates observing Ingress: %s/%s", ingress.Namespace, ingress.Name))
		return
	}
	for _, crt := range crts {
		key, err := keyFunc(crt)
		if err != nil {
			runtime.HandleError(err)
			continue
		}
		c.queue.Add(key)
	}
}

func (c *Controller) Run(workers int, stopCh <-chan struct{}) error {
	glog.V(4).Infof("Starting %s control loop", ControllerName)
	// wait for all the informer caches we depend to sync
	if !cache.WaitForCacheSync(stopCh, c.syncedFuncs...) {
		return fmt.Errorf("error waiting for informer caches to sync")
	}

	glog.V(4).Infof("Synced all caches for %s control loop", ControllerName)

	for i := 0; i < workers; i++ {
		c.workerWg.Add(1)
		// TODO (@munnerz): make time.Second duration configurable
		go wait.Until(func() { c.worker(stopCh) }, time.Second, stopCh)
	}
	<-stopCh
	glog.V(4).Infof("Shutting down queue as workqueue signaled shutdown")
	c.queue.ShutDown()
	glog.V(4).Infof("Waiting for workers to exit...")
	c.workerWg.Wait()
	glog.V(4).Infof("Workers exited.")
	return nil
}

func (c *Controller) worker(stopCh <-chan struct{}) {
	defer c.workerWg.Done()
	glog.V(4).Infof("Starting %q worker", ControllerName)
	for {
		obj, shutdown := c.queue.Get()
		if shutdown {
			break
		}

		var key string
		err := func(obj interface{}) error {
			defer c.queue.Done(obj)
			var ok bool
			if key, ok = obj.(string); !ok {
				return nil
			}
			ctx, cancel := context.WithCancel(context.Background())
			defer cancel()
			ctx = util.ContextWithStopCh(ctx, stopCh)
			glog.Infof("%s controller: syncing item '%s'", ControllerName, key)
			if err := c.syncHandler(ctx, key); err != nil {
				return err
			}
			c.queue.Forget(obj)
			return nil
		}(obj)

		if err != nil {
			glog.Errorf("%s controller: Re-queuing item %q due to error processing: %s", ControllerName, key, err.Error())
			c.queue.AddRateLimited(obj)
			continue
		}

		glog.Infof("%s controller: Finished processing work item %q", ControllerName, key)
	}
	glog.V(4).Infof("Exiting %q worker loop", ControllerName)
}

func (c *Controller) processNextWorkItem(ctx context.Context, key string) error {
	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		runtime.HandleError(fmt.Errorf("invalid resource key: %s", key))
		return nil
	}

	crt, err := c.certificateLister.Certificates(namespace).Get(name)

	if err != nil {
		if k8sErrors.IsNotFound(err) {
			c.scheduledWorkQueue.Forget(key)
			runtime.HandleError(fmt.Errorf("certificate '%s' in work queue no longer exists", key))
			return nil
		}

		return err
	}

	return c.Sync(ctx, crt)
}

var keyFunc = controllerpkg.KeyFunc

const (
	ControllerName = "certificates"
)

func init() {
	controllerpkg.Register(ControllerName, func(ctx *controllerpkg.Context) controllerpkg.Interface {
		var clusterIssuerInformer cminformers.ClusterIssuerInformer
		if ctx.Namespace == "" {
			clusterIssuerInformer = ctx.SharedInformerFactory.Certmanager().V1alpha1().ClusterIssuers()
		}
		return New(
			ctx.SharedInformerFactory.Certmanager().V1alpha1().Certificates(),
			ctx.SharedInformerFactory.Certmanager().V1alpha1().Issuers(),
			clusterIssuerInformer,
			ctx.KubeSharedInformerFactory.Core().V1().Secrets(),
			ctx.KubeSharedInformerFactory.Extensions().V1beta1().Ingresses(),
			ctx.KubeSharedInformerFactory.Core().V1().Pods(),
			ctx.KubeSharedInformerFactory.Core().V1().Services(),
			ctx.Client,
			ctx.CMClient,
			ctx.IssuerFactory,
			ctx.Recorder,
		).Run
	})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"os"
)

type configuration struct {
	cl       *flag.FlagSet
	username string
	password string
	noauth   bool
	register struct {
		username  string
		password  string
		firstName string
		lastName  string
		superuser bool
	}
}

func (c *configuration) init() {
	*c = configuration{
		cl: flag.NewFlagSet(os.Args[0], flag.ExitOnError),
	}

	c.cl.BoolVar(&c.noauth, "noauth", false, "noauth")
	c.cl.StringVar(&c.username, "username", "", "username")
	c.cl.StringVar(&c.password, "password", "", "password")
	c.cl.StringVar(&c.register.username, "r.username", "", "username")
	c.cl.StringVar(&c.register.password, "r.password", "", "password")
	c.cl.StringVar(&c.register.firstName, "r.firstname", "", "first name")
	c.cl.StringVar(&c.register.lastName, "r.lastname", "", "last name")
	c.cl.BoolVar(&c.register.superuser, "r.superuser", false, "superuser")
}

func (c *configuration) parse() {
	if c == nil || c.cl == nil {
		c.init()
	}
	if !c.cl.Parsed() {
		c.cl.Parse(os.Args[2:])
	}
}

func (c *configuration) cmd() string {
	return os.Args[1]
}
<commit_msg>#16 - no args panic fix<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
)

type configuration struct {
	cl       *flag.FlagSet
	username string
	password string
	noauth   bool
	register struct {
		username  string
		password  string
		firstName string
		lastName  string
		superuser bool
	}
}

func (c *configuration) init() {
	*c = configuration{
		cl: flag.NewFlagSet(os.Args[0], flag.ExitOnError),
	}

	c.cl.BoolVar(&c.noauth, "noauth", false, "noauth")
	c.cl.StringVar(&c.username, "username", "", "username")
	c.cl.StringVar(&c.password, "password", "", "password")
	c.cl.StringVar(&c.register.username, "r.username", "", "username")
	c.cl.StringVar(&c.register.password, "r.password", "", "password")
	c.cl.StringVar(&c.register.firstName, "r.firstname", "", "first name")
	c.cl.StringVar(&c.register.lastName, "r.lastname", "", "last name")
	c.cl.BoolVar(&c.register.superuser, "r.superuser", false, "superuser")
}

func (c *configuration) parse() {
	if c == nil || c.cl == nil {
		c.init()
	}
	if !c.cl.Parsed() {
		if len(os.Args) < 2 {
			// TODO: make it more verbose
			fmt.Println("action is required eg. register")
			os.Exit(1)
		} else {
			c.cl.Parse(os.Args[2:])
		}
	}
}

func (c *configuration) cmd() string {
	return os.Args[1]
}
<|endoftext|>


<commit_before>package btrfs

import (
	"io/ioutil"
	"testing"

	"./fs"
)

func TestIsSubvolume(t *testing.T) {
	b, err := IsSubvolume(".")
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("%q", b)
}

func testingImage() (string, error) {
	fh, err := ioutil.TempFile("", "btrfs-testing.")
	if err != nil {
		return "", err
	}

	// get a 1GB non-allocated file
	if err := fh.Truncate(1 * 1024 * 1024 * 1024); err != nil {
		return "", err
	}

	if err := fh.Close(); err != nil {
		return "", err
	}

	if err := fs.Mkfs(fh.Name()); err != nil {
		return "", err
	}
	return fh.Name(), nil
}
<commit_msg>test: fix type for go vet<commit_after>package btrfs

import (
	"io/ioutil"
	"testing"

	"./fs"
)

func TestIsSubvolume(t *testing.T) {
	b, err := IsSubvolume(".")
	if err != nil {
		t.Fatal(err)
	}
	t.Log(b)
}

func testingImage() (string, error) {
	fh, err := ioutil.TempFile("", "btrfs-testing.")
	if err != nil {
		return "", err
	}

	// get a 1GB non-allocated file
	if err := fh.Truncate(1 * 1024 * 1024 * 1024); err != nil {
		return "", err
	}

	if err := fh.Close(); err != nil {
		return "", err
	}

	if err := fs.Mkfs(fh.Name()); err != nil {
		return "", err
	}
	return fh.Name(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/bertbaron/solve"
	"sort"
)

const N = 16

type sortBytes []byte
func (b sortBytes) Len() int {
	return len(b)
}
func (b sortBytes) Less(i, j int) bool {
	return b[i] < b[j]
}
func (b sortBytes) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

type swapContext struct {
	size int
	goal [N]byte
}

type swapState struct {
	context *swapContext
	vector  [N]byte
	cost    float64
	op      int
}

func (s swapState) String() string {
	return fmt.Sprintf("%v, %d", s.vector[0:s.context.size], s.op)
}

func newSwapState(context *swapContext, vector [N]byte, cost float64, op int) swapState {
	return swapState{context, vector, cost, op}
}

func swapProblem(initialState []byte) swapState {
	if len(initialState) > N {
		panic(fmt.Sprintf("Maximum size of vector is %v, but found %v", N, len(initialState)))
	}
	var array [N]byte
	for i, v := range initialState {
		array[i]=v
	}
	sorted := array
	sort.Sort(sortBytes(sorted[0:len(initialState)]))
	context := &swapContext{len(initialState), sorted}
	return newSwapState(context, array, 0.0, -1)
}

// returns a copy of the given vector, where the element at index is swapped with its right neighbour
func swap(vector [N]byte, index int) [N]byte {
	vector[index], vector[index+1] = vector[index+1], vector[index]
	return vector
}

func (v swapState) Id() interface{} {
	return v.vector
}

func (v swapState) Expand() []solve.State {
	n := v.context.size - 1
	steps := make([]solve.State, n, n)
	for i := 0; i < n; i++ {
		steps[i] = newSwapState(v.context, swap(v.vector, i), v.cost + 1.0, i)
	}
	return steps
}

func (v swapState) IsGoal() bool {
	return v.vector == v.context.goal
}

func (v swapState) Cost() float64 {
	return v.cost
}

func (v swapState) Heuristic() float64 {
	goal := v.context.goal
	n := v.context.size
	offset := 0
	for i:=0; i < n; i++ {
		value := v.vector[i]
		for d:=0; d < n; d++ {
			l, r := i - d, i + d
			if l >= 0 && goal[l] == value || r < n && goal[r] == value {
				offset += d
				break
			}
		}
	}
	return float64(offset / 2)
}

func printSolution(node solve.Node) {
	if !node.Exists() {
		return
	}
	printSolution(node.Parent())
	swapstate := node.State().(swapState)
	for i, e := range swapstate.vector[0:swapstate.context.size] {
		if i > 0 {
			if i == swapstate.op + 1 {
				fmt.Print("x")
			} else {
				fmt.Printf(" ")
			}
		}
		fmt.Print(e)
	}
	fmt.Println()
}

func main() {
	state := swapProblem([]byte{7, 6, 5, 4, 3, 2, 1, 0})
	fmt.Printf("Sorting %v in minimal number of swaps of neighbouring elements\n", state)
	solution := solve.NewSolver(state).
		Algorithm(solve.IDAstar).
		Constraint(solve.CHEAPEST_PATH).
		Solve()

	fmt.Printf("visited: %d, expanded %d\n", solution.Visited, solution.Expanded)
	if !solution.Solution.Exists() {
		fmt.Printf("No solution found\n")
	} else {
		fmt.Printf("Solution found in %.0f steps\n", solution.Solution.State().Cost())
		printSolution(solution.Solution)
	}
}
<commit_msg>Swapsort example performance and code improvement<commit_after>package main

import (
	"fmt"
	"github.com/bertbaron/solve"
	"sort"
)

const N = 16

type sortBytes []byte
func (b sortBytes) Len() int {
	return len(b)
}
func (b sortBytes) Less(i, j int) bool {
	return b[i] < b[j]
}
func (b sortBytes) Swap(i, j int) {
	b[i], b[j] = b[j], b[i]
}

type swapContext struct {
	size int
	goal [N]byte
}

type swapState struct {
	context *swapContext
	vector  [N]byte
	cost    float64
	op      int
}

func asSlice(s swapState)  []byte {
	return s.vector[0:s.context.size]
}

func (s swapState) String() string {
	return fmt.Sprintf("%v, %d", asSlice(s), s.op)
}

func newSwapState(context *swapContext, vector [N]byte, cost float64, op int) swapState {
	return swapState{context, vector, cost, op}
}

func swapProblem(initialState []byte) swapState {
	if len(initialState) > N {
		panic(fmt.Sprintf("Maximum size of vector is %v, but found %v", N, len(initialState)))
	}
	var array [N]byte
	for i, v := range initialState {
		array[i]=v
	}
	sorted := array
	sort.Sort(sortBytes(sorted[0:len(initialState)]))
	context := &swapContext{len(initialState), sorted}
	return newSwapState(context, array, 0.0, -1)
}

// returns a copy of the given vector, where the element at index is swapped with its right neighbour
func swap(vector [N]byte, index int) [N]byte {
	vector[index], vector[index+1] = vector[index+1], vector[index]
	return vector
}

func (v swapState) Id() interface{} {
	return v.vector
}

func (v swapState) Expand() []solve.State {
	n := v.context.size - 1
	steps := make([]solve.State, n, n)
	for i := 0; i < n; i++ {
		steps[i] = newSwapState(v.context, swap(v.vector, i), v.cost + 1.0, i)
	}
	return steps
}

func (v swapState) IsGoal() bool {
	return v.vector == v.context.goal
}

func (v swapState) Cost() float64 {
	return v.cost
}

func (v swapState) Heuristic() float64 {
	goal := v.context.goal
	n := v.context.size
	offset := 0
	for i:=0; i < n; i++ {
		value := v.vector[i]
		for d:=0; d < n; d++ {
			l, r := i - d, i + d
			if l >= 0 && goal[l] == value || r < n && goal[r] == value {
				offset += d
				break
			}
		}
	}
	return float64(offset / 2)
}

func printSolution(node solve.Node) {
	if !node.Exists() {
		return
	}
	printSolution(node.Parent())
	swapstate := node.State().(swapState)
	for i, e := range asSlice(swapstate) {
		if i > 0 {
			if i == swapstate.op + 1 {
				fmt.Print("x")
			} else {
				fmt.Printf(" ")
			}
		}
		fmt.Print(e)
	}
	fmt.Println()
}

func main() {
	state := swapProblem([]byte{8, 7, 6, 5, 4, 3, 2, 1, 0})
	fmt.Printf("Sorting %v in minimal number of swaps of neighbouring elements\n", state)
	solution := solve.NewSolver(state).
		Algorithm(solve.IDAstar).
		Constraint(solve.CHEAPEST_PATH).
		Solve()

	fmt.Printf("visited: %d, expanded %d\n", solution.Visited, solution.Expanded)
	if !solution.Solution.Exists() {
		fmt.Printf("No solution found\n")
	} else {
		fmt.Printf("Solution found in %.0f steps\n", solution.Solution.State().Cost())
		printSolution(solution.Solution)
	}
}
<|endoftext|>


<commit_before>// +build !windows

package oci

import (
	"context"
	"path"
	"sync"

	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/contrib/seccomp"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/namespaces"
	"github.com/containerd/containerd/oci"
	"github.com/containerd/continuity/fs"
	"github.com/docker/docker/pkg/idtools"
	"github.com/mitchellh/hashstructure"
	"github.com/moby/buildkit/executor"
	"github.com/moby/buildkit/snapshot"
	"github.com/moby/buildkit/solver/pb"
	"github.com/moby/buildkit/util/entitlements"
	"github.com/moby/buildkit/util/network"
	"github.com/moby/buildkit/util/system"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
)

// Ideally we don't have to import whole containerd just for the default spec

// GenerateSpec generates spec using containerd functionality.
// opts are ignored for s.Process, s.Hostname, and s.Mounts .
func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, idmap *idtools.IdentityMapping, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
	c := &containers.Container{
		ID: id,
	}
	_, ok := namespaces.Namespace(ctx)
	if !ok {
		ctx = namespaces.WithNamespace(ctx, "buildkit")
	}
	if meta.SecurityMode == pb.SecurityMode_INSECURE {
		opts = append(opts, entitlements.WithInsecureSpec())
	} else if system.SeccompSupported() && meta.SecurityMode == pb.SecurityMode_SANDBOX {
		opts = append(opts, seccomp.WithDefaultProfile())
	}

	switch processMode {
	case NoProcessSandbox:
		// Mount for /proc is replaced in GetMounts()
		opts = append(opts,
			oci.WithHostNamespace(specs.PIDNamespace))
		// TODO(AkihiroSuda): Configure seccomp to disable ptrace (and prctl?) explicitly
	}

	// Note that containerd.GenerateSpec is namespaced so as to make
	// specs.Linux.CgroupsPath namespaced
	s, err := oci.GenerateSpec(ctx, nil, c, opts...)
	if err != nil {
		return nil, nil, err
	}
	// set the networking information on the spec
	namespace.Set(s)

	s.Process.Args = meta.Args
	s.Process.Env = meta.Env
	s.Process.Cwd = meta.Cwd
	s.Process.Rlimits = nil           // reset open files limit
	s.Process.NoNewPrivileges = false // reset nonewprivileges
	s.Hostname = "buildkitsandbox"

	s.Mounts, err = GetMounts(ctx,
		withProcessMode(processMode),
		withROBind(resolvConf, "/etc/resolv.conf"),
		withROBind(hostsFile, "/etc/hosts"),
	)
	if err != nil {
		return nil, nil, err
	}

	s.Mounts = append(s.Mounts, specs.Mount{
		Destination: "/sys/fs/cgroup",
		Type:        "cgroup",
		Source:      "cgroup",
		Options:     []string{"ro", "nosuid", "noexec", "nodev"},
	})

	if processMode == NoProcessSandbox {
		var maskedPaths []string
		for _, s := range s.Linux.MaskedPaths {
			if !hasPrefix(s, "/proc") {
				maskedPaths = append(maskedPaths, s)
			}
		}
		s.Linux.MaskedPaths = maskedPaths
		var readonlyPaths []string
		for _, s := range s.Linux.ReadonlyPaths {
			if !hasPrefix(s, "/proc") {
				readonlyPaths = append(readonlyPaths, s)
			}
		}
		s.Linux.ReadonlyPaths = readonlyPaths
	}

	if meta.SecurityMode == pb.SecurityMode_INSECURE {
		//make sysfs rw mount for insecure mode.
		for _, m := range s.Mounts {
			if m.Type == "sysfs" {
				m.Options = []string{"nosuid", "noexec", "nodev", "rw"}
			}
		}
	}

	if idmap != nil {
		s.Linux.Namespaces = append(s.Linux.Namespaces, specs.LinuxNamespace{
			Type: specs.UserNamespace,
		})
		s.Linux.UIDMappings = specMapping(idmap.UIDs())
		s.Linux.GIDMappings = specMapping(idmap.GIDs())
	}

	sm := &submounts{}

	var releasers []func() error
	releaseAll := func() {
		sm.cleanup()
		for _, f := range releasers {
			f()
		}
	}

	for _, m := range mounts {
		if m.Src == nil {
			return nil, nil, errors.Errorf("mount %s has no source", m.Dest)
		}
		mountable, err := m.Src.Mount(ctx, m.Readonly)
		if err != nil {
			releaseAll()
			return nil, nil, errors.Wrapf(err, "failed to mount %s", m.Dest)
		}
		mounts, err := mountable.Mount()
		if err != nil {
			releaseAll()
			return nil, nil, errors.WithStack(err)
		}
		releasers = append(releasers, mountable.Release)
		for _, mount := range mounts {
			mount, err = sm.subMount(mount, m.Selector)
			if err != nil {
				releaseAll()
				return nil, nil, err
			}
			s.Mounts = append(s.Mounts, specs.Mount{
				Destination: m.Dest,
				Type:        mount.Type,
				Source:      mount.Source,
				Options:     mount.Options,
			})
		}
	}

	return s, releaseAll, nil
}

type mountRef struct {
	mount   mount.Mount
	unmount func() error
}

type submounts struct {
	m map[uint64]mountRef
}

func (s *submounts) subMount(m mount.Mount, subPath string) (mount.Mount, error) {
	if path.Join("/", subPath) == "/" {
		return m, nil
	}
	if s.m == nil {
		s.m = map[uint64]mountRef{}
	}
	h, err := hashstructure.Hash(m, nil)
	if err != nil {
		return mount.Mount{}, nil
	}
	if mr, ok := s.m[h]; ok {
		sm, err := sub(mr.mount, subPath)
		if err != nil {
			return mount.Mount{}, nil
		}
		return sm, nil
	}

	lm := snapshot.LocalMounterWithMounts([]mount.Mount{m})

	mp, err := lm.Mount()
	if err != nil {
		return mount.Mount{}, err
	}

	opts := []string{"rbind"}
	for _, opt := range m.Options {
		if opt == "ro" {
			opts = append(opts, opt)
		}
	}

	s.m[h] = mountRef{
		mount: mount.Mount{
			Source:  mp,
			Type:    "bind",
			Options: opts,
		},
		unmount: lm.Unmount,
	}

	sm, err := sub(s.m[h].mount, subPath)
	if err != nil {
		return mount.Mount{}, err
	}
	return sm, nil
}

func (s *submounts) cleanup() {
	var wg sync.WaitGroup
	wg.Add(len(s.m))
	for _, m := range s.m {
		func(m mountRef) {
			go func() {
				m.unmount()
				wg.Done()
			}()
		}(m)
	}
	wg.Wait()
}

func sub(m mount.Mount, subPath string) (mount.Mount, error) {
	src, err := fs.RootPath(m.Source, subPath)
	if err != nil {
		return mount.Mount{}, err
	}
	m.Source = src
	return m, nil
}

func specMapping(s []idtools.IDMap) []specs.LinuxIDMapping {
	var ids []specs.LinuxIDMapping
	for _, item := range s {
		ids = append(ids, specs.LinuxIDMapping{
			HostID:      uint32(item.HostID),
			ContainerID: uint32(item.ContainerID),
			Size:        uint32(item.Size),
		})
	}
	return ids
}
<commit_msg>Fix updating /sys/fs/cgroup mount to 'rw'<commit_after>// +build !windows

package oci

import (
	"context"
	"path"
	"sync"

	"github.com/containerd/containerd/containers"
	"github.com/containerd/containerd/contrib/seccomp"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/namespaces"
	"github.com/containerd/containerd/oci"
	"github.com/containerd/continuity/fs"
	"github.com/docker/docker/pkg/idtools"
	"github.com/mitchellh/hashstructure"
	"github.com/moby/buildkit/executor"
	"github.com/moby/buildkit/snapshot"
	"github.com/moby/buildkit/solver/pb"
	"github.com/moby/buildkit/util/entitlements"
	"github.com/moby/buildkit/util/network"
	"github.com/moby/buildkit/util/system"
	specs "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
)

// Ideally we don't have to import whole containerd just for the default spec

// GenerateSpec generates spec using containerd functionality.
// opts are ignored for s.Process, s.Hostname, and s.Mounts .
func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, idmap *idtools.IdentityMapping, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
	c := &containers.Container{
		ID: id,
	}
	_, ok := namespaces.Namespace(ctx)
	if !ok {
		ctx = namespaces.WithNamespace(ctx, "buildkit")
	}
	if meta.SecurityMode == pb.SecurityMode_INSECURE {
		opts = append(opts, entitlements.WithInsecureSpec())
	} else if system.SeccompSupported() && meta.SecurityMode == pb.SecurityMode_SANDBOX {
		opts = append(opts, seccomp.WithDefaultProfile())
	}

	switch processMode {
	case NoProcessSandbox:
		// Mount for /proc is replaced in GetMounts()
		opts = append(opts,
			oci.WithHostNamespace(specs.PIDNamespace))
		// TODO(AkihiroSuda): Configure seccomp to disable ptrace (and prctl?) explicitly
	}

	// Note that containerd.GenerateSpec is namespaced so as to make
	// specs.Linux.CgroupsPath namespaced
	s, err := oci.GenerateSpec(ctx, nil, c, opts...)
	if err != nil {
		return nil, nil, err
	}
	// set the networking information on the spec
	namespace.Set(s)

	s.Process.Args = meta.Args
	s.Process.Env = meta.Env
	s.Process.Cwd = meta.Cwd
	s.Process.Rlimits = nil           // reset open files limit
	s.Process.NoNewPrivileges = false // reset nonewprivileges
	s.Hostname = "buildkitsandbox"

	s.Mounts, err = GetMounts(ctx,
		withProcessMode(processMode),
		withROBind(resolvConf, "/etc/resolv.conf"),
		withROBind(hostsFile, "/etc/hosts"),
	)
	if err != nil {
		return nil, nil, err
	}

	s.Mounts = append(s.Mounts, specs.Mount{
		Destination: "/sys/fs/cgroup",
		Type:        "cgroup",
		Source:      "cgroup",
		Options:     []string{"ro", "nosuid", "noexec", "nodev"},
	})

	if processMode == NoProcessSandbox {
		var maskedPaths []string
		for _, s := range s.Linux.MaskedPaths {
			if !hasPrefix(s, "/proc") {
				maskedPaths = append(maskedPaths, s)
			}
		}
		s.Linux.MaskedPaths = maskedPaths
		var readonlyPaths []string
		for _, s := range s.Linux.ReadonlyPaths {
			if !hasPrefix(s, "/proc") {
				readonlyPaths = append(readonlyPaths, s)
			}
		}
		s.Linux.ReadonlyPaths = readonlyPaths
	}

	if meta.SecurityMode == pb.SecurityMode_INSECURE {
		//make sysfs rw mount for insecure mode.
		for i, m := range s.Mounts {
			if m.Destination == "/sys/fs/cgroup" {
				s.Mounts[i].Options = []string{"nosuid", "noexec", "nodev", "rw"}
			}
		}
	}

	if idmap != nil {
		s.Linux.Namespaces = append(s.Linux.Namespaces, specs.LinuxNamespace{
			Type: specs.UserNamespace,
		})
		s.Linux.UIDMappings = specMapping(idmap.UIDs())
		s.Linux.GIDMappings = specMapping(idmap.GIDs())
	}

	sm := &submounts{}

	var releasers []func() error
	releaseAll := func() {
		sm.cleanup()
		for _, f := range releasers {
			f()
		}
	}

	for _, m := range mounts {
		if m.Src == nil {
			return nil, nil, errors.Errorf("mount %s has no source", m.Dest)
		}
		mountable, err := m.Src.Mount(ctx, m.Readonly)
		if err != nil {
			releaseAll()
			return nil, nil, errors.Wrapf(err, "failed to mount %s", m.Dest)
		}
		mounts, err := mountable.Mount()
		if err != nil {
			releaseAll()
			return nil, nil, errors.WithStack(err)
		}
		releasers = append(releasers, mountable.Release)
		for _, mount := range mounts {
			mount, err = sm.subMount(mount, m.Selector)
			if err != nil {
				releaseAll()
				return nil, nil, err
			}
			s.Mounts = append(s.Mounts, specs.Mount{
				Destination: m.Dest,
				Type:        mount.Type,
				Source:      mount.Source,
				Options:     mount.Options,
			})
		}
	}

	return s, releaseAll, nil
}

type mountRef struct {
	mount   mount.Mount
	unmount func() error
}

type submounts struct {
	m map[uint64]mountRef
}

func (s *submounts) subMount(m mount.Mount, subPath string) (mount.Mount, error) {
	if path.Join("/", subPath) == "/" {
		return m, nil
	}
	if s.m == nil {
		s.m = map[uint64]mountRef{}
	}
	h, err := hashstructure.Hash(m, nil)
	if err != nil {
		return mount.Mount{}, nil
	}
	if mr, ok := s.m[h]; ok {
		sm, err := sub(mr.mount, subPath)
		if err != nil {
			return mount.Mount{}, nil
		}
		return sm, nil
	}

	lm := snapshot.LocalMounterWithMounts([]mount.Mount{m})

	mp, err := lm.Mount()
	if err != nil {
		return mount.Mount{}, err
	}

	opts := []string{"rbind"}
	for _, opt := range m.Options {
		if opt == "ro" {
			opts = append(opts, opt)
		}
	}

	s.m[h] = mountRef{
		mount: mount.Mount{
			Source:  mp,
			Type:    "bind",
			Options: opts,
		},
		unmount: lm.Unmount,
	}

	sm, err := sub(s.m[h].mount, subPath)
	if err != nil {
		return mount.Mount{}, err
	}
	return sm, nil
}

func (s *submounts) cleanup() {
	var wg sync.WaitGroup
	wg.Add(len(s.m))
	for _, m := range s.m {
		func(m mountRef) {
			go func() {
				m.unmount()
				wg.Done()
			}()
		}(m)
	}
	wg.Wait()
}

func sub(m mount.Mount, subPath string) (mount.Mount, error) {
	src, err := fs.RootPath(m.Source, subPath)
	if err != nil {
		return mount.Mount{}, err
	}
	m.Source = src
	return m, nil
}

func specMapping(s []idtools.IDMap) []specs.LinuxIDMapping {
	var ids []specs.LinuxIDMapping
	for _, item := range s {
		ids = append(ids, specs.LinuxIDMapping{
			HostID:      uint32(item.HostID),
			ContainerID: uint32(item.ContainerID),
			Size:        uint32(item.Size),
		})
	}
	return ids
}
<|endoftext|>


<commit_before>package export

import (
	"fmt"

	mylog "github.com/patrickalin/GoMyLog"
	bloomskyStructure "github.com/patrickalin/bloomsky-client-go/bloomskyStructure"
)

//print major informations from a bloomsky JSON to console
func displayToConsole(onebloomsky bloomskyStructure.BloomskyStructure) {

	fmt.Printf("\nTimestamp : \t \t%s\n", onebloomsky.GetTimeStamp())
	fmt.Printf("City : \t \t \t%s\n", onebloomsky.GetCity())
	fmt.Printf("Device Id : \t \t%s\n", onebloomsky.GetDeviceID())
	fmt.Printf("Num Of Followers : \t%d\n", onebloomsky.GetNumOfFollowers())
	fmt.Printf("Index UV : \t \t%s\n", onebloomsky.GetIndexUV())
	fmt.Printf("Night : \t \t%t\n", onebloomsky.IsNight())
	fmt.Printf("Wind Direction : \t%s\n", onebloomsky.GetWindDirection())
	fmt.Printf("Wind Gust : \t \t%.2f mPh\n", onebloomsky.GetWindGustMph())
	fmt.Printf("Sustained Wind Speed : \t%.2f mPh\n", onebloomsky.GetSustainedWindSpeedMph())
	fmt.Printf("Wind Gust : \t \t%.2f km/h\n", onebloomsky.GetWindGustMs())
	fmt.Printf("Sustained Wind Speed : \t \t%.2f m/s\n", onebloomsky.GetSustainedWindSpeedMs())
	fmt.Printf("Rain : \t \t \t%t\n", onebloomsky.IsRain())
	fmt.Printf("Rain Daily : \t \t%.2f in\n", onebloomsky.GetRainDailyIn())
	fmt.Printf("24h Rain : \t \t%.2f in\n", onebloomsky.GetRainIn())
	fmt.Printf("Rain Rate : \t \t%.2f in\n", onebloomsky.GetRainRateIn())
	fmt.Printf("Rain Daily : \t \t%.2f mm\n", onebloomsky.GetRainDailyMm())
	fmt.Printf("24h Rain : \t \t%.2f mm\n", onebloomsky.GetRainMm())
	fmt.Printf("Rain Rate : \t \t%.2f mm\n", onebloomsky.GetRainRateMm())
	fmt.Printf("Temperature F : \t%.1f °F\n", onebloomsky.GetTemperatureFahrenheit())
	fmt.Printf("Temperature C : \t%.1f °C\n", onebloomsky.GetTemperatureCelsius())
	fmt.Printf("Humidity : \t \t%.f %%\n", onebloomsky.GetHumidity())
	fmt.Printf("Pressure InHg : \t%.1f inHg\n", onebloomsky.GetPressureInHg())
	fmt.Printf("Pressure HPa : \t \t%.1f hPa\n", onebloomsky.GetPressureHPa())
}

//InitConsole listen on the chanel
func InitConsole(messages chan bloomskyStructure.BloomskyStructure) {
	go func() {

		mylog.Trace.Println("Init the queue to receive message to export to console")

		for {
			mylog.Trace.Println("Receive message to export to console")
			msg := <-messages
			displayToConsole(msg)
		}
	}()
}
<commit_msg>Indent problem<commit_after>package export

import (
	"fmt"

	mylog "github.com/patrickalin/GoMyLog"
	bloomskyStructure "github.com/patrickalin/bloomsky-client-go/bloomskyStructure"
)

//print major informations from a bloomsky JSON to console
func displayToConsole(onebloomsky bloomskyStructure.BloomskyStructure) {

	fmt.Printf("\nTimestamp : \t \t%s\n", onebloomsky.GetTimeStamp())
	fmt.Printf("City : \t \t \t%s\n", onebloomsky.GetCity())
	fmt.Printf("Device Id : \t \t%s\n", onebloomsky.GetDeviceID())
	fmt.Printf("Num Of Followers : \t%d\n", onebloomsky.GetNumOfFollowers())
	fmt.Printf("Index UV : \t \t%s\n", onebloomsky.GetIndexUV())
	fmt.Printf("Night : \t \t%t\n", onebloomsky.IsNight())
	fmt.Printf("Wind Direction : \t%s\n", onebloomsky.GetWindDirection())
	fmt.Printf("Wind Gust : \t \t%.2f mPh\n", onebloomsky.GetWindGustMph())
	fmt.Printf("Sustained Wind Speed : \t%.2f mPh\n", onebloomsky.GetSustainedWindSpeedMph())
	fmt.Printf("Wind Gust : \t \t%.2f km/h\n", onebloomsky.GetWindGustMs())
	fmt.Printf("Sustained Wind Speed : \t%.2f m/s\n", onebloomsky.GetSustainedWindSpeedMs())
	fmt.Printf("Rain : \t \t \t%t\n", onebloomsky.IsRain())
	fmt.Printf("Rain Daily : \t \t%.2f in\n", onebloomsky.GetRainDailyIn())
	fmt.Printf("24h Rain : \t \t%.2f in\n", onebloomsky.GetRainIn())
	fmt.Printf("Rain Rate : \t \t%.2f in\n", onebloomsky.GetRainRateIn())
	fmt.Printf("Rain Daily : \t \t%.2f mm\n", onebloomsky.GetRainDailyMm())
	fmt.Printf("24h Rain : \t \t%.2f mm\n", onebloomsky.GetRainMm())
	fmt.Printf("Rain Rate : \t \t%.2f mm\n", onebloomsky.GetRainRateMm())
	fmt.Printf("Temperature F : \t%.1f °F\n", onebloomsky.GetTemperatureFahrenheit())
	fmt.Printf("Temperature C : \t%.1f °C\n", onebloomsky.GetTemperatureCelsius())
	fmt.Printf("Humidity : \t \t%.f %%\n", onebloomsky.GetHumidity())
	fmt.Printf("Pressure InHg : \t%.1f inHg\n", onebloomsky.GetPressureInHg())
	fmt.Printf("Pressure HPa : \t \t%.1f hPa\n", onebloomsky.GetPressureHPa())
}

//InitConsole listen on the chanel
func InitConsole(messages chan bloomskyStructure.BloomskyStructure) {
	go func() {

		mylog.Trace.Println("Init the queue to receive message to export to console")

		for {
			mylog.Trace.Println("Receive message to export to console")
			msg := <-messages
			displayToConsole(msg)
		}
	}()
}
<|endoftext|>


<commit_before>/*
Copyright 2019 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 digitalocean

import (
	"context"
	"errors"
	"fmt"

	"github.com/digitalocean/godo"
	apiv1 "k8s.io/api/core/v1"

	"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
	schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
)

const (
	doksLabelNamespace = "doks.digitalocean.com"
	nodeIDLabel        = doksLabelNamespace + "/node-id"
)

var (
	// ErrNodePoolNotExist is return if no node pool exists for a given cluster ID
	ErrNodePoolNotExist = errors.New("node pool does not exist")
)

// NodeGroup implements cloudprovider.NodeGroup interface. NodeGroup contains
// configuration info and functions to control a set of nodes that have the
// same capacity and set of labels.
type NodeGroup struct {
	id        string
	clusterID string
	client    nodeGroupClient
	nodePool  *godo.KubernetesNodePool

	minSize int
	maxSize int
}

// MaxSize returns maximum size of the node group.
func (n *NodeGroup) MaxSize() int {
	return n.maxSize
}

// MinSize returns minimum size of the node group.
func (n *NodeGroup) MinSize() int {
	return n.minSize
}

// TargetSize returns the current target size of the node group. It is possible
// that the number of nodes in Kubernetes is different at the moment but should
// be equal to Size() once everything stabilizes (new nodes finish startup and
// registration or removed nodes are deleted completely). Implementation
// required.
func (n *NodeGroup) TargetSize() (int, error) {
	return n.nodePool.Count, nil
}

// IncreaseSize increases the size of the node group. To delete a node you need
// to explicitly name it and use DeleteNode. This function should wait until
// node group size is updated. Implementation required.
func (n *NodeGroup) IncreaseSize(delta int) error {
	if delta <= 0 {
		return fmt.Errorf("delta must be positive, have: %d", delta)
	}

	targetSize := n.nodePool.Count + delta

	if targetSize > n.MaxSize() {
		return fmt.Errorf("size increase is too large. current: %d desired: %d max: %d",
			n.nodePool.Count, targetSize, n.MaxSize())
	}

	req := &godo.KubernetesNodePoolUpdateRequest{
		Count: &targetSize,
	}

	ctx := context.Background()
	updatedNodePool, _, err := n.client.UpdateNodePool(ctx, n.clusterID, n.id, req)
	if err != nil {
		return err
	}

	if updatedNodePool.Count != targetSize {
		return fmt.Errorf("couldn't increase size to %d (delta: %d). Current size is: %d",
			targetSize, delta, updatedNodePool.Count)
	}

	// update internal cache
	n.nodePool.Count = targetSize
	return nil
}

// DeleteNodes deletes nodes from this node group (and also increasing the size
// of the node group with that). Error is returned either on failure or if the
// given node doesn't belong to this node group. This function should wait
// until node group size is updated. Implementation required.
func (n *NodeGroup) DeleteNodes(nodes []*apiv1.Node) error {
	ctx := context.Background()
	for _, node := range nodes {
		nodeID, ok := node.Labels[nodeIDLabel]
		if !ok {
			// CA creates fake node objects to represent upcoming VMs that haven't
			// registered as nodes yet. They have node.Spec.ProviderID set. Use
			// that as nodeID.
			nodeID = node.Spec.ProviderID
		}

		_, err := n.client.DeleteNode(ctx, n.clusterID, n.id, nodeID, nil)
		if err != nil {
			return fmt.Errorf("deleting node failed for cluster: %q node pool: %q node: %q: %s",
				n.clusterID, n.id, nodeID, err)
		}

		// decrement the count by one  after a successful delete
		n.nodePool.Count--
	}

	return nil
}

// DecreaseTargetSize decreases the target size of the node group. This function
// doesn't permit to delete any existing node and can be used only to reduce the
// request for new nodes that have not been yet fulfilled. Delta should be negative.
// It is assumed that cloud provider will not delete the existing nodes when there
// is an option to just decrease the target. Implementation required.
func (n *NodeGroup) DecreaseTargetSize(delta int) error {
	if delta >= 0 {
		return fmt.Errorf("delta must be negative, have: %d", delta)
	}

	targetSize := n.nodePool.Count + delta
	if targetSize < n.MinSize() {
		return fmt.Errorf("size decrease is too small. current: %d desired: %d min: %d",
			n.nodePool.Count, targetSize, n.MinSize())
	}

	req := &godo.KubernetesNodePoolUpdateRequest{
		Count: &targetSize,
	}

	ctx := context.Background()
	updatedNodePool, _, err := n.client.UpdateNodePool(ctx, n.clusterID, n.id, req)
	if err != nil {
		return err
	}

	if updatedNodePool.Count != targetSize {
		return fmt.Errorf("couldn't increase size to %d (delta: %d). Current size is: %d",
			targetSize, delta, updatedNodePool.Count)
	}

	// update internal cache
	n.nodePool.Count = targetSize
	return nil
}

// Id returns an unique identifier of the node group.
func (n *NodeGroup) Id() string {
	return n.id
}

// Debug returns a string containing all information regarding this node group.
func (n *NodeGroup) Debug() string {
	return fmt.Sprintf("cluster ID: %s (min:%d max:%d)", n.Id(), n.MinSize(), n.MaxSize())
}

// Nodes returns a list of all nodes that belong to this node group.  It is
// required that Instance objects returned by this method have Id field set.
// Other fields are optional.
func (n *NodeGroup) Nodes() ([]cloudprovider.Instance, error) {
	if n.nodePool == nil {
		return nil, errors.New("node pool instance is not created")
	}

	//TODO(arslan): after increasing a node pool, the number of nodes is not
	//anymore equal to the cache here. We should return a placeholder node for
	//that. As an example PR check this out:
	//https://github.com/kubernetes/autoscaler/pull/2235
	return toInstances(n.nodePool.Nodes), nil
}

// TemplateNodeInfo returns a schedulerframework.NodeInfo structure of an empty
// (as if just started) node. This will be used in scale-up simulations to
// predict what would a new node look like if a node group was expanded. The
// returned NodeInfo is expected to have a fully populated Node object, with
// all of the labels, capacity and allocatable information as well as all pods
// that are started on the node by default, using manifest (most likely only
// kube-proxy). Implementation optional.
func (n *NodeGroup) TemplateNodeInfo() (*schedulerframework.NodeInfo, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// Exist checks if the node group really exists on the cloud provider side.
// Allows to tell the theoretical node group from the real one. Implementation
// required.
func (n *NodeGroup) Exist() bool {
	return n.nodePool != nil
}

// Create creates the node group on the cloud provider side. Implementation
// optional.
func (n *NodeGroup) Create() (cloudprovider.NodeGroup, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// Delete deletes the node group on the cloud provider side.  This will be
// executed only for autoprovisioned node groups, once their size drops to 0.
// Implementation optional.
func (n *NodeGroup) Delete() error {
	return cloudprovider.ErrNotImplemented
}

// Autoprovisioned returns true if the node group is autoprovisioned. An
// autoprovisioned group was created by CA and can be deleted when scaled to 0.
func (n *NodeGroup) Autoprovisioned() bool {
	return false
}

// toInstances converts a slice of *godo.KubernetesNode to
// cloudprovider.Instance
func toInstances(nodes []*godo.KubernetesNode) []cloudprovider.Instance {
	instances := make([]cloudprovider.Instance, 0, len(nodes))
	for _, nd := range nodes {
		instances = append(instances, toInstance(nd))
	}
	return instances
}

// toInstance converts the given *godo.KubernetesNode to a
// cloudprovider.Instance
func toInstance(node *godo.KubernetesNode) cloudprovider.Instance {
	return cloudprovider.Instance{
		Id:     toProviderID(node.DropletID),
		Status: toInstanceStatus(node.Status),
	}
}

// toInstanceStatus converts the given *godo.KubernetesNodeStatus to a
// cloudprovider.InstanceStatus
func toInstanceStatus(nodeState *godo.KubernetesNodeStatus) *cloudprovider.InstanceStatus {
	if nodeState == nil {
		return nil
	}

	st := &cloudprovider.InstanceStatus{}
	switch nodeState.State {
	case "provisioning":
		st.State = cloudprovider.InstanceCreating
	case "running":
		st.State = cloudprovider.InstanceRunning
	case "draining", "deleting":
		st.State = cloudprovider.InstanceDeleting
	default:
		st.ErrorInfo = &cloudprovider.InstanceErrorInfo{
			ErrorClass:   cloudprovider.OtherErrorClass,
			ErrorCode:    "no-code-digitalocean",
			ErrorMessage: nodeState.Message,
		}
	}

	return st
}
<commit_msg>DigitalOcean: do not use provider ID for node ID<commit_after>/*
Copyright 2019 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 digitalocean

import (
	"context"
	"errors"
	"fmt"

	"github.com/digitalocean/godo"
	apiv1 "k8s.io/api/core/v1"

	"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
	schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
)

const (
	doksLabelNamespace = "doks.digitalocean.com"
	nodeIDLabel        = doksLabelNamespace + "/node-id"
)

var (
	// ErrNodePoolNotExist is return if no node pool exists for a given cluster ID
	ErrNodePoolNotExist = errors.New("node pool does not exist")
)

// NodeGroup implements cloudprovider.NodeGroup interface. NodeGroup contains
// configuration info and functions to control a set of nodes that have the
// same capacity and set of labels.
type NodeGroup struct {
	id        string
	clusterID string
	client    nodeGroupClient
	nodePool  *godo.KubernetesNodePool

	minSize int
	maxSize int
}

// MaxSize returns maximum size of the node group.
func (n *NodeGroup) MaxSize() int {
	return n.maxSize
}

// MinSize returns minimum size of the node group.
func (n *NodeGroup) MinSize() int {
	return n.minSize
}

// TargetSize returns the current target size of the node group. It is possible
// that the number of nodes in Kubernetes is different at the moment but should
// be equal to Size() once everything stabilizes (new nodes finish startup and
// registration or removed nodes are deleted completely). Implementation
// required.
func (n *NodeGroup) TargetSize() (int, error) {
	return n.nodePool.Count, nil
}

// IncreaseSize increases the size of the node group. To delete a node you need
// to explicitly name it and use DeleteNode. This function should wait until
// node group size is updated. Implementation required.
func (n *NodeGroup) IncreaseSize(delta int) error {
	if delta <= 0 {
		return fmt.Errorf("delta must be positive, have: %d", delta)
	}

	targetSize := n.nodePool.Count + delta

	if targetSize > n.MaxSize() {
		return fmt.Errorf("size increase is too large. current: %d desired: %d max: %d",
			n.nodePool.Count, targetSize, n.MaxSize())
	}

	req := &godo.KubernetesNodePoolUpdateRequest{
		Count: &targetSize,
	}

	ctx := context.Background()
	updatedNodePool, _, err := n.client.UpdateNodePool(ctx, n.clusterID, n.id, req)
	if err != nil {
		return err
	}

	if updatedNodePool.Count != targetSize {
		return fmt.Errorf("couldn't increase size to %d (delta: %d). Current size is: %d",
			targetSize, delta, updatedNodePool.Count)
	}

	// update internal cache
	n.nodePool.Count = targetSize
	return nil
}

// DeleteNodes deletes nodes from this node group (and also increasing the size
// of the node group with that). Error is returned either on failure or if the
// given node doesn't belong to this node group. This function should wait
// until node group size is updated. Implementation required.
func (n *NodeGroup) DeleteNodes(nodes []*apiv1.Node) error {
	ctx := context.Background()
	for _, node := range nodes {
		nodeID, ok := node.Labels[nodeIDLabel]
		if !ok {
			// CA creates fake node objects to represent upcoming VMs that
			// haven't registered as nodes yet. We cannot delete the node at
			// this point.
			return fmt.Errorf("cannot delete node %q with provider ID %q on node pool %q: node ID label %q is missing", node.Name, node.Spec.ProviderID, n.id, nodeIDLabel)
		}

		_, err := n.client.DeleteNode(ctx, n.clusterID, n.id, nodeID, nil)
		if err != nil {
			return fmt.Errorf("deleting node failed for cluster: %q node pool: %q node: %q: %s",
				n.clusterID, n.id, nodeID, err)
		}

		// decrement the count by one  after a successful delete
		n.nodePool.Count--
	}

	return nil
}

// DecreaseTargetSize decreases the target size of the node group. This function
// doesn't permit to delete any existing node and can be used only to reduce the
// request for new nodes that have not been yet fulfilled. Delta should be negative.
// It is assumed that cloud provider will not delete the existing nodes when there
// is an option to just decrease the target. Implementation required.
func (n *NodeGroup) DecreaseTargetSize(delta int) error {
	if delta >= 0 {
		return fmt.Errorf("delta must be negative, have: %d", delta)
	}

	targetSize := n.nodePool.Count + delta
	if targetSize < n.MinSize() {
		return fmt.Errorf("size decrease is too small. current: %d desired: %d min: %d",
			n.nodePool.Count, targetSize, n.MinSize())
	}

	req := &godo.KubernetesNodePoolUpdateRequest{
		Count: &targetSize,
	}

	ctx := context.Background()
	updatedNodePool, _, err := n.client.UpdateNodePool(ctx, n.clusterID, n.id, req)
	if err != nil {
		return err
	}

	if updatedNodePool.Count != targetSize {
		return fmt.Errorf("couldn't increase size to %d (delta: %d). Current size is: %d",
			targetSize, delta, updatedNodePool.Count)
	}

	// update internal cache
	n.nodePool.Count = targetSize
	return nil
}

// Id returns an unique identifier of the node group.
func (n *NodeGroup) Id() string {
	return n.id
}

// Debug returns a string containing all information regarding this node group.
func (n *NodeGroup) Debug() string {
	return fmt.Sprintf("cluster ID: %s (min:%d max:%d)", n.Id(), n.MinSize(), n.MaxSize())
}

// Nodes returns a list of all nodes that belong to this node group.  It is
// required that Instance objects returned by this method have Id field set.
// Other fields are optional.
func (n *NodeGroup) Nodes() ([]cloudprovider.Instance, error) {
	if n.nodePool == nil {
		return nil, errors.New("node pool instance is not created")
	}

	//TODO(arslan): after increasing a node pool, the number of nodes is not
	//anymore equal to the cache here. We should return a placeholder node for
	//that. As an example PR check this out:
	//https://github.com/kubernetes/autoscaler/pull/2235
	return toInstances(n.nodePool.Nodes), nil
}

// TemplateNodeInfo returns a schedulerframework.NodeInfo structure of an empty
// (as if just started) node. This will be used in scale-up simulations to
// predict what would a new node look like if a node group was expanded. The
// returned NodeInfo is expected to have a fully populated Node object, with
// all of the labels, capacity and allocatable information as well as all pods
// that are started on the node by default, using manifest (most likely only
// kube-proxy). Implementation optional.
func (n *NodeGroup) TemplateNodeInfo() (*schedulerframework.NodeInfo, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// Exist checks if the node group really exists on the cloud provider side.
// Allows to tell the theoretical node group from the real one. Implementation
// required.
func (n *NodeGroup) Exist() bool {
	return n.nodePool != nil
}

// Create creates the node group on the cloud provider side. Implementation
// optional.
func (n *NodeGroup) Create() (cloudprovider.NodeGroup, error) {
	return nil, cloudprovider.ErrNotImplemented
}

// Delete deletes the node group on the cloud provider side.  This will be
// executed only for autoprovisioned node groups, once their size drops to 0.
// Implementation optional.
func (n *NodeGroup) Delete() error {
	return cloudprovider.ErrNotImplemented
}

// Autoprovisioned returns true if the node group is autoprovisioned. An
// autoprovisioned group was created by CA and can be deleted when scaled to 0.
func (n *NodeGroup) Autoprovisioned() bool {
	return false
}

// toInstances converts a slice of *godo.KubernetesNode to
// cloudprovider.Instance
func toInstances(nodes []*godo.KubernetesNode) []cloudprovider.Instance {
	instances := make([]cloudprovider.Instance, 0, len(nodes))
	for _, nd := range nodes {
		instances = append(instances, toInstance(nd))
	}
	return instances
}

// toInstance converts the given *godo.KubernetesNode to a
// cloudprovider.Instance
func toInstance(node *godo.KubernetesNode) cloudprovider.Instance {
	return cloudprovider.Instance{
		Id:     toProviderID(node.DropletID),
		Status: toInstanceStatus(node.Status),
	}
}

// toInstanceStatus converts the given *godo.KubernetesNodeStatus to a
// cloudprovider.InstanceStatus
func toInstanceStatus(nodeState *godo.KubernetesNodeStatus) *cloudprovider.InstanceStatus {
	if nodeState == nil {
		return nil
	}

	st := &cloudprovider.InstanceStatus{}
	switch nodeState.State {
	case "provisioning":
		st.State = cloudprovider.InstanceCreating
	case "running":
		st.State = cloudprovider.InstanceRunning
	case "draining", "deleting":
		st.State = cloudprovider.InstanceDeleting
	default:
		st.ErrorInfo = &cloudprovider.InstanceErrorInfo{
			ErrorClass:   cloudprovider.OtherErrorClass,
			ErrorCode:    "no-code-digitalocean",
			ErrorMessage: nodeState.Message,
		}
	}

	return st
}
<|endoftext|>


<commit_before>package ecs

import (
	"encoding/base64"
	"encoding/json"
	"strconv"
	"time"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/util"
)

// InstanceStatus represents instance status
type InstanceStatus string

// Constants of InstanceStatus
const (
	Creating = InstanceStatus("Creating")
	Running  = InstanceStatus("Running")
	Starting = InstanceStatus("Starting")

	Stopped  = InstanceStatus("Stopped")
	Stopping = InstanceStatus("Stopping")
)

type LockReason string

const (
	LockReasonFinancial = LockReason("financial")
	LockReasonSecurity  = LockReason("security")
)

type LockReasonType struct {
	LockReason LockReason
}

type DescribeInstanceStatusArgs struct {
	RegionId common.Region
	ZoneId   string
	common.Pagination
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instancestatusitemtype
type InstanceStatusItemType struct {
	InstanceId string
	Status     InstanceStatus
}

type DescribeInstanceStatusResponse struct {
	common.Response
	common.PaginationResult
	InstanceStatuses struct {
		InstanceStatus []InstanceStatusItemType
	}
}

// DescribeInstanceStatus describes instance status
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancestatus
func (client *Client) DescribeInstanceStatus(args *DescribeInstanceStatusArgs) (instanceStatuses []InstanceStatusItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstanceStatusResponse{}

	err = client.Invoke("DescribeInstanceStatus", args, &response)

	if err == nil {
		return response.InstanceStatuses.InstanceStatus, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type StopInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type StopInstanceResponse struct {
	common.Response
}

// StopInstance stops instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&stopinstance
func (client *Client) StopInstance(instanceId string, forceStop bool) error {
	args := StopInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := StopInstanceResponse{}
	err := client.Invoke("StopInstance", &args, &response)
	return err
}

type StartInstanceArgs struct {
	InstanceId string
}

type StartInstanceResponse struct {
	common.Response
}

// StartInstance starts instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&startinstance
func (client *Client) StartInstance(instanceId string) error {
	args := StartInstanceArgs{InstanceId: instanceId}
	response := StartInstanceResponse{}
	err := client.Invoke("StartInstance", &args, &response)
	return err
}

type RebootInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type RebootInstanceResponse struct {
	common.Response
}

// RebootInstance reboot instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&rebootinstance
func (client *Client) RebootInstance(instanceId string, forceStop bool) error {
	request := RebootInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := RebootInstanceResponse{}
	err := client.Invoke("RebootInstance", &request, &response)
	return err
}

type DescribeInstanceAttributeArgs struct {
	InstanceId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&operationlockstype
type OperationLocksType struct {
	LockReason []LockReasonType //enum for financial, security
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&securitygroupidsettype
type SecurityGroupIdSetType struct {
	SecurityGroupId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&ipaddresssettype
type IpAddressSetType struct {
	IpAddress []string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&vpcattributestype
type VpcAttributesType struct {
	VpcId            string
	VSwitchId        string
	PrivateIpAddress IpAddressSetType
	NatIpAddress     string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&eipaddressassociatetype
type EipAddressAssociateType struct {
	AllocationId       string
	IpAddress          string
	Bandwidth          int
	InternetChargeType common.InternetChargeType
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instanceattributestype
type InstanceAttributesType struct {
	InstanceId         string
	InstanceName       string
	Description        string
	ImageId            string
	RegionId           common.Region
	ZoneId             string
	CPU                int
	Memory             int
	ClusterId          string
	InstanceType       string
	InstanceTypeFamily string
	HostName           string
	SerialNumber       string
	Status             InstanceStatus
	OperationLocks     OperationLocksType
	SecurityGroupIds   struct {
		SecurityGroupId []string
	}
	PublicIpAddress         IpAddressSetType
	InnerIpAddress          IpAddressSetType
	InstanceNetworkType     string //enum Classic | Vpc
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	InternetChargeType      common.InternetChargeType
	CreationTime            util.ISO6801Time //time.Time
	VpcAttributes           VpcAttributesType
	EipAddress              EipAddressAssociateType
	IoOptimized             StringOrBool
	InstanceChargeType      common.InternetChargeType
	ExpiredTime             util.ISO6801Time
}

type DescribeInstanceAttributeResponse struct {
	common.Response
	InstanceAttributesType
}

// DescribeInstanceAttribute describes instance attribute
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstanceattribute
func (client *Client) DescribeInstanceAttribute(instanceId string) (instance *InstanceAttributesType, err error) {
	args := DescribeInstanceAttributeArgs{InstanceId: instanceId}

	response := DescribeInstanceAttributeResponse{}
	err = client.Invoke("DescribeInstanceAttribute", &args, &response)
	if err != nil {
		return nil, err
	}
	return &response.InstanceAttributesType, err
}

type ModifyInstanceAttributeArgs struct {
	InstanceId   string
	InstanceName string
	Description  string
	Password     string
	HostName     string
}

type ModifyInstanceAttributeResponse struct {
	common.Response
}

//ModifyInstanceAttribute  modify instance attrbute
//
// You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/modifyinstanceattribute.html
func (client *Client) ModifyInstanceAttribute(args *ModifyInstanceAttributeArgs) error {
	response := ModifyInstanceAttributeResponse{}
	err := client.Invoke("ModifyInstanceAttribute", args, &response)
	return err
}

// Default timeout value for WaitForInstance method
const InstanceDefaultTimeout = 120

// WaitForInstance waits for instance to given status
func (client *Client) WaitForInstance(instanceId string, status InstanceStatus, timeout int) error {
	if timeout <= 0 {
		timeout = InstanceDefaultTimeout
	}
	for {
		instance, err := client.DescribeInstanceAttribute(instanceId)
		if err != nil {
			return err
		}
		if instance.Status == status {
			//TODO
			//Sleep one more time for timing issues
			time.Sleep(DefaultWaitForInterval * time.Second)
			break
		}
		timeout = timeout - DefaultWaitForInterval
		if timeout <= 0 {
			return common.GetClientErrorFromString("Timeout")
		}
		time.Sleep(DefaultWaitForInterval * time.Second)

	}
	return nil
}

type DescribeInstanceVncUrlArgs struct {
	RegionId   common.Region
	InstanceId string
}

type DescribeInstanceVncUrlResponse struct {
	common.Response
	VncUrl string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancevncurl
func (client *Client) DescribeInstanceVncUrl(args *DescribeInstanceVncUrlArgs) (string, error) {
	response := DescribeInstanceVncUrlResponse{}

	err := client.Invoke("DescribeInstanceVncUrl", args, &response)

	if err == nil {
		return response.VncUrl, nil
	}

	return "", err
}

type DescribeInstancesArgs struct {
	RegionId            common.Region
	VpcId               string
	VSwitchId           string
	ZoneId              string
	InstanceIds         string
	InstanceNetworkType string
	InstanceName        string
	Status              InstanceStatus
	PrivateIpAddresses  string
	InnerIpAddresses    string
	PublicIpAddresses   string
	SecurityGroupId     string
	common.Pagination
}

type DescribeInstancesResponse struct {
	common.Response
	common.PaginationResult
	Instances struct {
		Instance []InstanceAttributesType
	}
}

// DescribeInstances describes instances
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstances
func (client *Client) DescribeInstances(args *DescribeInstancesArgs) (instances []InstanceAttributesType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstancesResponse{}

	err = client.Invoke("DescribeInstances", args, &response)

	if err == nil {
		return response.Instances.Instance, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type DeleteInstanceArgs struct {
	InstanceId string
}

type DeleteInstanceResponse struct {
	common.Response
}

// DeleteInstance deletes instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&deleteinstance
func (client *Client) DeleteInstance(instanceId string) error {
	args := DeleteInstanceArgs{InstanceId: instanceId}
	response := DeleteInstanceResponse{}
	err := client.Invoke("DeleteInstance", &args, &response)
	return err
}

type DataDiskType struct {
	Size               int
	Category           DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	SnapshotId         string
	DiskName           string
	Description        string
	Device             string
	DeleteWithInstance bool
}

type SystemDiskType struct {
	Size        int
	Category    DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	DiskName    string
	Description string
}

type IoOptimized string

type StringOrBool struct {
	Value bool
}

// UnmarshalJSON implements the json.Unmarshaller interface.
func (io *StringOrBool) UnmarshalJSON(value []byte) error {
	if value[0] == '"' {
		var str string
		err := json.Unmarshal(value, &str)
		if err == nil {
			io.Value = (str == "true" || str == "optimized")
		}
		return err
	}
	var boolVal bool
	err := json.Unmarshal(value, &boolVal)
	if err == nil {
		io.Value = boolVal
	}
	return err
}

func (io StringOrBool) Bool() bool {
	return io.Value
}

func (io StringOrBool) String() string {
	return strconv.FormatBool(io.Value)
}

var (
	IoOptimizedNone      = IoOptimized("none")
	IoOptimizedOptimized = IoOptimized("optimized")
)

type CreateInstanceArgs struct {
	RegionId                common.Region
	ZoneId                  string
	ImageId                 string
	InstanceType            string
	SecurityGroupId         string
	InstanceName            string
	Description             string
	InternetChargeType      common.InternetChargeType
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	HostName                string
	Password                string
	IoOptimized             IoOptimized
	SystemDisk              SystemDiskType
	DataDisk                []DataDiskType
	VSwitchId               string
	PrivateIpAddress        string
	ClientToken             string
	InstanceChargeType      common.InstanceChargeType
	Period                  int
	UserData                string
}

type CreateInstanceResponse struct {
	common.Response
	InstanceId string
}

// CreateInstance creates instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&createinstance
func (client *Client) CreateInstance(args *CreateInstanceArgs) (instanceId string, err error) {
	if args.UserData != "" {
		// Encode to base64 string
		args.UserData = base64.StdEncoding.EncodeToString([]byte(args.UserData))
	}
	response := CreateInstanceResponse{}
	err = client.Invoke("CreateInstance", args, &response)
	if err != nil {
		return "", err
	}
	return response.InstanceId, err
}

type SecurityGroupArgs struct {
	InstanceId      string
	SecurityGroupId string
}

type SecurityGroupResponse struct {
	common.Response
}

//JoinSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/joinsecuritygroup.html
func (client *Client) JoinSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("JoinSecurityGroup", &args, &response)
	return err
}

//LeaveSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/leavesecuritygroup.html
func (client *Client) LeaveSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("LeaveSecurityGroup", &args, &response)
	return err
}
<commit_msg>fix miss-spelling<commit_after>package ecs

import (
	"encoding/base64"
	"encoding/json"
	"strconv"
	"time"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/util"
)

// InstanceStatus represents instance status
type InstanceStatus string

// Constants of InstanceStatus
const (
	Creating = InstanceStatus("Creating")
	Running  = InstanceStatus("Running")
	Starting = InstanceStatus("Starting")

	Stopped  = InstanceStatus("Stopped")
	Stopping = InstanceStatus("Stopping")
)

type LockReason string

const (
	LockReasonFinancial = LockReason("financial")
	LockReasonSecurity  = LockReason("security")
)

type LockReasonType struct {
	LockReason LockReason
}

type DescribeInstanceStatusArgs struct {
	RegionId common.Region
	ZoneId   string
	common.Pagination
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instancestatusitemtype
type InstanceStatusItemType struct {
	InstanceId string
	Status     InstanceStatus
}

type DescribeInstanceStatusResponse struct {
	common.Response
	common.PaginationResult
	InstanceStatuses struct {
		InstanceStatus []InstanceStatusItemType
	}
}

// DescribeInstanceStatus describes instance status
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancestatus
func (client *Client) DescribeInstanceStatus(args *DescribeInstanceStatusArgs) (instanceStatuses []InstanceStatusItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstanceStatusResponse{}

	err = client.Invoke("DescribeInstanceStatus", args, &response)

	if err == nil {
		return response.InstanceStatuses.InstanceStatus, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type StopInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type StopInstanceResponse struct {
	common.Response
}

// StopInstance stops instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&stopinstance
func (client *Client) StopInstance(instanceId string, forceStop bool) error {
	args := StopInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := StopInstanceResponse{}
	err := client.Invoke("StopInstance", &args, &response)
	return err
}

type StartInstanceArgs struct {
	InstanceId string
}

type StartInstanceResponse struct {
	common.Response
}

// StartInstance starts instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&startinstance
func (client *Client) StartInstance(instanceId string) error {
	args := StartInstanceArgs{InstanceId: instanceId}
	response := StartInstanceResponse{}
	err := client.Invoke("StartInstance", &args, &response)
	return err
}

type RebootInstanceArgs struct {
	InstanceId string
	ForceStop  bool
}

type RebootInstanceResponse struct {
	common.Response
}

// RebootInstance reboot instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&rebootinstance
func (client *Client) RebootInstance(instanceId string, forceStop bool) error {
	request := RebootInstanceArgs{
		InstanceId: instanceId,
		ForceStop:  forceStop,
	}
	response := RebootInstanceResponse{}
	err := client.Invoke("RebootInstance", &request, &response)
	return err
}

type DescribeInstanceAttributeArgs struct {
	InstanceId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&operationlockstype
type OperationLocksType struct {
	LockReason []LockReasonType //enum for financial, security
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&securitygroupidsettype
type SecurityGroupIdSetType struct {
	SecurityGroupId string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&ipaddresssettype
type IpAddressSetType struct {
	IpAddress []string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&vpcattributestype
type VpcAttributesType struct {
	VpcId            string
	VSwitchId        string
	PrivateIpAddress IpAddressSetType
	NatIpAddress     string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&eipaddressassociatetype
type EipAddressAssociateType struct {
	AllocationId       string
	IpAddress          string
	Bandwidth          int
	InternetChargeType common.InternetChargeType
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/datatype&instanceattributestype
type InstanceAttributesType struct {
	InstanceId         string
	InstanceName       string
	Description        string
	ImageId            string
	RegionId           common.Region
	ZoneId             string
	CPU                int
	Memory             int
	ClusterId          string
	InstanceType       string
	InstanceTypeFamily string
	HostName           string
	SerialNumber       string
	Status             InstanceStatus
	OperationLocks     OperationLocksType
	SecurityGroupIds   struct {
		SecurityGroupId []string
	}
	PublicIpAddress         IpAddressSetType
	InnerIpAddress          IpAddressSetType
	InstanceNetworkType     string //enum Classic | Vpc
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	InternetChargeType      common.InternetChargeType
	CreationTime            util.ISO6801Time //time.Time
	VpcAttributes           VpcAttributesType
	EipAddress              EipAddressAssociateType
	IoOptimized             StringOrBool
	InstanceChargeType      common.InstanceChargeType
	ExpiredTime             util.ISO6801Time
}

type DescribeInstanceAttributeResponse struct {
	common.Response
	InstanceAttributesType
}

// DescribeInstanceAttribute describes instance attribute
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstanceattribute
func (client *Client) DescribeInstanceAttribute(instanceId string) (instance *InstanceAttributesType, err error) {
	args := DescribeInstanceAttributeArgs{InstanceId: instanceId}

	response := DescribeInstanceAttributeResponse{}
	err = client.Invoke("DescribeInstanceAttribute", &args, &response)
	if err != nil {
		return nil, err
	}
	return &response.InstanceAttributesType, err
}

type ModifyInstanceAttributeArgs struct {
	InstanceId   string
	InstanceName string
	Description  string
	Password     string
	HostName     string
}

type ModifyInstanceAttributeResponse struct {
	common.Response
}

//ModifyInstanceAttribute  modify instance attrbute
//
// You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/modifyinstanceattribute.html
func (client *Client) ModifyInstanceAttribute(args *ModifyInstanceAttributeArgs) error {
	response := ModifyInstanceAttributeResponse{}
	err := client.Invoke("ModifyInstanceAttribute", args, &response)
	return err
}

// Default timeout value for WaitForInstance method
const InstanceDefaultTimeout = 120

// WaitForInstance waits for instance to given status
func (client *Client) WaitForInstance(instanceId string, status InstanceStatus, timeout int) error {
	if timeout <= 0 {
		timeout = InstanceDefaultTimeout
	}
	for {
		instance, err := client.DescribeInstanceAttribute(instanceId)
		if err != nil {
			return err
		}
		if instance.Status == status {
			//TODO
			//Sleep one more time for timing issues
			time.Sleep(DefaultWaitForInterval * time.Second)
			break
		}
		timeout = timeout - DefaultWaitForInterval
		if timeout <= 0 {
			return common.GetClientErrorFromString("Timeout")
		}
		time.Sleep(DefaultWaitForInterval * time.Second)

	}
	return nil
}

type DescribeInstanceVncUrlArgs struct {
	RegionId   common.Region
	InstanceId string
}

type DescribeInstanceVncUrlResponse struct {
	common.Response
	VncUrl string
}

//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstancevncurl
func (client *Client) DescribeInstanceVncUrl(args *DescribeInstanceVncUrlArgs) (string, error) {
	response := DescribeInstanceVncUrlResponse{}

	err := client.Invoke("DescribeInstanceVncUrl", args, &response)

	if err == nil {
		return response.VncUrl, nil
	}

	return "", err
}

type DescribeInstancesArgs struct {
	RegionId            common.Region
	VpcId               string
	VSwitchId           string
	ZoneId              string
	InstanceIds         string
	InstanceNetworkType string
	InstanceName        string
	Status              InstanceStatus
	PrivateIpAddresses  string
	InnerIpAddresses    string
	PublicIpAddresses   string
	SecurityGroupId     string
	common.Pagination
}

type DescribeInstancesResponse struct {
	common.Response
	common.PaginationResult
	Instances struct {
		Instance []InstanceAttributesType
	}
}

// DescribeInstances describes instances
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&describeinstances
func (client *Client) DescribeInstances(args *DescribeInstancesArgs) (instances []InstanceAttributesType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstancesResponse{}

	err = client.Invoke("DescribeInstances", args, &response)

	if err == nil {
		return response.Instances.Instance, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type DeleteInstanceArgs struct {
	InstanceId string
}

type DeleteInstanceResponse struct {
	common.Response
}

// DeleteInstance deletes instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&deleteinstance
func (client *Client) DeleteInstance(instanceId string) error {
	args := DeleteInstanceArgs{InstanceId: instanceId}
	response := DeleteInstanceResponse{}
	err := client.Invoke("DeleteInstance", &args, &response)
	return err
}

type DataDiskType struct {
	Size               int
	Category           DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	SnapshotId         string
	DiskName           string
	Description        string
	Device             string
	DeleteWithInstance bool
}

type SystemDiskType struct {
	Size        int
	Category    DiskCategory //Enum cloud, ephemeral, ephemeral_ssd
	DiskName    string
	Description string
}

type IoOptimized string

type StringOrBool struct {
	Value bool
}

// UnmarshalJSON implements the json.Unmarshaller interface.
func (io *StringOrBool) UnmarshalJSON(value []byte) error {
	if value[0] == '"' {
		var str string
		err := json.Unmarshal(value, &str)
		if err == nil {
			io.Value = (str == "true" || str == "optimized")
		}
		return err
	}
	var boolVal bool
	err := json.Unmarshal(value, &boolVal)
	if err == nil {
		io.Value = boolVal
	}
	return err
}

func (io StringOrBool) Bool() bool {
	return io.Value
}

func (io StringOrBool) String() string {
	return strconv.FormatBool(io.Value)
}

var (
	IoOptimizedNone      = IoOptimized("none")
	IoOptimizedOptimized = IoOptimized("optimized")
)

type CreateInstanceArgs struct {
	RegionId                common.Region
	ZoneId                  string
	ImageId                 string
	InstanceType            string
	SecurityGroupId         string
	InstanceName            string
	Description             string
	InternetChargeType      common.InternetChargeType
	InternetMaxBandwidthIn  int
	InternetMaxBandwidthOut int
	HostName                string
	Password                string
	IoOptimized             IoOptimized
	SystemDisk              SystemDiskType
	DataDisk                []DataDiskType
	VSwitchId               string
	PrivateIpAddress        string
	ClientToken             string
	InstanceChargeType      common.InstanceChargeType
	Period                  int
	UserData                string
}

type CreateInstanceResponse struct {
	common.Response
	InstanceId string
}

// CreateInstance creates instance
//
// You can read doc at http://docs.aliyun.com/#/pub/ecs/open-api/instance&createinstance
func (client *Client) CreateInstance(args *CreateInstanceArgs) (instanceId string, err error) {
	if args.UserData != "" {
		// Encode to base64 string
		args.UserData = base64.StdEncoding.EncodeToString([]byte(args.UserData))
	}
	response := CreateInstanceResponse{}
	err = client.Invoke("CreateInstance", args, &response)
	if err != nil {
		return "", err
	}
	return response.InstanceId, err
}

type SecurityGroupArgs struct {
	InstanceId      string
	SecurityGroupId string
}

type SecurityGroupResponse struct {
	common.Response
}

//JoinSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/joinsecuritygroup.html
func (client *Client) JoinSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("JoinSecurityGroup", &args, &response)
	return err
}

//LeaveSecurityGroup
//
//You can read doc at https://help.aliyun.com/document_detail/ecs/open-api/instance/leavesecuritygroup.html
func (client *Client) LeaveSecurityGroup(instanceId string, securityGroupId string) error {
	args := SecurityGroupArgs{InstanceId: instanceId, SecurityGroupId: securityGroupId}
	response := SecurityGroupResponse{}
	err := client.Invoke("LeaveSecurityGroup", &args, &response)
	return err
}
<|endoftext|>


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

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

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

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

package update

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"os/exec"
	"regexp"
	"text/template"
	"time"

	"github.com/cenkalti/backoff/v4"

	"k8s.io/klog/v2"
)

const (
	// FSRoot is a relative (to scripts in subfolders) root folder of local filesystem repo to update
	FSRoot = "../../../"
)

var (
	target = os.Getenv("UPDATE_TARGET")
)

// init klog and check general requirements
func init() {
	klog.InitFlags(nil)
	if err := flag.Set("logtostderr", "false"); err != nil {
		klog.Warningf("Unable to set flag value for logtostderr: %v", err)
	}
	if err := flag.Set("alsologtostderr", "true"); err != nil {
		klog.Warningf("Unable to set flag value for alsologtostderr: %v", err)
	}

	// used in update_kubeadm_constants.go
	flag.String("kubernetes-version", "latest", "kubernetes-version")
	flag.Parse()
	defer klog.Flush()
}

// Item defines Content where all occurrences of each Replace map key,
// corresponding to GitHub TreeEntry.Path and/or local filesystem repo file path (prefixed with FSRoot),
// would be swapped with its respective actual map value (having placeholders replaced with data), creating a concrete update plan.
// Replace map keys can use RegExp and map values can use Golang Text Template.
type Item struct {
	Content []byte
	Replace map[string]string
}

// apply updates Item Content by replacing all occurrences of Replace map's keys with their actual map values (with placeholders replaced with data).
func (i *Item) apply(data interface{}) error {
	if i.Content == nil {
		return fmt.Errorf("unable to update content: nothing to update")
	}
	str := string(i.Content)
	for src, dst := range i.Replace {
		out, err := ParseTmpl(dst, data, "")
		if err != nil {
			return err
		}
		re := regexp.MustCompile(src)
		str = re.ReplaceAllString(str, out)
	}
	i.Content = []byte(str)

	return nil
}

// Apply applies concrete update plan (schema + data) to local filesystem repo
func Apply(schema map[string]Item, data interface{}) {
	schema, pretty, err := GetPlan(schema, data)
	if err != nil {
		klog.Fatalf("Unable to parse schema: %v\n%s", err, pretty)
	}
	klog.Infof("The Plan:\n%s", pretty)

	changed, err := fsUpdate(FSRoot, schema, data)
	if err != nil {
		klog.Errorf("Unable to update local repo: %v", err)
	} else if !changed {
		klog.Infof("Local repo update skipped: nothing changed")
	} else {
		klog.Infof("Local repo successfully updated")
	}
}

// GetPlan returns concrete plan replacing placeholders in schema with actual data values, returns JSON-formatted representation of the plan and any error occurred.
func GetPlan(schema map[string]Item, data interface{}) (plan map[string]Item, prettyprint string, err error) {
	plan = make(map[string]Item)
	for p, item := range schema {
		path, err := ParseTmpl(p, data, "")
		if err != nil {
			return plan, fmt.Sprintf("%+v", schema), err
		}
		plan[path] = item
	}

	for _, item := range plan {
		for src, dst := range item.Replace {
			out, err := ParseTmpl(dst, data, "")
			if err != nil {
				return plan, fmt.Sprintf("%+v", schema), err
			}
			item.Replace[src] = out
		}
	}
	str, err := json.MarshalIndent(plan, "", "  ")
	if err != nil {
		return plan, fmt.Sprintf("%+v", schema), err
	}

	return plan, string(str), nil
}

// RunWithRetryNotify runs command cmd with stdin using exponential backoff for maxTime duration
// up to maxRetries (negative values will make it ignored),
// notifies about any intermediary errors and return any final error.
// similar to pkg/util/retry/retry.go:Expo(), just for commands with params and also with context
func RunWithRetryNotify(ctx context.Context, cmd *exec.Cmd, stdin io.Reader, maxTime time.Duration, maxRetries uint64) error {
	be := backoff.NewExponentialBackOff()
	be.Multiplier = 2
	be.MaxElapsedTime = maxTime
	bm := backoff.WithMaxRetries(be, maxRetries)
	bc := backoff.WithContext(bm, ctx)

	notify := func(err error, wait time.Duration) {
		klog.Errorf("Temporary error running '%s' (will retry in %s): %v", cmd.String(), wait, err)
	}
	return backoff.RetryNotify(func() error {
		cmd.Stdin = stdin
		var stderr bytes.Buffer
		cmd.Stderr = &stderr
		if err := cmd.Run(); err != nil {
			time.Sleep(be.NextBackOff().Round(1 * time.Second))
			return fmt.Errorf("%w: %s", err, stderr.String())
		}
		return nil
	}, bc, notify)
}

// Run runs command cmd with stdin
func Run(cmd *exec.Cmd, stdin io.Reader) error {
	cmd.Stdin = stdin
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("%w: %s", err, out.String())
	}
	return nil
}

// ParseTmpl replaces placeholders in text with actual data values
func ParseTmpl(text string, data interface{}, name string) (string, error) {
	tmpl := template.Must(template.New(name).Parse(text))
	buf := new(bytes.Buffer)
	if err := tmpl.Execute(buf, data); err != nil {
		return "", err
	}
	return buf.String(), nil
}
<commit_msg>linting<commit_after>/*
Copyright 2020 The Kubernetes Authors All rights reserved.

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

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

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

package update

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os/exec"
	"regexp"
	"text/template"
	"time"

	"github.com/cenkalti/backoff/v4"

	"k8s.io/klog/v2"
)

const (
	// FSRoot is a relative (to scripts in subfolders) root folder of local filesystem repo to update
	FSRoot = "../../../"
)

// init klog and check general requirements
func init() {
	klog.InitFlags(nil)
	if err := flag.Set("logtostderr", "false"); err != nil {
		klog.Warningf("Unable to set flag value for logtostderr: %v", err)
	}
	if err := flag.Set("alsologtostderr", "true"); err != nil {
		klog.Warningf("Unable to set flag value for alsologtostderr: %v", err)
	}

	// used in update_kubeadm_constants.go
	flag.String("kubernetes-version", "latest", "kubernetes-version")
	flag.Parse()
	defer klog.Flush()
}

// Item defines Content where all occurrences of each Replace map key,
// corresponding to GitHub TreeEntry.Path and/or local filesystem repo file path (prefixed with FSRoot),
// would be swapped with its respective actual map value (having placeholders replaced with data), creating a concrete update plan.
// Replace map keys can use RegExp and map values can use Golang Text Template.
type Item struct {
	Content []byte
	Replace map[string]string
}

// apply updates Item Content by replacing all occurrences of Replace map's keys with their actual map values (with placeholders replaced with data).
func (i *Item) apply(data interface{}) error {
	if i.Content == nil {
		return fmt.Errorf("unable to update content: nothing to update")
	}
	str := string(i.Content)
	for src, dst := range i.Replace {
		out, err := ParseTmpl(dst, data, "")
		if err != nil {
			return err
		}
		re := regexp.MustCompile(src)
		str = re.ReplaceAllString(str, out)
	}
	i.Content = []byte(str)

	return nil
}

// Apply applies concrete update plan (schema + data) to local filesystem repo
func Apply(schema map[string]Item, data interface{}) {
	schema, pretty, err := GetPlan(schema, data)
	if err != nil {
		klog.Fatalf("Unable to parse schema: %v\n%s", err, pretty)
	}
	klog.Infof("The Plan:\n%s", pretty)

	changed, err := fsUpdate(FSRoot, schema, data)
	if err != nil {
		klog.Errorf("Unable to update local repo: %v", err)
	} else if !changed {
		klog.Infof("Local repo update skipped: nothing changed")
	} else {
		klog.Infof("Local repo successfully updated")
	}
}

// GetPlan returns concrete plan replacing placeholders in schema with actual data values, returns JSON-formatted representation of the plan and any error occurred.
func GetPlan(schema map[string]Item, data interface{}) (plan map[string]Item, prettyprint string, err error) {
	plan = make(map[string]Item)
	for p, item := range schema {
		path, err := ParseTmpl(p, data, "")
		if err != nil {
			return plan, fmt.Sprintf("%+v", schema), err
		}
		plan[path] = item
	}

	for _, item := range plan {
		for src, dst := range item.Replace {
			out, err := ParseTmpl(dst, data, "")
			if err != nil {
				return plan, fmt.Sprintf("%+v", schema), err
			}
			item.Replace[src] = out
		}
	}
	str, err := json.MarshalIndent(plan, "", "  ")
	if err != nil {
		return plan, fmt.Sprintf("%+v", schema), err
	}

	return plan, string(str), nil
}

// RunWithRetryNotify runs command cmd with stdin using exponential backoff for maxTime duration
// up to maxRetries (negative values will make it ignored),
// notifies about any intermediary errors and return any final error.
// similar to pkg/util/retry/retry.go:Expo(), just for commands with params and also with context
func RunWithRetryNotify(ctx context.Context, cmd *exec.Cmd, stdin io.Reader, maxTime time.Duration, maxRetries uint64) error {
	be := backoff.NewExponentialBackOff()
	be.Multiplier = 2
	be.MaxElapsedTime = maxTime
	bm := backoff.WithMaxRetries(be, maxRetries)
	bc := backoff.WithContext(bm, ctx)

	notify := func(err error, wait time.Duration) {
		klog.Errorf("Temporary error running '%s' (will retry in %s): %v", cmd.String(), wait, err)
	}
	return backoff.RetryNotify(func() error {
		cmd.Stdin = stdin
		var stderr bytes.Buffer
		cmd.Stderr = &stderr
		if err := cmd.Run(); err != nil {
			time.Sleep(be.NextBackOff().Round(1 * time.Second))
			return fmt.Errorf("%w: %s", err, stderr.String())
		}
		return nil
	}, bc, notify)
}

// Run runs command cmd with stdin
func Run(cmd *exec.Cmd, stdin io.Reader) error {
	cmd.Stdin = stdin
	var out bytes.Buffer
	cmd.Stderr = &out
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("%w: %s", err, out.String())
	}
	return nil
}

// ParseTmpl replaces placeholders in text with actual data values
func ParseTmpl(text string, data interface{}, name string) (string, error) {
	tmpl := template.Must(template.New(name).Parse(text))
	buf := new(bytes.Buffer)
	if err := tmpl.Execute(buf, data); err != nil {
		return "", err
	}
	return buf.String(), nil
}
<|endoftext|>