<commit_before>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/joeshaw/envdecode"
	"gopkg.in/mailgun/mailgun-go.v1"
)

const (
	mailDomain  = "list.brandur.org"
	fromAddress = "Brandur <brandur@brandur.org>"
)

// Conf contains configuration information for the command. It's extracted from
// environment variables.
type Conf struct {
	// MailgunAPIKey is a key for Mailgun used to send email.
	MailgunAPIKey string `env:"MAILGUN_API_KEY,required"`
}

// Left as a global for now for the sake of convenience, but it's not used in
// very many places and can probably be refactored as a local if desired.
var conf Conf

func renderAndSend(records [][]string, live bool) error {
	mg := mailgun.NewMailgun(mailDomain, conf.MailgunAPIKey, "")

	for _, record := range records {
		// skip empty lines
		if len(record) == 0 {
			continue
		}

		if len(record) < 2 {
			return fmt.Errorf("Record less than 2-width: %v", record)
		}

		name := record[0]
		recipient := record[1]

		subject := "I'm subscribing you to my newsletter"
		body := fmt.Sprintf(`%s,

One thing I've realized over the last few years is that I
don't do a very good job of keeping in touch with people.
On top of that, I also don't do much on social media, so
it's not even possible to passively stay appraised of what
I'm doing.

On a recent trip I was inspired to try and fix this, and to
that end I'm trying something new: a newsletter. Each issue
will be a small compilation of stories and thoughts. The
bursts will be pretty infrequent; I'll send out roughly as
often as we get to witness a total solar eclipse.

(This email is not the newsletter, but) I'm about to send
its first issue, and I've added you to the list to receive
it. If you don't want it, either reply to me here saying
so, or wait until I send it and click the very conspicuous
unsubscribe link (I won't get notified on an unsubscribe,
and even if I did, I wouldn't take it personally).

Thanks, and I hope you like it!

Brandur`,
			name,
		)

		if live {
			message := mailgun.NewMessage(fromAddress, subject, body, recipient)
			resp, _, err := mg.Send(message)
			if err != nil {
				log.Fatal(err)
			}
			log.Printf(`Sent to: %s (response: "%s")`, recipient, resp)
		} else {
			fmt.Printf("To: %v <%v>\n", name, recipient)
			fmt.Printf("Subject: %v\n\n", subject)
			fmt.Printf("%v\n---\n\n", body)
		}
	}

	return nil
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [-live] <recipient_file>\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	live := flag.Bool("live", false,
		"Send to list (as opposed to dry run)")
	flag.Parse()

	if len(flag.Args()) != 1 {
		flag.Usage()
	}

	err := envdecode.Decode(&conf)
	if err != nil {
		log.Fatal(err)
	}

	f, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}

	r := csv.NewReader(f)
	r.Comment = '#'

	records, err := r.ReadAll()
	if err != nil {
		log.Fatal(err)
	}

	err = renderAndSend(records, *live)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Reword a few things<commit_after>package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/joeshaw/envdecode"
	"gopkg.in/mailgun/mailgun-go.v1"
)

const (
	mailDomain  = "list.brandur.org"
	fromAddress = "Brandur <brandur@brandur.org>"
)

// Conf contains configuration information for the command. It's extracted from
// environment variables.
type Conf struct {
	// MailgunAPIKey is a key for Mailgun used to send email.
	MailgunAPIKey string `env:"MAILGUN_API_KEY,required"`
}

// Left as a global for now for the sake of convenience, but it's not used in
// very many places and can probably be refactored as a local if desired.
var conf Conf

func renderAndSend(records [][]string, live bool) error {
	mg := mailgun.NewMailgun(mailDomain, conf.MailgunAPIKey, "")

	for _, record := range records {
		// skip empty lines
		if len(record) == 0 {
			continue
		}

		if len(record) < 2 {
			return fmt.Errorf("Record less than 2-width: %v", record)
		}

		name := record[0]
		recipient := record[1]

		subject := "I'm subscribing you to my newsletter"
		body := fmt.Sprintf(`%s,

One thing I've realized over the last few years is that I
don't do a very good job of keeping in touch with people.
On top of that, I also don't do much with social media, so
it's not even possible to passively stay appraised of what
I'm doing.

On a recent trip I was inspired to try and address this,
and to that end I'm trying something new: a newsletter.
Each issue will be a small compilation of stories and
thoughts. The bursts will be pretty infrequent; I'll send
out roughly as often as we get to witness a total solar
eclipse.

(This email is not the newsletter, but) I'm about to send
its first issue, and I've added you to the list to receive
it. If you don't want it, either reply to me here saying
so, or wait until I send it and click the very conspicuous
unsubscribe link (I won't get notified on an unsubscribe,
and even if I did, I wouldn't take it personally).

Thanks, and I hope you like it!

Brandur`,
			name,
		)

		if live {
			message := mailgun.NewMessage(fromAddress, subject, body, recipient)
			resp, _, err := mg.Send(message)
			if err != nil {
				log.Fatal(err)
			}
			log.Printf(`Sent to: %s (response: "%s")`, recipient, resp)
		} else {
			fmt.Printf("To: %v <%v>\n", name, recipient)
			fmt.Printf("Subject: %v\n\n", subject)
			fmt.Printf("%v\n---\n\n", body)
		}
	}

	return nil
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [-live] <recipient_file>\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	live := flag.Bool("live", false,
		"Send to list (as opposed to dry run)")
	flag.Parse()

	if len(flag.Args()) != 1 {
		flag.Usage()
	}

	err := envdecode.Decode(&conf)
	if err != nil {
		log.Fatal(err)
	}

	f, err := os.Open(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}

	r := csv.NewReader(f)
	r.Comment = '#'

	records, err := r.ReadAll()
	if err != nil {
		log.Fatal(err)
	}

	err = renderAndSend(records, *live)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package backend

import (
	"github.com/discordapp/lilliput"
	"github.com/pkg/errors"

	imagefile "github.com/thoas/picfit/image"
)

type LilliputEngine struct {
	MaxBufferSize int
}

func NewLilliputEngine(maxBufferSize int) *LilliputEngine {
	if maxBufferSize > 0 {
		return &LilliputEngine{MaxBufferSize: maxBufferSize}
	}
	return &LilliputEngine{MaxBufferSize: 8192}
}

// Resize resizes the image to the specified width and height and
// returns the transformed image. If one of width or height is 0,
// the image aspect ratio is preserved.
func (e *LilliputEngine) Resize(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	opts := &lilliput.ImageOptions{
		FileType:     img.FilenameExt(),
		Width:        options.Width,
		Height:       options.Height,
		ResizeMethod: lilliput.ImageOpsResize,
	}

	return e.transform(img, opts)
}

func (e *LilliputEngine) Rotate(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	return nil, MethodNotImplementedError
}

func (e *LilliputEngine) Flip(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	return nil, MethodNotImplementedError
}

// Thumbnail scales the image up or down using the specified resample filter, crops it
// to the specified width and hight and returns the transformed image.
func (e *LilliputEngine) Thumbnail(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	opts := &lilliput.ImageOptions{
		FileType: img.FilenameExt(),
		Width:    options.Width,
		Height:   options.Height,
		// Lilliput ImageOpsFit is a thumbnail operation
		ResizeMethod: lilliput.ImageOpsFit,
	}

	return e.transform(img, opts)
}

func (e *LilliputEngine) Fit(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	return nil, MethodNotImplementedError
}

func (e *LilliputEngine) transform(img *imagefile.ImageFile, options *lilliput.ImageOptions) ([]byte, error) {
	decoder, err := lilliput.NewDecoder(img.Source)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer decoder.Close()

	header, err := decoder.Header()
	if options.Width == 0 {
		options.Width = header.Width()
	}

	if options.Height == 0 {
		options.Height = header.Height()
	}

	ops := lilliput.NewImageOps(e.MaxBufferSize)
	defer ops.Close()

	outputImg := make([]byte, 50*1024*1024)

	return ops.Transform(decoder, options, outputImg)
}
<commit_msg>fix backend lilliput: keep ratio<commit_after>package backend

import (
	"math"

	"github.com/discordapp/lilliput"
	"github.com/pkg/errors"

	imagefile "github.com/thoas/picfit/image"
)

type LilliputEngine struct {
	MaxBufferSize int
}

func NewLilliputEngine(maxBufferSize int) *LilliputEngine {
	if maxBufferSize > 0 {
		return &LilliputEngine{MaxBufferSize: maxBufferSize}
	}
	return &LilliputEngine{MaxBufferSize: 8192}
}

// Resize resizes the image to the specified width and height and
// returns the transformed image. If one of width or height is 0,
// the image aspect ratio is preserved.
func (e *LilliputEngine) Resize(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	opts := &lilliput.ImageOptions{
		FileType:     img.FilenameExt(),
		Width:        options.Width,
		Height:       options.Height,
		ResizeMethod: lilliput.ImageOpsResize,
	}

	return e.transform(img, opts, options.Upscale)
}

func (e *LilliputEngine) Rotate(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	return nil, MethodNotImplementedError
}

func (e *LilliputEngine) Flip(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	return nil, MethodNotImplementedError
}

// Thumbnail scales the image up or down using the specified resample filter, crops it
// to the specified width and hight and returns the transformed image.
func (e *LilliputEngine) Thumbnail(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	opts := &lilliput.ImageOptions{
		FileType: img.FilenameExt(),
		Width:    options.Width,
		Height:   options.Height,
		// Lilliput ImageOpsFit is a thumbnail operation
		ResizeMethod: lilliput.ImageOpsFit,
	}

	return e.transform(img, opts, options.Upscale)
}

func (e *LilliputEngine) Fit(img *imagefile.ImageFile, options *Options) ([]byte, error) {
	return nil, MethodNotImplementedError
}

func (e *LilliputEngine) transform(img *imagefile.ImageFile, options *lilliput.ImageOptions, upscale bool) ([]byte, error) {
	decoder, err := lilliput.NewDecoder(img.Source)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer decoder.Close()

	header, err := decoder.Header()
	if err != nil {
		return nil, err
	}

	srcW := header.Width()
	srcH := header.Height()

	if scalingFactor(srcW, srcH, options.Width, options.Height) > 1 && !upscale {
		return img.Source, nil
	}

	if options.Width == 0 {
		tmpW := float64(options.Height) * float64(srcW) / float64(srcH)
		options.Width = int(math.Max(1.0, math.Floor(tmpW+0.5)))
	}
	if options.Height == 0 {
		tmpH := float64(options.Width) * float64(srcH) / float64(srcW)
		options.Height = int(math.Max(1.0, math.Floor(tmpH+0.5)))
	}

	ops := lilliput.NewImageOps(e.MaxBufferSize)
	defer ops.Close()

	outputImg := make([]byte, 50*1024*1024)

	return ops.Transform(decoder, options, outputImg)
}
<|endoftext|>


<commit_before>package engine

import (
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
)

func TestBackupKeygen(t *testing.T) {
	tc := SetupEngineTest(t, "backup")
	defer tc.Cleanup()

	fu := CreateAndSignupFakeUser(tc, "login")

	ctx := &Context{}
	eng := NewBackupKeygen(tc.G)
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}
	if len(eng.Passphrase()) == 0 {
		t.Fatal("empty passphrase")
	}
	Logout(tc)

	// check for the backup key
	u, err := libkb.LoadUser(libkb.LoadUserArg{Name: fu.Username, ForceReload: true})
	if err != nil {
		t.Fatal(err)
	}
	cki := u.GetComputedKeyInfos()
	if cki == nil {
		t.Fatal("no computed key infos")
	}
	var devid keybase1.DeviceID
	for k, v := range cki.Devices {
		if v.Type == libkb.DeviceTypeBackup {
			devid = k
			break
		}
	}
	if devid.IsNil() {
		t.Fatal("no backup device found")
	}
	sibkey, err := u.GetComputedKeyFamily().GetSibkeyForDevice(devid)
	if err != nil {
		t.Fatal(err)
	}
	if sibkey == nil {
		t.Fatal("nil backup sibkey")
	}
	enckey, err := u.GetComputedKeyFamily().GetEncryptionSubkeyForDevice(devid)
	if err != nil {
		t.Fatal(err)
	}
	if enckey == nil {
		t.Fatal("nil backup enckey")
	}
}
<commit_msg>added some login tests after backup key generation<commit_after>package engine

import (
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
)

func TestBackupKeygen(t *testing.T) {
	tc := SetupEngineTest(t, "backup")
	defer tc.Cleanup()

	fu := CreateAndSignupFakeUser(tc, "login")

	ctx := &Context{}
	eng := NewBackupKeygen(tc.G)
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}
	if len(eng.Passphrase()) == 0 {
		t.Fatal("empty passphrase")
	}
	Logout(tc)

	// check for the backup key
	u, err := libkb.LoadUser(libkb.LoadUserArg{Name: fu.Username, ForceReload: true})
	if err != nil {
		t.Fatal(err)
	}
	cki := u.GetComputedKeyInfos()
	if cki == nil {
		t.Fatal("no computed key infos")
	}
	var devid keybase1.DeviceID
	for k, v := range cki.Devices {
		if v.Type == libkb.DeviceTypeBackup {
			devid = k
			break
		}
	}
	if devid.IsNil() {
		t.Fatal("no backup device found")
	}
	sibkey, err := u.GetComputedKeyFamily().GetSibkeyForDevice(devid)
	if err != nil {
		t.Fatal(err)
	}
	if sibkey == nil {
		t.Fatal("nil backup sibkey")
	}
	enckey, err := u.GetComputedKeyFamily().GetEncryptionSubkeyForDevice(devid)
	if err != nil {
		t.Fatal(err)
	}
	if enckey == nil {
		t.Fatal("nil backup enckey")
	}

	// make sure the passphrase authentication didn't change:

	// ok, just log in again:
	if err := fu.Login(tc.G); err != nil {
		t.Errorf("after backup key gen, login failed: %s", err)
	}
	Logout(tc)

	// make sure the passphrase authentication didn't change:
	leng := NewLoginWithPassphraseEngine(fu.Username, fu.Passphrase, false, tc.G)
	lctx := &Context{
		LogUI:       tc.G.UI.GetLogUI(),
		LocksmithUI: &lockui{},
		GPGUI:       &gpgtestui{},
		SecretUI:    libkb.TestSecretUI{},
	}
	if err := RunEngine(leng, lctx); err != nil {
		t.Errorf("after backup key gen, login with passphrase failed: %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nsf/termbox-go"
	"github.com/simulatedsimian/emu6502/core6502"
)

func main() {
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	var ctx core6502.BasicCPUContext
	core6502.HardResetCPU(&ctx, 0x400)

	doQuit := false

	dl := DisplayList{}

	regDisp := RegisterDisplay{1, 1, &ctx}
	memDisp := MemoryDisplay{30, 1, 0, &ctx}
	stkDisp := StackDisplay{24, 1, &ctx}
	logDisp := ScrollingTextOutput{1, 20, 80, 5, nil}

	cmdInput := MakeTextInputField(10, 18, func(inp string) {
		if inp == "q" {
			doQuit = true
		}

		logDisp.WriteLine(inp)
	})

	dl.AddElement(cmdInput)
	dl.AddElement(&regDisp)
	dl.AddElement(&memDisp)
	dl.AddElement(&stkDisp)
	dl.AddElement(&logDisp)
	dl.AddElement(&StaticText{1, 18, "Command:"})
	dl.AddElement(&StaticText{1, 0, "Registers:"})
	dl.AddElement(&StaticText{30, 0, "Memory:"})
	dl.AddElement(&StaticText{24, 0, "TOS:"})

	cmdInput.GiveFocus()

	dl.Draw()
	termbox.Flush()

	for !doQuit {
		ev := termbox.PollEvent()

		if ev.Type == termbox.EventKey {
			dl.HandleInput(ev.Key, ev.Ch)
			dl.Draw()
			termbox.Flush()
		}

		if ev.Type == termbox.EventResize {
			termbox.Flush()
		}
	}
}
<commit_msg>experimenting with reflection<commit_after>package main

import (
	"fmt"
	"github.com/nsf/termbox-go"
	"github.com/simulatedsimian/emu6502/core6502"
	"reflect"
	"strconv"
)

func testFunc(ctx core6502.CPUContext, cmd string, x uint8, y uint16, s string) {

}

func main() {
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	var ctx core6502.BasicCPUContext
	core6502.HardResetCPU(&ctx, 0x400)

	doQuit := false

	dl := DisplayList{}

	regDisp := RegisterDisplay{1, 1, &ctx}
	memDisp := MemoryDisplay{30, 1, 0, &ctx}
	stkDisp := StackDisplay{24, 1, &ctx}
	logDisp := ScrollingTextOutput{1, 20, 80, 10, nil}

	cmdInput := MakeTextInputField(10, 18, func(inp string) {
		if inp == "q" {
			doQuit = true
		}

		t := reflect.TypeOf(testFunc)
		for n := 0; n < t.NumIn(); n++ {
			logDisp.WriteLine(fmt.Sprint(t.In(n)))
		}

		logDisp.WriteLine(fmt.Sprint(t))

		i, err := strconv.ParseInt(inp, 16, 16)

		logDisp.WriteLine(fmt.Sprint(i, err))
	})

	dl.AddElement(cmdInput)
	dl.AddElement(&regDisp)
	dl.AddElement(&memDisp)
	dl.AddElement(&stkDisp)
	dl.AddElement(&logDisp)
	dl.AddElement(&StaticText{1, 18, "Command:"})
	dl.AddElement(&StaticText{1, 0, "Registers:"})
	dl.AddElement(&StaticText{30, 0, "Memory:"})
	dl.AddElement(&StaticText{24, 0, "TOS:"})

	cmdInput.GiveFocus()

	dl.Draw()
	termbox.Flush()

	for !doQuit {
		ev := termbox.PollEvent()

		if ev.Type == termbox.EventKey {
			dl.HandleInput(ev.Key, ev.Ch)
			dl.Draw()
			termbox.Flush()
		}

		if ev.Type == termbox.EventResize {
			termbox.Flush()
		}
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
	"github.com/hashicorp/terraform/helper/resource"
)

func resourceAwsElasticBeanstalkApplication() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsElasticBeanstalkApplicationCreate,
		Read:   resourceAwsElasticBeanstalkApplicationRead,
		Update: resourceAwsElasticBeanstalkApplicationUpdate,
		Delete: resourceAwsElasticBeanstalkApplicationDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},
		},
	}
}

func resourceAwsElasticBeanstalkApplicationCreate(d *schema.ResourceData, meta interface{}) error {
	beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

	// Get the name and description
	name := d.Get("name").(string)
	description := d.Get("description").(string)

	log.Printf("[DEBUG] Elastic Beanstalk application create: %s, description: %s", name, description)

	req := &elasticbeanstalk.CreateApplicationInput{
		ApplicationName: aws.String(name),
		Description:     aws.String(description),
	}

	_, err := beanstalkConn.CreateApplication(req)
	if err != nil {
		return err
	}

	d.SetId(name)

	return resourceAwsElasticBeanstalkApplicationRead(d, meta)
}

func resourceAwsElasticBeanstalkApplicationUpdate(d *schema.ResourceData, meta interface{}) error {
	beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

	if d.HasChange("description") {
		if err := resourceAwsElasticBeanstalkApplicationDescriptionUpdate(beanstalkConn, d); err != nil {
			return err
		}
	}

	return resourceAwsElasticBeanstalkApplicationRead(d, meta)
}

func resourceAwsElasticBeanstalkApplicationDescriptionUpdate(beanstalkConn *elasticbeanstalk.ElasticBeanstalk, d *schema.ResourceData) error {
	name := d.Get("name").(string)
	description := d.Get("description").(string)

	log.Printf("[DEBUG] Elastic Beanstalk application: %s, update description: %s", name, description)

	_, err := beanstalkConn.UpdateApplication(&elasticbeanstalk.UpdateApplicationInput{
		ApplicationName: aws.String(name),
		Description:     aws.String(description),
	})

	return err
}

func resourceAwsElasticBeanstalkApplicationRead(d *schema.ResourceData, meta interface{}) error {
	a, err := getBeanstalkApplication(d, meta)
	if err != nil {
		return err
	}
	if a == nil {
		return err
	}

	d.Set("name", a.ApplicationName)
	d.Set("description", a.Description)
	return nil
}

func resourceAwsElasticBeanstalkApplicationDelete(d *schema.ResourceData, meta interface{}) error {
	beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

	a, err := getBeanstalkApplication(d, meta)
	if err != nil {
		return err
	}
	_, err = beanstalkConn.DeleteApplication(&elasticbeanstalk.DeleteApplicationInput{
		ApplicationName: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}

	return resource.Retry(10*time.Second, func() *resource.RetryError {
		if a, err = getBeanstalkApplication(d, meta); a != nil {
			return resource.RetryableError(
				fmt.Errorf("Beanstalk Application (%s) still exists: %s", d.Id(), err))
		}
		return nil
	})
}

func getBeanstalkApplication(
	d *schema.ResourceData,
	meta interface{}) (*elasticbeanstalk.ApplicationDescription, error) {
	conn := meta.(*AWSClient).elasticbeanstalkconn

	resp, err := conn.DescribeApplications(&elasticbeanstalk.DescribeApplicationsInput{
		ApplicationNames: []*string{aws.String(d.Id())},
	})

	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() != "InvalidBeanstalkAppID.NotFound" {
			log.Printf("[Err] Error reading Elastic Beanstalk Application (%s): Application not found", d.Id())
			d.SetId("")
			return nil, nil
		}
		return nil, err
	}

	switch {
	case len(resp.Applications) > 1:
		return nil, fmt.Errorf("Error %d Applications matched, expected 1", len(resp.Applications))
	case len(resp.Applications) == 0:
		d.SetId("")
		return nil, nil
	default:
		return resp.Applications[0], nil
	}
}
<commit_msg>resource/aws_elastic_beanstalk_application: Retry DescribeApplication after creation<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
	"github.com/hashicorp/terraform/helper/resource"
)

func resourceAwsElasticBeanstalkApplication() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsElasticBeanstalkApplicationCreate,
		Read:   resourceAwsElasticBeanstalkApplicationRead,
		Update: resourceAwsElasticBeanstalkApplicationUpdate,
		Delete: resourceAwsElasticBeanstalkApplicationDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},
		},
	}
}

func resourceAwsElasticBeanstalkApplicationCreate(d *schema.ResourceData, meta interface{}) error {
	beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

	// Get the name and description
	name := d.Get("name").(string)
	description := d.Get("description").(string)

	log.Printf("[DEBUG] Elastic Beanstalk application create: %s, description: %s", name, description)

	req := &elasticbeanstalk.CreateApplicationInput{
		ApplicationName: aws.String(name),
		Description:     aws.String(description),
	}

	_, err := beanstalkConn.CreateApplication(req)
	if err != nil {
		return err
	}

	d.SetId(name)

	return resourceAwsElasticBeanstalkApplicationRead(d, meta)
}

func resourceAwsElasticBeanstalkApplicationUpdate(d *schema.ResourceData, meta interface{}) error {
	beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

	if d.HasChange("description") {
		if err := resourceAwsElasticBeanstalkApplicationDescriptionUpdate(beanstalkConn, d); err != nil {
			return err
		}
	}

	return resourceAwsElasticBeanstalkApplicationRead(d, meta)
}

func resourceAwsElasticBeanstalkApplicationDescriptionUpdate(beanstalkConn *elasticbeanstalk.ElasticBeanstalk, d *schema.ResourceData) error {
	name := d.Get("name").(string)
	description := d.Get("description").(string)

	log.Printf("[DEBUG] Elastic Beanstalk application: %s, update description: %s", name, description)

	_, err := beanstalkConn.UpdateApplication(&elasticbeanstalk.UpdateApplicationInput{
		ApplicationName: aws.String(name),
		Description:     aws.String(description),
	})

	return err
}

func resourceAwsElasticBeanstalkApplicationRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticbeanstalkconn

	var app *elasticbeanstalk.ApplicationDescription
	err := resource.Retry(30*time.Second, func() *resource.RetryError {
		var err error
		app, err = getBeanstalkApplication(d.Id(), conn)
		if err != nil {
			return resource.NonRetryableError(err)
		}

		if app == nil {
			if d.IsNewResource() {
				return resource.RetryableError(fmt.Errorf("Elastic Beanstalk Application %q not found.", d.Id()))
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})
	if err != nil {
		return err
	}

	d.Set("name", app.ApplicationName)
	d.Set("description", app.Description)
	return nil
}

func resourceAwsElasticBeanstalkApplicationDelete(d *schema.ResourceData, meta interface{}) error {
	beanstalkConn := meta.(*AWSClient).elasticbeanstalkconn

	_, err := beanstalkConn.DeleteApplication(&elasticbeanstalk.DeleteApplicationInput{
		ApplicationName: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}

	return resource.Retry(10*time.Second, func() *resource.RetryError {
		app, err := getBeanstalkApplication(d.Id(), meta.(*AWSClient).elasticbeanstalkconn)
		if err != nil {
			return resource.NonRetryableError(err)
		}

		if app != nil {
			return resource.RetryableError(
				fmt.Errorf("Beanstalk Application (%s) still exists: %s", d.Id(), err))
		}
		return nil
	})
}

func getBeanstalkApplication(id string, conn *elasticbeanstalk.ElasticBeanstalk) (*elasticbeanstalk.ApplicationDescription, error) {
	resp, err := conn.DescribeApplications(&elasticbeanstalk.DescribeApplicationsInput{
		ApplicationNames: []*string{aws.String(id)},
	})
	if err != nil {
		if isAWSErr(err, "InvalidBeanstalkAppID.NotFound", "") {
			return nil, nil
		}
		return nil, err
	}

	if len(resp.Applications) > 1 {
		return nil, fmt.Errorf("Error %d Applications matched, expected 1", len(resp.Applications))
	}

	if len(resp.Applications) == 0 {
		return nil, nil
	}

	return resp.Applications[0], nil
}
<|endoftext|>


<commit_before>package ethernet

import (
	"github.com/hsheth2/logs"
)

// A FrameHeader is used when returning data from Reader.Read() calls
type FrameHeader struct {
	//Rmac, Lmac *MAC_Address
	Packet []byte
}

type ethernetReader struct {
	ethertype EtherType
	input     chan []byte
	processed chan *FrameHeader
}

func newEthernetReader(etp EtherType) (*ethernetReader, error) {
	ethr := &ethernetReader{
		ethertype: etp,
		input:     make(chan []byte, ethProtocolBufferSize),
		processed: make(chan *FrameHeader, ethProtocolBufferSize),
	}

	go ethr.readAll()

	return ethr, nil
}

func (ethr *ethernetReader) readAll() {
	for {
		//logs.Trace.Println("Ethernet reader attempting to get work")
		data := <-ethr.input
		//logs.Trace.Println("Ethernet reader recieved packet")

		ethHead := &FrameHeader{
			//Rmac: &MAC_Address{Data: data[ETH_MAC_ADDR_SZ : 2*ETH_MAC_ADDR_SZ]},
			//Lmac:   &MAC_Address{Data: data[0:ETH_MAC_ADDR_SZ]},
			Packet: data[ethHeaderSize:],
		}
		//			/*logs*/logs.Info.Println("Beginning to forward ethernet packet")
		select {
		case ethr.processed <- ethHead:
			//logs.Trace.Println("Forwarding ethernet packet")
		default:
			logs.Warn.Println("Dropping Ethernet packet: buffer full")
		}
	}
}

// blocking read call
func (ethr *ethernetReader) Read() (*FrameHeader, error) {
	return <-ethr.processed, nil
}

func (ethr *ethernetReader) Close() error {
	// TODO unbind
	// TODO close input channel
	// TODO close output channel
	return nil
}
<commit_msg>fix spelling mistake<commit_after>package ethernet

import (
	"github.com/hsheth2/logs"
)

// A FrameHeader is used when returning data from Reader.Read() calls
type FrameHeader struct {
	//Rmac, Lmac *MAC_Address
	Packet []byte
}

type ethernetReader struct {
	ethertype EtherType
	input     chan []byte
	processed chan *FrameHeader
}

func newEthernetReader(etp EtherType) (*ethernetReader, error) {
	ethr := &ethernetReader{
		ethertype: etp,
		input:     make(chan []byte, ethProtocolBufferSize),
		processed: make(chan *FrameHeader, ethProtocolBufferSize),
	}

	go ethr.readAll()

	return ethr, nil
}

func (ethr *ethernetReader) readAll() {
	for {
		//logs.Trace.Println("Ethernet reader attempting to get work")
		data := <-ethr.input
		//logs.Trace.Println("Ethernet reader received packet")

		ethHead := &FrameHeader{
			//Rmac: &MAC_Address{Data: data[ETH_MAC_ADDR_SZ : 2*ETH_MAC_ADDR_SZ]},
			//Lmac:   &MAC_Address{Data: data[0:ETH_MAC_ADDR_SZ]},
			Packet: data[ethHeaderSize:],
		}
		//			/*logs*/logs.Info.Println("Beginning to forward ethernet packet")
		select {
		case ethr.processed <- ethHead:
			//logs.Trace.Println("Forwarding ethernet packet")
		default:
			logs.Warn.Println("Dropping Ethernet packet: buffer full")
		}
	}
}

// blocking read call
func (ethr *ethernetReader) Read() (*FrameHeader, error) {
	return <-ethr.processed, nil
}

func (ethr *ethernetReader) Close() error {
	// TODO unbind
	// TODO close input channel
	// TODO close output channel
	return nil
}
<|endoftext|>


<commit_before>package encoder

// Original code borrowed from https://github.com/PuerkitoBio/martini-api-example
// TextEncoder and XmlEncoder has been removed. If someone really needs it, let me know.

// Supported tags:
// 	 - "out" if it sets to "false", value won't be set to field
import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"reflect"
	"time"
)

// An Encoder implements an encoding format of values to be sent as response to
// requests on the API endpoints.
type Encoder interface {
	Encode(v ...interface{}) ([]byte, error)
}

// Because `panic`s are caught by martini's Recovery handler, it can be used
// to return server-side errors (500). Some helpful text message should probably
// be sent, although not the technical error (which is printed in the log).
func Must(data []byte, err error) []byte {
	if err != nil {
		panic(err)
	}
	return data
}

type JsonEncoder struct {
	PrettyPrint bool
}

// @todo test for slice of structure support
func (self JsonEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v
	var result interface{}

	if v == nil {
		// So that empty results produces `[]` and not `null`
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	t := reflect.TypeOf(data)
	for t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	switch t.Kind() {
	case reflect.Slice:
		result = iterateSlice(reflect.ValueOf(data)).Interface()

	case reflect.Struct:
		result = copyStruct(reflect.ValueOf(data)).Interface()

	default:
		result = data
	}

	if self.PrettyPrint {
		return json.MarshalIndent(result, "", "	")
	} else {
		return json.Marshal(result)
	}
}

type XmlEncoder struct{}

// Since we don't use xml as a binding source, we don't need to use
// copyStruct here. Just Marshal.
func (_ XmlEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v
	var buffer bytes.Buffer

	if v == nil {
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	if _, err := buffer.Write([]byte(xml.Header)); err != nil {
		return []byte{}, err
	}

	b, err := xml.Marshal(data)
	if err != nil {
		return []byte{}, err
	}

	buffer.Write(b)

	return buffer.Bytes(), nil
}

func copyStruct(v reflect.Value) reflect.Value {
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if !v.IsValid() {
		return reflect.Value{}
	}

	result := reflect.New(v.Type()).Elem()

	t := v.Type()

	for i := 0; i < v.NumField(); i++ {
		vfield := v.Field(i)

		if tag := t.Field(i).Tag.Get("out"); tag == "false" {
			continue
		}

		if vfield.Type() == reflect.TypeOf(time.Time{}) {
			result.Field(i).Set(vfield)
			continue
		}

		if vfield.Kind() == reflect.Interface && vfield.Interface() != nil {
			vfield = vfield.Elem()

			for vfield.Kind() == reflect.Ptr {
				vfield = vfield.Elem()
			}

			result.Field(i).Set(copyStruct(vfield))
			continue
		}

		if vfield.Kind() == reflect.Struct || vfield.Kind() == reflect.Ptr {
			r := copyStruct(vfield)

			if result.Field(i).Kind() == reflect.Ptr {
				if r.CanAddr() {
					result.Field(i).Set(r.Addr())
				}
			} else {
				result.Field(i).Set(r)
			}

			continue
		}

		if vfield.Kind() == reflect.Array || vfield.Kind() == reflect.Slice {
			result.Field(i).Set(iterateSlice(vfield))
			continue
		}

		if result.Field(i).CanSet() {
			result.Field(i).Set(vfield)
		}
	}

	return result
}

func iterateSlice(v reflect.Value) reflect.Value {
	result := reflect.MakeSlice(v.Type(), 0, v.Len())

	for i := 0; i < v.Len(); i++ {
		value := v.Index(i)

		if value.Kind() == reflect.Slice || value.Kind() == reflect.Array {
			result = reflect.Append(result, iterateSlice(value))
			continue
		}

		vi := value
		if value.Kind() == reflect.Struct {
			vi = copyStruct(value)
		}

		if value.Kind() == reflect.Ptr && reflect.SliceOf(vi.Type()) != v.Type() {
			result = reflect.Append(result, vi.Addr())
		} else {
			result = reflect.Append(result, vi)
		}
	}

	return result
}
<commit_msg>Iterate over map fields<commit_after>package encoder

// Original code borrowed from https://github.com/PuerkitoBio/martini-api-example
// TextEncoder and XmlEncoder has been removed. If someone really needs it, let me know.

// Supported tags:
// 	 - "out" if it sets to "false", value won't be set to field
import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"reflect"
	"time"
)

// An Encoder implements an encoding format of values to be sent as response to
// requests on the API endpoints.
type Encoder interface {
	Encode(v ...interface{}) ([]byte, error)
}

// Because `panic`s are caught by martini's Recovery handler, it can be used
// to return server-side errors (500). Some helpful text message should probably
// be sent, although not the technical error (which is printed in the log).
func Must(data []byte, err error) []byte {
	if err != nil {
		panic(err)
	}
	return data
}

type JsonEncoder struct {
	PrettyPrint bool
}

// @todo test for slice of structure support
func (self JsonEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v
	var result interface{}

	if v == nil {
		// So that empty results produces `[]` and not `null`
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	t := reflect.TypeOf(data)
	for t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	switch t.Kind() {
	case reflect.Slice:
		result = iterateSlice(reflect.ValueOf(data)).Interface()

	case reflect.Struct:
		result = copyStruct(reflect.ValueOf(data)).Interface()

	default:
		result = data
	}

	if self.PrettyPrint {
		return json.MarshalIndent(result, "", "	")
	} else {
		return json.Marshal(result)
	}
}

type XmlEncoder struct{}

// Since we don't use xml as a binding source, we don't need to use
// copyStruct here. Just Marshal.
func (_ XmlEncoder) Encode(v ...interface{}) ([]byte, error) {
	var data interface{} = v
	var buffer bytes.Buffer

	if v == nil {
		data = []interface{}{}
	} else if len(v) == 1 {
		data = v[0]
	}

	if _, err := buffer.Write([]byte(xml.Header)); err != nil {
		return []byte{}, err
	}

	b, err := xml.Marshal(data)
	if err != nil {
		return []byte{}, err
	}

	buffer.Write(b)

	return buffer.Bytes(), nil
}

func copyStruct(v reflect.Value) reflect.Value {
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if !v.IsValid() {
		return reflect.Value{}
	}

	result := reflect.New(v.Type()).Elem()

	t := v.Type()

	for i := 0; i < v.NumField(); i++ {
		vfield := v.Field(i)

		if tag := t.Field(i).Tag.Get("out"); tag == "false" {
			continue
		}

		if vfield.Type() == reflect.TypeOf(time.Time{}) {
			result.Field(i).Set(vfield)
			continue
		}

		if vfield.Kind() == reflect.Interface && vfield.Interface() != nil {
			vfield = vfield.Elem()

			for vfield.Kind() == reflect.Ptr {
				vfield = vfield.Elem()
			}

			result.Field(i).Set(copyStruct(vfield))
			continue
		}

		if vfield.Kind() == reflect.Struct || vfield.Kind() == reflect.Ptr {
			r := copyStruct(vfield)

			if result.Field(i).Kind() == reflect.Ptr {
				if r.CanAddr() {
					result.Field(i).Set(r.Addr())
				}
			} else {
				result.Field(i).Set(r)
			}

			continue
		}

		if vfield.Kind() == reflect.Array || vfield.Kind() == reflect.Slice {
			result.Field(i).Set(iterateSlice(vfield))
			continue
		}

		if vfield.Kind() == reflect.Map {
			result.Field(i).Set(iterateMap(vfield))
			continue
		}

		if result.Field(i).CanSet() {
			result.Field(i).Set(vfield)
		}
	}

	return result
}

func iterateSlice(v reflect.Value) reflect.Value {
	result := reflect.MakeSlice(v.Type(), 0, v.Len())

	for i := 0; i < v.Len(); i++ {
		value := v.Index(i)

		if value.Kind() == reflect.Slice || value.Kind() == reflect.Array {
			result = reflect.Append(result, iterateSlice(value))
			continue
		}

		vi := value
		if value.Kind() == reflect.Struct {
			vi = copyStruct(value)
		}

		if value.Kind() == reflect.Ptr && reflect.SliceOf(vi.Type()) != v.Type() {
			result = reflect.Append(result, vi.Addr())
		} else {
			result = reflect.Append(result, vi)
		}
	}

	return result
}

func iterateMap(v reflect.Value) reflect.Value {
	result := reflect.MakeMap(v.Type())

	keys := v.MapKeys()
	for _, key := range keys {
		value := v.MapIndex(key)

		if value.Kind() == reflect.Slice || value.Kind() == reflect.Array {
			result.SetMapIndex(key, iterateSlice(value))
			continue
		}

		if value.Kind() == reflect.Map {
			result.SetMapIndex(key, iterateMap(value))
			continue
		}

		vi := value
		if value.Kind() == reflect.Struct {
			vi = copyStruct(value)
		}

		if value.Kind() == reflect.Ptr && reflect.SliceOf(vi.Type()) != v.Type() {
			result.SetMapIndex(key, vi.Addr())
		} else {
			result.SetMapIndex(key, vi)
		}
	}

	return result
}
<|endoftext|>


<commit_before>package service

//// RandomStringGenerator is the interface that generates random strings
//type RandomStringGenerator interface {
//	CryptoString(n int) (string, error)
//}
//
//// MovieTransactor is the interface that wraps the DML actions for
//// a Movie in the DB
//type MovieTransactor interface {
//	Create(ctx context.Context, m *movie.Movie) error
//	Update(ctx context.Context, m *movie.Movie) error
//	Delete(ctx context.Context, m *movie.Movie) error
//}
//
//// MovieSelector reads Movie records from the db
//type MovieSelector interface {
//	FindByID(context.Context, string) (*movie.Movie, error)
//	FindAll(context.Context) ([]*movie.Movie, error)
//}
//
//// CreateMovieRequest is the request struct for Creating a Movie
//type CreateMovieRequest struct {
//	Title    string `json:"title"`
//	Rated    string `json:"rated"`
//	Released string `json:"release_date"`
//	RunTime  int    `json:"run_time"`
//	Director string `json:"director"`
//	Writer   string `json:"writer"`
//}
//
//// UpdateMovieRequest is the request struct for updating a Movie
//type UpdateMovieRequest struct {
//	ExternalID string
//	Title      string `json:"title"`
//	Rated      string `json:"rated"`
//	Released   string `json:"release_date"`
//	RunTime    int    `json:"run_time"`
//	Director   string `json:"director"`
//	Writer     string `json:"writer"`
//}
//
//// MovieResponse is the response struct for a Movie
//type MovieResponse struct {
//	ExternalID      string `json:"external_id"`
//	Title           string `json:"title"`
//	Rated           string `json:"rated"`
//	Released        string `json:"release_date"`
//	RunTime         int    `json:"run_time"`
//	Director        string `json:"director"`
//	Writer          string `json:"writer"`
//	CreateUsername  string `json:"create_username"`
//	CreateTimestamp string `json:"create_timestamp"`
//	UpdateUsername  string `json:"update_username"`
//	UpdateTimestamp string `json:"update_timestamp"`
//}
//
//// DeleteMovieResponse is the response struct for deleted Movies
//type DeleteMovieResponse struct {
//	ExternalID string `json:"extl_id"`
//	Deleted    bool   `json:"deleted"`
//}
//
//func newMovieResponse(m *movie.Movie) MovieResponse {
//	return MovieResponse{
//		ExternalID:      m.ExternalID,
//		Title:           m.Title,
//		Rated:           m.Rated,
//		Released:        m.Released.Format(time.RFC3339),
//		RunTime:         m.RunTime,
//		Director:        m.Director,
//		Writer:          m.Writer,
//		CreateUsername:  m.CreateUser.Email,
//		CreateTimestamp: m.CreateTime.Format(time.RFC3339),
//		UpdateUsername:  m.UpdateUser.Email,
//		UpdateTimestamp: m.UpdateTime.Format(time.RFC3339),
//	}
//}
//
//// CreateMovieService is a service for creating a Movie
//type CreateMovieService struct {
//	RandomStringGenerator RandomStringGenerator
//	MovieTransactor       MovieTransactor
//}
//
//// NewCreateMovieService is an initializer for CreateMovieService
//func NewCreateMovieService(rsg RandomStringGenerator, mt MovieTransactor) *CreateMovieService {
//	return &CreateMovieService{RandomStringGenerator: rsg, MovieTransactor: mt}
//}
//
//// Create is used to create a Movie
//func (cms CreateMovieService) Create(ctx context.Context, r *CreateMovieRequest, u user.User) (MovieResponse, error) {
//
//	mr := MovieResponse{}
//
//	extlID, err := cms.RandomStringGenerator.CryptoString(15)
//	if err != nil {
//		return mr, err
//	}
//
//	// Call the NewMovie method for struct initialization
//	m, err := movie.NewMovie(uuid.New(), extlID, u)
//	if err != nil {
//		return mr, err
//	}
//
//	m, err = m.SetReleased(r.Released)
//	if err != nil {
//		return mr, err
//	}
//	m.SetTitle(r.Title).
//		SetRated(r.Rated).
//		SetRunTime(r.RunTime).
//		SetDirector(r.Director).
//		SetWriter(r.Writer)
//
//	err = m.IsValid()
//	if err != nil {
//		return mr, err
//	}
//
//	// Call the Create method of the Transactor to insert data to
//	// the database. If an error occurs, rollback the transaction
//	err = cms.MovieTransactor.Create(ctx, m)
//	if err != nil {
//		return mr, err
//	}
//
//	return newMovieResponse(m), nil
//}
//
//// UpdateMovieService is a service for updating a Movie
//type UpdateMovieService struct {
//	MovieTransactor MovieTransactor
//}
//
//// NewUpdateMovieService is an initializer for UpdateMovieService
//func NewUpdateMovieService(mt MovieTransactor) *UpdateMovieService {
//	return &UpdateMovieService{MovieTransactor: mt}
//}
//
//// Update is used to update a movie
//func (ums UpdateMovieService) Update(ctx context.Context, r *UpdateMovieRequest, u user.User) (MovieResponse, error) {
//
//	mr := MovieResponse{}
//
//	// Convert request into a Movie struct
//	m := new(movie.Movie)
//	m.SetExternalID(r.ExternalID)
//	m.SetTitle(r.Title)
//	m.SetRated(r.Rated)
//	m, err := m.SetReleased(r.Released)
//	if err != nil {
//		return mr, err
//	}
//	m.SetRunTime(r.RunTime)
//	m.SetDirector(r.Director)
//	m.SetWriter(r.Writer)
//	m.SetUpdateUser(u)
//	m.SetUpdateTime()
//
//	err = m.IsValid()
//	if err != nil {
//		return mr, err
//	}
//
//	// Call the Update method of the Transactor to update the record
//	// in the database.
//	err = ums.MovieTransactor.Update(ctx, m)
//	if err != nil {
//		return mr, err
//	}
//
//	return newMovieResponse(m), nil
//}
//
//// DeleteMovieService is a service for deleting a Movie
//type DeleteMovieService struct {
//	MovieSelector   MovieSelector
//	MovieTransactor MovieTransactor
//}
//
//// NewDeleteMovieService is an initializer for DeleteMovieService
//func NewDeleteMovieService(ms MovieSelector, mt MovieTransactor) *DeleteMovieService {
//	return &DeleteMovieService{MovieSelector: ms, MovieTransactor: mt}
//}
//
//// Delete is used to delete a movie
//func (dms DeleteMovieService) Delete(ctx context.Context, extlID string) (DeleteMovieResponse, error) {
//
//	dmr := DeleteMovieResponse{}
//
//	// Find the Movie by ID using the selector.FindMovieByID method
//	// It's arguable I don't need to do this and can just send
//	// the external ID to the database Transactor directly instead,
//	// (I'd have to rework it slightly) but this way works as an
//	// example
//	m, err := dms.MovieSelector.FindByID(ctx, extlID)
//	if err != nil {
//		return dmr, err
//	}
//
//	// Delete method of Transactor physically deletes the record
//	// from the DB, unless mocked
//	err = dms.MovieTransactor.Delete(ctx, m)
//	if err != nil {
//		return dmr, err
//	}
//
//	response := DeleteMovieResponse{
//		ExternalID: m.ExternalID,
//		Deleted:    true,
//	}
//
//	return response, nil
//}
//
//// FindMovieService is a service for reading a Movie from the DB
//type FindMovieService struct {
//	MovieSelector MovieSelector
//}
//
//// NewFindMovieService is an initializer for FindMovieService
//func NewFindMovieService(ms MovieSelector) *FindMovieService {
//	return &FindMovieService{MovieSelector: ms}
//}
//
//// FindMovieByID is used to find an individual movie
//func (fms FindMovieService) FindMovieByID(ctx context.Context, extlID string) (MovieResponse, error) {
//
//	mr := MovieResponse{}
//
//	m, err := fms.MovieSelector.FindByID(ctx, extlID)
//	if err != nil {
//		return mr, err
//	}
//
//	return newMovieResponse(m), nil
//}
//
//// FindAllMovies is used to list all movies in the db
//func (fms FindMovieService) FindAllMovies(ctx context.Context) ([]MovieResponse, error) {
//
//	var response []MovieResponse
//
//	// Find the list of all Movies using the selector.FindAll method
//	movies, err := fms.MovieSelector.FindAll(ctx)
//	if err != nil {
//		return response, err
//	}
//
//	for _, m := range movies {
//		mr := newMovieResponse(m)
//		response = append(response, mr)
//	}
//
//	return response, nil
//}
<commit_msg>Add Movie back in<commit_after>package service

import (
	"context"
	"time"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v4"

	"github.com/gilcrest/go-api-basic/datastore"
	"github.com/gilcrest/go-api-basic/datastore/moviestore"
	"github.com/gilcrest/go-api-basic/domain/audit"
	"github.com/gilcrest/go-api-basic/domain/errs"
	"github.com/gilcrest/go-api-basic/domain/movie"
	"github.com/gilcrest/go-api-basic/domain/secure"
)

// CreateMovieRequest is the request struct for Creating a Movie
type CreateMovieRequest struct {
	Title    string `json:"title"`
	Rated    string `json:"rated"`
	Released string `json:"release_date"`
	RunTime  int    `json:"run_time"`
	Director string `json:"director"`
	Writer   string `json:"writer"`
}

// MovieResponse is the response struct for a Movie
type MovieResponse struct {
	ExternalID  string        `json:"external_id"`
	Title       string        `json:"title"`
	Rated       string        `json:"rated"`
	Released    string        `json:"release_date"`
	RunTime     int           `json:"run_time"`
	Director    string        `json:"director"`
	Writer      string        `json:"writer"`
	CreateAudit auditResponse `json:"create_audit"`
	UpdateAudit auditResponse `json:"update_audit"`
}

// newMovieResponse initializes MovieResponse
func newMovieResponse(m movie.Movie, sa audit.SimpleAudit) MovieResponse {
	return MovieResponse{
		ExternalID:  m.ExternalID.String(),
		Title:       m.Title,
		Rated:       m.Rated,
		Released:    m.Released.Format(time.RFC3339),
		RunTime:     m.RunTime,
		Director:    m.Director,
		Writer:      m.Writer,
		CreateAudit: newAuditResponse(sa.First),
		UpdateAudit: newAuditResponse(sa.Last),
	}
}

// CreateMovieService is a service for creating a Movie
type CreateMovieService struct {
	Datastorer Datastorer
}

// Create is used to create an Movie
func (s CreateMovieService) Create(ctx context.Context, r *CreateMovieRequest, adt audit.Audit) (MovieResponse, error) {
	var err error

	released, err := time.Parse(time.RFC3339, r.Released)
	if err != nil {
		return MovieResponse{}, errs.E(errs.Validation,
			errs.Code("invalid_date_format"),
			errs.Parameter("release_date"),
			err)
	}

	// initialize Movie and inject dependent fields
	m := movie.Movie{
		ID:         uuid.New(),
		ExternalID: secure.NewID(),
		Title:      r.Title,
		Rated:      r.Rated,
		Released:   released,
		RunTime:    r.RunTime,
		Director:   r.Director,
		Writer:     r.Writer,
	}

	sa := audit.SimpleAudit{
		First: adt,
		Last:  adt,
	}

	err = m.IsValid()
	if err != nil {
		return MovieResponse{}, err
	}

	createMovieParams := moviestore.CreateMovieParams{
		MovieID:         m.ID,
		ExtlID:          m.ExternalID.String(),
		Title:           m.Title,
		Rated:           datastore.NewNullString(m.Rated),
		Released:        datastore.NewNullTime(released),
		RunTime:         datastore.NewNullInt32(int32(m.RunTime)),
		Director:        datastore.NewNullString(m.Director),
		Writer:          datastore.NewNullString(m.Writer),
		CreateAppID:     sa.First.App.ID,
		CreateUserID:    datastore.NewNullUUID(sa.First.User.ID),
		CreateTimestamp: sa.First.Moment,
		UpdateAppID:     sa.Last.App.ID,
		UpdateUserID:    datastore.NewNullUUID(sa.Last.User.ID),
		UpdateTimestamp: sa.Last.Moment,
	}

	// start db txn using pgxpool
	tx, err := s.Datastorer.BeginTx(ctx)
	if err != nil {
		return MovieResponse{}, err
	}

	_, err = moviestore.New(tx).CreateMovie(ctx, createMovieParams)
	if err != nil {
		return MovieResponse{}, errs.E(errs.Database, s.Datastorer.RollbackTx(ctx, tx, err))
	}

	// commit db txn using pgxpool
	err = s.Datastorer.CommitTx(ctx, tx)
	if err != nil {
		return MovieResponse{}, err
	}

	return newMovieResponse(m, sa), nil
}

// UpdateMovieRequest is the request struct for updating a Movie
type UpdateMovieRequest struct {
	ExternalID string
	Title      string `json:"title"`
	Rated      string `json:"rated"`
	Released   string `json:"release_date"`
	RunTime    int    `json:"run_time"`
	Director   string `json:"director"`
	Writer     string `json:"writer"`
}

// UpdateMovieService is a service for updating a Movie
type UpdateMovieService struct {
	Datastorer Datastorer
}

// Update is used to update a movie
func (s UpdateMovieService) Update(ctx context.Context, r *UpdateMovieRequest, adt audit.Audit) (MovieResponse, error) {

	// retrieve existing Movie
	var (
		m   movie.Movie
		dbm moviestore.Movie
		sa  audit.SimpleAudit
		err error
	)

	var released time.Time
	released, err = time.Parse(time.RFC3339, r.Released)
	if err != nil {
		return MovieResponse{}, errs.E(errs.Validation,
			errs.Code("invalid_date_format"),
			errs.Parameter("release_date"),
			err)
	}

	dbm, err = moviestore.New(s.Datastorer.Pool()).FindMovieByExternalID(ctx, r.ExternalID)
	if err != nil {
		if err == pgx.ErrNoRows {
			return MovieResponse{}, errs.E(errs.Validation, "No movie exists for the given external ID")
		}
		return MovieResponse{}, errs.E(errs.Database, err)
	}

	m, sa, err = hydrateMovieFromDB(ctx, s.Datastorer.Pool(), dbm)
	if err != nil {
		return MovieResponse{}, err
	}

	// update fields from request
	m.Title = r.Title
	m.Rated = r.Rated
	m.Released = released
	m.RunTime = r.RunTime
	m.Director = r.Director
	m.Writer = r.Writer

	err = m.IsValid()
	if err != nil {
		return MovieResponse{}, err
	}

	// update audit with latest
	sa.Last = adt

	updateMovieParams := moviestore.UpdateMovieParams{
		Title:           m.Title,
		Rated:           datastore.NewNullString(m.Rated),
		Released:        datastore.NewNullTime(released),
		RunTime:         datastore.NewNullInt32(int32(m.RunTime)),
		Director:        datastore.NewNullString(m.Director),
		Writer:          datastore.NewNullString(m.Writer),
		UpdateAppID:     adt.App.ID,
		UpdateUserID:    datastore.NewNullUUID(adt.User.ID),
		UpdateTimestamp: adt.Moment,
		MovieID:         m.ID,
	}

	// start db txn using pgxpool
	tx, err := s.Datastorer.BeginTx(ctx)
	if err != nil {
		return MovieResponse{}, err
	}

	err = moviestore.New(tx).UpdateMovie(ctx, updateMovieParams)
	if err != nil {
		return MovieResponse{}, errs.E(errs.Database, s.Datastorer.RollbackTx(ctx, tx, err))
	}

	// commit db txn using pgxpool
	err = s.Datastorer.CommitTx(ctx, tx)
	if err != nil {
		return MovieResponse{}, err
	}

	return newMovieResponse(m, sa), nil
}

// DeleteMovieResponse is the response struct for deleted Movies
type DeleteMovieResponse struct {
	ExternalID string `json:"extl_id"`
	Deleted    bool   `json:"deleted"`
}

// DeleteMovieService is a service for deleting a Movie
type DeleteMovieService struct {
	Datastorer Datastorer
}

// Delete is used to delete a movie
func (s DeleteMovieService) Delete(ctx context.Context, extlID string) (DeleteMovieResponse, error) {

	// retrieve existing Movie
	var (
		dbm moviestore.Movie
		err error
	)
	dbm, err = moviestore.New(s.Datastorer.Pool()).FindMovieByExternalID(ctx, extlID)
	if err != nil {
		if err == pgx.ErrNoRows {
			return DeleteMovieResponse{}, errs.E(errs.Validation, "No movie exists for the given external ID")
		}
		return DeleteMovieResponse{}, errs.E(errs.Database, err)
	}

	// start db txn using pgxpool
	var tx pgx.Tx
	tx, err = s.Datastorer.BeginTx(ctx)
	if err != nil {
		return DeleteMovieResponse{}, err
	}

	err = moviestore.New(tx).DeleteMovie(ctx, dbm.MovieID)
	if err != nil {
		return DeleteMovieResponse{}, errs.E(errs.Database, s.Datastorer.RollbackTx(ctx, tx, err))
	}

	// commit db txn using pgxpool
	err = s.Datastorer.CommitTx(ctx, tx)
	if err != nil {
		return DeleteMovieResponse{}, err
	}

	response := DeleteMovieResponse{
		ExternalID: dbm.ExtlID,
		Deleted:    true,
	}

	return response, nil
}

// FindMovieService is a service for reading Movies from the DB
type FindMovieService struct {
	Datastorer Datastorer
}

// FindMovieByID is used to find an individual movie
func (s FindMovieService) FindMovieByID(ctx context.Context, extlID string) (MovieResponse, error) {

	var (
		m   movie.Movie
		dbm moviestore.Movie
		sa  audit.SimpleAudit
		err error
	)

	dbm, err = moviestore.New(s.Datastorer.Pool()).FindMovieByExternalID(ctx, extlID)
	if err != nil {
		if err == pgx.ErrNoRows {
			return MovieResponse{}, errs.E(errs.Validation, "no movie exists for the given external ID")
		}
		return MovieResponse{}, errs.E(errs.Database, err)
	}

	m, sa, err = hydrateMovieFromDB(ctx, s.Datastorer.Pool(), dbm)
	if err != nil {
		return MovieResponse{}, err
	}

	return newMovieResponse(m, sa), nil
}

// FindAllMovies is used to list all movies in the db
func (s FindMovieService) FindAllMovies(ctx context.Context) ([]MovieResponse, error) {

	var response []MovieResponse

	movies, err := moviestore.New(s.Datastorer.Pool()).FindMovies(ctx)
	if err != nil {
		if err == pgx.ErrNoRows {
			return nil, errs.E(errs.Validation, "no movies exists")
		}
		return nil, errs.E(errs.Database, err)
	}

	for _, dbm := range movies {
		var (
			m  movie.Movie
			sa audit.SimpleAudit
		)
		m, sa, err = hydrateMovieFromDB(ctx, s.Datastorer.Pool(), dbm)
		if err != nil {
			return nil, err
		}

		mr := newMovieResponse(m, sa)
		response = append(response, mr)
	}

	return response, nil
}

// hydrateMovieFromDB populates a movie.Movie and an audit.SimpleAudit given a moviestore.Movie
func hydrateMovieFromDB(ctx context.Context, dbtx DBTX, dbm moviestore.Movie) (movie.Movie, audit.SimpleAudit, error) {
	var (
		err error
	)

	// Convert moviestore.Movie into a domain movie.Movie struct
	m := movie.Movie{
		ID:         dbm.MovieID,
		ExternalID: secure.MustParseIdentifier(dbm.ExtlID),
		Title:      dbm.Title,
		Rated:      dbm.Rated.String,
		Released:   dbm.Released.Time,
		RunTime:    int(dbm.RunTime.Int32),
		Director:   dbm.Director.String,
		Writer:     dbm.Writer.String,
	}

	var createAudit audit.Audit
	createAudit, err = newAudit(ctx, dbtx, dbm.CreateAppID, dbm.CreateUserID, dbm.CreateTimestamp)
	if err != nil {
		return movie.Movie{}, audit.SimpleAudit{}, err
	}

	var updateAudit audit.Audit
	updateAudit, err = newAudit(ctx, dbtx, dbm.UpdateAppID, dbm.UpdateUserID, dbm.UpdateTimestamp)
	if err != nil {
		return movie.Movie{}, audit.SimpleAudit{}, err
	}

	sa := audit.SimpleAudit{
		First: createAudit,
		Last:  updateAudit,
	}

	return m, sa, nil
}
<|endoftext|>


<commit_before>package services

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"time"

	"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
	m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
)

var (
	IoHelper       m.IoUtil = IoUtilImp{}
	HttpClient     http.Client
	grafanaVersion string
)

func Init(version string) {
	grafanaVersion = version

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
	}

	HttpClient = http.Client{
		Timeout:   time.Duration(10 * time.Second),
		Transport: tr,
	}
}

func ListAllPlugins(repoUrl string) (m.PluginRepo, error) {
	body, err := createRequest(repoUrl, "repo")

	if err != nil {
		logger.Info("Failed to create request", "error", err)
		return m.PluginRepo{}, fmt.Errorf("Failed to create request. error: %v", err)
	}

	if err != nil {
		return m.PluginRepo{}, err
	}

	var data m.PluginRepo
	err = json.Unmarshal(body, &data)
	if err != nil {
		logger.Info("Failed to unmarshal graphite response error: %v", err)
		return m.PluginRepo{}, err
	}

	return data, nil
}

func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) {
	distPluginDataPath := path.Join(pluginDir, pluginName, "dist", "plugin.json")

	var data []byte
	var err error
	data, err = IoHelper.ReadFile(distPluginDataPath)

	if err != nil {
		pluginDataPath := path.Join(pluginDir, pluginName, "plugin.json")
		data, err = IoHelper.ReadFile(pluginDataPath)

		if err != nil {
			return m.InstalledPlugin{}, errors.New("Could not find dist/plugin.json or plugin.json on  " + pluginName + " in " + pluginDir)
		}
	}

	res := m.InstalledPlugin{}
	json.Unmarshal(data, &res)

	if res.Info.Version == "" {
		res.Info.Version = "0.0.0"
	}

	if res.Id == "" {
		return m.InstalledPlugin{}, errors.New("could not find plugin " + pluginName + " in " + pluginDir)
	}

	return res, nil
}

func GetLocalPlugins(pluginDir string) []m.InstalledPlugin {
	result := make([]m.InstalledPlugin, 0)
	files, _ := IoHelper.ReadDir(pluginDir)
	for _, f := range files {
		res, err := ReadPlugin(pluginDir, f.Name())
		if err == nil {
			result = append(result, res)
		}
	}

	return result
}

func RemoveInstalledPlugin(pluginPath, pluginName string) error {
	logger.Infof("Removing plugin: %v\n", pluginName)
	pluginDir := path.Join(pluginPath, pluginName)

	_, err := IoHelper.Stat(pluginDir)
	if err != nil {
		return err
	}

	return IoHelper.RemoveAll(pluginDir)
}

func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) {
	body, err := createRequest(repoUrl, "repo", pluginId)

	if err != nil {
		logger.Info("Failed to create request", "error", err)
		return m.Plugin{}, fmt.Errorf("Failed to create request. error: %v", err)
	}

	if err != nil {
		return m.Plugin{}, err
	}

	var data m.Plugin
	err = json.Unmarshal(body, &data)
	if err != nil {
		logger.Info("Failed to unmarshal graphite response error: %v", err)
		return m.Plugin{}, err
	}

	return data, nil
}

func createRequest(repoUrl string, subPaths ...string) ([]byte, error) {
	u, _ := url.Parse(repoUrl)
	for _, v := range subPaths {
		u.Path = path.Join(u.Path, v)
	}

	req, err := http.NewRequest(http.MethodGet, u.String(), nil)

	logger.Info("grafanaVersion ", grafanaVersion)

	req.Header.Set("grafana-version", grafanaVersion)
	req.Header.Set("User-Agent", "grafana "+grafanaVersion)

	if err != nil {
		return []byte{}, err
	}

	res, err := HttpClient.Do(req)

	body, err := ioutil.ReadAll(res.Body)
	defer res.Body.Close()

	return body, err
}
<commit_msg>fix(cli): remove unused logging<commit_after>package services

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"time"

	"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
	m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
)

var (
	IoHelper       m.IoUtil = IoUtilImp{}
	HttpClient     http.Client
	grafanaVersion string
)

func Init(version string) {
	grafanaVersion = version

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
	}

	HttpClient = http.Client{
		Timeout:   time.Duration(10 * time.Second),
		Transport: tr,
	}
}

func ListAllPlugins(repoUrl string) (m.PluginRepo, error) {
	body, err := createRequest(repoUrl, "repo")

	if err != nil {
		logger.Info("Failed to create request", "error", err)
		return m.PluginRepo{}, fmt.Errorf("Failed to create request. error: %v", err)
	}

	if err != nil {
		return m.PluginRepo{}, err
	}

	var data m.PluginRepo
	err = json.Unmarshal(body, &data)
	if err != nil {
		logger.Info("Failed to unmarshal graphite response error: %v", err)
		return m.PluginRepo{}, err
	}

	return data, nil
}

func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) {
	distPluginDataPath := path.Join(pluginDir, pluginName, "dist", "plugin.json")

	var data []byte
	var err error
	data, err = IoHelper.ReadFile(distPluginDataPath)

	if err != nil {
		pluginDataPath := path.Join(pluginDir, pluginName, "plugin.json")
		data, err = IoHelper.ReadFile(pluginDataPath)

		if err != nil {
			return m.InstalledPlugin{}, errors.New("Could not find dist/plugin.json or plugin.json on  " + pluginName + " in " + pluginDir)
		}
	}

	res := m.InstalledPlugin{}
	json.Unmarshal(data, &res)

	if res.Info.Version == "" {
		res.Info.Version = "0.0.0"
	}

	if res.Id == "" {
		return m.InstalledPlugin{}, errors.New("could not find plugin " + pluginName + " in " + pluginDir)
	}

	return res, nil
}

func GetLocalPlugins(pluginDir string) []m.InstalledPlugin {
	result := make([]m.InstalledPlugin, 0)
	files, _ := IoHelper.ReadDir(pluginDir)
	for _, f := range files {
		res, err := ReadPlugin(pluginDir, f.Name())
		if err == nil {
			result = append(result, res)
		}
	}

	return result
}

func RemoveInstalledPlugin(pluginPath, pluginName string) error {
	logger.Infof("Removing plugin: %v\n", pluginName)
	pluginDir := path.Join(pluginPath, pluginName)

	_, err := IoHelper.Stat(pluginDir)
	if err != nil {
		return err
	}

	return IoHelper.RemoveAll(pluginDir)
}

func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) {
	body, err := createRequest(repoUrl, "repo", pluginId)

	if err != nil {
		logger.Info("Failed to create request", "error", err)
		return m.Plugin{}, fmt.Errorf("Failed to create request. error: %v", err)
	}

	if err != nil {
		return m.Plugin{}, err
	}

	var data m.Plugin
	err = json.Unmarshal(body, &data)
	if err != nil {
		logger.Info("Failed to unmarshal graphite response error: %v", err)
		return m.Plugin{}, err
	}

	return data, nil
}

func createRequest(repoUrl string, subPaths ...string) ([]byte, error) {
	u, _ := url.Parse(repoUrl)
	for _, v := range subPaths {
		u.Path = path.Join(u.Path, v)
	}

	req, err := http.NewRequest(http.MethodGet, u.String(), nil)

	req.Header.Set("grafana-version", grafanaVersion)
	req.Header.Set("User-Agent", "grafana "+grafanaVersion)

	if err != nil {
		return []byte{}, err
	}

	res, err := HttpClient.Do(req)

	body, err := ioutil.ReadAll(res.Body)
	defer res.Body.Close()

	return body, err
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 options

import (
	"fmt"
	"net"
	"strings"
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apiserver/pkg/server"
	utilfeature "k8s.io/apiserver/pkg/util/feature"

	"github.com/spf13/pflag"
)

// ServerRunOptions contains the options while running a generic api server.
type ServerRunOptions struct {
	AdvertiseAddress net.IP

	CorsAllowedOriginList       []string
	HSTSDirectives              []string
	ExternalHost                string
	MaxRequestsInFlight         int
	MaxMutatingRequestsInFlight int
	RequestTimeout              time.Duration
	GoawayChance                float64
	LivezGracePeriod            time.Duration
	MinRequestTimeout           int
	ShutdownDelayDuration       time.Duration
	// We intentionally did not add a flag for this option. Users of the
	// apiserver library can wire it to a flag.
	JSONPatchMaxCopyBytes int64
	// The limit on the request body size that would be accepted and
	// decoded in a write request. 0 means no limit.
	// We intentionally did not add a flag for this option. Users of the
	// apiserver library can wire it to a flag.
	MaxRequestBodyBytes       int64
	EnablePriorityAndFairness bool

	// ShutdownSendRetryAfter dictates when to initiate shutdown of the HTTP
	// Server during the graceful termination of the apiserver. If true, we wait
	// for non longrunning requests in flight to be drained and then initiate a
	// shutdown of the HTTP Server. If false, we initiate a shutdown of the HTTP
	// Server as soon as ShutdownDelayDuration has elapsed.
	// If enabled, after ShutdownDelayDuration elapses, any incoming request is
	// rejected with a 429 status code and a 'Retry-After' response.
	ShutdownSendRetryAfter bool
}

func NewServerRunOptions() *ServerRunOptions {
	defaults := server.NewConfig(serializer.CodecFactory{})
	return &ServerRunOptions{
		MaxRequestsInFlight:         defaults.MaxRequestsInFlight,
		MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight,
		RequestTimeout:              defaults.RequestTimeout,
		LivezGracePeriod:            defaults.LivezGracePeriod,
		MinRequestTimeout:           defaults.MinRequestTimeout,
		ShutdownDelayDuration:       defaults.ShutdownDelayDuration,
		JSONPatchMaxCopyBytes:       defaults.JSONPatchMaxCopyBytes,
		MaxRequestBodyBytes:         defaults.MaxRequestBodyBytes,
		EnablePriorityAndFairness:   true,
		ShutdownSendRetryAfter:      false,
	}
}

// ApplyTo applies the run options to the method receiver and returns self
func (s *ServerRunOptions) ApplyTo(c *server.Config) error {
	c.CorsAllowedOriginList = s.CorsAllowedOriginList
	c.HSTSDirectives = s.HSTSDirectives
	c.ExternalAddress = s.ExternalHost
	c.MaxRequestsInFlight = s.MaxRequestsInFlight
	c.MaxMutatingRequestsInFlight = s.MaxMutatingRequestsInFlight
	c.LivezGracePeriod = s.LivezGracePeriod
	c.RequestTimeout = s.RequestTimeout
	c.GoawayChance = s.GoawayChance
	c.MinRequestTimeout = s.MinRequestTimeout
	c.ShutdownDelayDuration = s.ShutdownDelayDuration
	c.JSONPatchMaxCopyBytes = s.JSONPatchMaxCopyBytes
	c.MaxRequestBodyBytes = s.MaxRequestBodyBytes
	c.PublicAddress = s.AdvertiseAddress
	c.ShutdownSendRetryAfter = s.ShutdownSendRetryAfter

	return nil
}

// DefaultAdvertiseAddress sets the field AdvertiseAddress if unset. The field will be set based on the SecureServingOptions.
func (s *ServerRunOptions) DefaultAdvertiseAddress(secure *SecureServingOptions) error {
	if secure == nil {
		return nil
	}

	if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() {
		hostIP, err := secure.DefaultExternalAddress()
		if err != nil {
			return fmt.Errorf("Unable to find suitable network address.error='%v'. "+
				"Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
		}
		s.AdvertiseAddress = hostIP
	}

	return nil
}

// Validate checks validation of ServerRunOptions
func (s *ServerRunOptions) Validate() []error {
	errors := []error{}

	if s.LivezGracePeriod < 0 {
		errors = append(errors, fmt.Errorf("--livez-grace-period can not be a negative value"))
	}

	if s.MaxRequestsInFlight < 0 {
		errors = append(errors, fmt.Errorf("--max-requests-inflight can not be negative value"))
	}
	if s.MaxMutatingRequestsInFlight < 0 {
		errors = append(errors, fmt.Errorf("--max-mutating-requests-inflight can not be negative value"))
	}

	if s.RequestTimeout.Nanoseconds() < 0 {
		errors = append(errors, fmt.Errorf("--request-timeout can not be negative value"))
	}

	if s.GoawayChance < 0 || s.GoawayChance > 0.02 {
		errors = append(errors, fmt.Errorf("--goaway-chance can not be less than 0 or greater than 0.02"))
	}

	if s.MinRequestTimeout < 0 {
		errors = append(errors, fmt.Errorf("--min-request-timeout can not be negative value"))
	}

	if s.ShutdownDelayDuration < 0 {
		errors = append(errors, fmt.Errorf("--shutdown-delay-duration can not be negative value"))
	}

	if s.JSONPatchMaxCopyBytes < 0 {
		errors = append(errors, fmt.Errorf("ServerRunOptions.JSONPatchMaxCopyBytes can not be negative value"))
	}

	if s.MaxRequestBodyBytes < 0 {
		errors = append(errors, fmt.Errorf("ServerRunOptions.MaxRequestBodyBytes can not be negative value"))
	}

	if err := validateHSTSDirectives(s.HSTSDirectives); err != nil {
		errors = append(errors, err)
	}
	return errors
}

func validateHSTSDirectives(hstsDirectives []string) error {
	// HSTS Headers format: Strict-Transport-Security:max-age=expireTime [;includeSubDomains] [;preload]
	// See https://tools.ietf.org/html/rfc6797#section-6.1 for more information
	allErrors := []error{}
	for _, hstsDirective := range hstsDirectives {
		if len(strings.TrimSpace(hstsDirective)) == 0 {
			allErrors = append(allErrors, fmt.Errorf("empty value in strict-transport-security-directives"))
			continue
		}
		if hstsDirective != "includeSubDomains" && hstsDirective != "preload" {
			maxAgeDirective := strings.Split(hstsDirective, "=")
			if len(maxAgeDirective) != 2 || maxAgeDirective[0] != "max-age" {
				allErrors = append(allErrors, fmt.Errorf("--strict-transport-security-directives invalid, allowed values: max-age=expireTime, includeSubDomains, preload. see https://tools.ietf.org/html/rfc6797#section-6.1 for more information"))
			}
		}
	}
	return errors.NewAggregate(allErrors)
}

// AddUniversalFlags adds flags for a specific APIServer to the specified FlagSet
func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
	// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
	// arrange these text blocks sensibly. Grrr.

	fs.IPVar(&s.AdvertiseAddress, "advertise-address", s.AdvertiseAddress, ""+
		"The IP address on which to advertise the apiserver to members of the cluster. This "+
		"address must be reachable by the rest of the cluster. If blank, the --bind-address "+
		"will be used. If --bind-address is unspecified, the host's default interface will "+
		"be used.")

	fs.StringSliceVar(&s.CorsAllowedOriginList, "cors-allowed-origins", s.CorsAllowedOriginList, ""+
		"List of allowed origins for CORS, comma separated.  An allowed origin can be a regular "+
		"expression to support subdomain matching. If this list is empty CORS will not be enabled.")

	fs.StringSliceVar(&s.HSTSDirectives, "strict-transport-security-directives", s.HSTSDirectives, ""+
		"List of directives for HSTS, comma separated. If this list is empty, then HSTS directives will not "+
		"be added. Example: 'max-age=31536000,includeSubDomains,preload'")

	fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost,
		"The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs or OpenID Discovery).")

	deprecatedMasterServiceNamespace := metav1.NamespaceDefault
	fs.StringVar(&deprecatedMasterServiceNamespace, "master-service-namespace", deprecatedMasterServiceNamespace, ""+
		"DEPRECATED: the namespace from which the Kubernetes master services should be injected into pods.")

	fs.IntVar(&s.MaxRequestsInFlight, "max-requests-inflight", s.MaxRequestsInFlight, ""+
		"This and --max-mutating-requests-inflight are summed to determine the server's total concurrency limit "+
		"(which must be positive) if --enable-priority-and-fairness is true. "+
		"Otherwise, this flag limits the maximum number of non-mutating requests in flight, "+
		"or a zero value disables the limit completely.")

	fs.IntVar(&s.MaxMutatingRequestsInFlight, "max-mutating-requests-inflight", s.MaxMutatingRequestsInFlight, ""+
		"This and --max-requests-inflight are summed to determine the server's total concurrency limit "+
		"(which must be positive) if --enable-priority-and-fairness is true. "+
		"Otherwise, this flag limits the maximum number of mutating requests in flight, "+
		"or a zero value disables the limit completely.")

	fs.DurationVar(&s.RequestTimeout, "request-timeout", s.RequestTimeout, ""+
		"An optional field indicating the duration a handler must keep a request open before timing "+
		"it out. This is the default request timeout for requests but may be overridden by flags such as "+
		"--min-request-timeout for specific types of requests.")

	fs.Float64Var(&s.GoawayChance, "goaway-chance", s.GoawayChance, ""+
		"To prevent HTTP/2 clients from getting stuck on a single apiserver, randomly close a connection (GOAWAY). "+
		"The client's other in-flight requests won't be affected, and the client will reconnect, likely landing on a different apiserver after going through the load balancer again. "+
		"This argument sets the fraction of requests that will be sent a GOAWAY. Clusters with single apiservers, or which don't use a load balancer, should NOT enable this. "+
		"Min is 0 (off), Max is .02 (1/50 requests); .001 (1/1000) is a recommended starting point.")

	fs.DurationVar(&s.LivezGracePeriod, "livez-grace-period", s.LivezGracePeriod, ""+
		"This option represents the maximum amount of time it should take for apiserver to complete its startup sequence "+
		"and become live. From apiserver's start time to when this amount of time has elapsed, /livez will assume "+
		"that unfinished post-start hooks will complete successfully and therefore return true.")

	fs.IntVar(&s.MinRequestTimeout, "min-request-timeout", s.MinRequestTimeout, ""+
		"An optional field indicating the minimum number of seconds a handler must keep "+
		"a request open before timing it out. Currently only honored by the watch request "+
		"handler, which picks a randomized value above this number as the connection timeout, "+
		"to spread out load.")

	fs.BoolVar(&s.EnablePriorityAndFairness, "enable-priority-and-fairness", s.EnablePriorityAndFairness, ""+
		"If true and the APIPriorityAndFairness feature gate is enabled, replace the max-in-flight handler with an enhanced one that queues and dispatches with priority and fairness")

	fs.DurationVar(&s.ShutdownDelayDuration, "shutdown-delay-duration", s.ShutdownDelayDuration, ""+
		"Time to delay the termination. During that time the server keeps serving requests normally. The endpoints /healthz and /livez "+
		"will return success, but /readyz immediately returns failure. Graceful termination starts after this delay "+
		"has elapsed. This can be used to allow load balancer to stop sending traffic to this server.")

	fs.BoolVar(&s.ShutdownSendRetryAfter, "shutdown-send-retry-after", s.ShutdownSendRetryAfter, ""+
		"If true the HTTP Server will continue listening until all non long running request(s) in flight have been drained, "+
		"during this window all incoming requests will be rejected with a status code 429 and a 'Retry-After' response header, "+
		"in addition 'Connection: close' response header is set in order to tear down the TCP connection when idle.")

	utilfeature.DefaultMutableFeatureGate.AddFlag(fs)
}
<commit_msg>kube-apiserver: mark unused master-service-namespace flag as deprecated<commit_after>/*
Copyright 2016 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 options

import (
	"fmt"
	"net"
	"strings"
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/util/errors"
	"k8s.io/apiserver/pkg/server"
	utilfeature "k8s.io/apiserver/pkg/util/feature"

	"github.com/spf13/pflag"
)

// ServerRunOptions contains the options while running a generic api server.
type ServerRunOptions struct {
	AdvertiseAddress net.IP

	CorsAllowedOriginList       []string
	HSTSDirectives              []string
	ExternalHost                string
	MaxRequestsInFlight         int
	MaxMutatingRequestsInFlight int
	RequestTimeout              time.Duration
	GoawayChance                float64
	LivezGracePeriod            time.Duration
	MinRequestTimeout           int
	ShutdownDelayDuration       time.Duration
	// We intentionally did not add a flag for this option. Users of the
	// apiserver library can wire it to a flag.
	JSONPatchMaxCopyBytes int64
	// The limit on the request body size that would be accepted and
	// decoded in a write request. 0 means no limit.
	// We intentionally did not add a flag for this option. Users of the
	// apiserver library can wire it to a flag.
	MaxRequestBodyBytes       int64
	EnablePriorityAndFairness bool

	// ShutdownSendRetryAfter dictates when to initiate shutdown of the HTTP
	// Server during the graceful termination of the apiserver. If true, we wait
	// for non longrunning requests in flight to be drained and then initiate a
	// shutdown of the HTTP Server. If false, we initiate a shutdown of the HTTP
	// Server as soon as ShutdownDelayDuration has elapsed.
	// If enabled, after ShutdownDelayDuration elapses, any incoming request is
	// rejected with a 429 status code and a 'Retry-After' response.
	ShutdownSendRetryAfter bool
}

func NewServerRunOptions() *ServerRunOptions {
	defaults := server.NewConfig(serializer.CodecFactory{})
	return &ServerRunOptions{
		MaxRequestsInFlight:         defaults.MaxRequestsInFlight,
		MaxMutatingRequestsInFlight: defaults.MaxMutatingRequestsInFlight,
		RequestTimeout:              defaults.RequestTimeout,
		LivezGracePeriod:            defaults.LivezGracePeriod,
		MinRequestTimeout:           defaults.MinRequestTimeout,
		ShutdownDelayDuration:       defaults.ShutdownDelayDuration,
		JSONPatchMaxCopyBytes:       defaults.JSONPatchMaxCopyBytes,
		MaxRequestBodyBytes:         defaults.MaxRequestBodyBytes,
		EnablePriorityAndFairness:   true,
		ShutdownSendRetryAfter:      false,
	}
}

// ApplyTo applies the run options to the method receiver and returns self
func (s *ServerRunOptions) ApplyTo(c *server.Config) error {
	c.CorsAllowedOriginList = s.CorsAllowedOriginList
	c.HSTSDirectives = s.HSTSDirectives
	c.ExternalAddress = s.ExternalHost
	c.MaxRequestsInFlight = s.MaxRequestsInFlight
	c.MaxMutatingRequestsInFlight = s.MaxMutatingRequestsInFlight
	c.LivezGracePeriod = s.LivezGracePeriod
	c.RequestTimeout = s.RequestTimeout
	c.GoawayChance = s.GoawayChance
	c.MinRequestTimeout = s.MinRequestTimeout
	c.ShutdownDelayDuration = s.ShutdownDelayDuration
	c.JSONPatchMaxCopyBytes = s.JSONPatchMaxCopyBytes
	c.MaxRequestBodyBytes = s.MaxRequestBodyBytes
	c.PublicAddress = s.AdvertiseAddress
	c.ShutdownSendRetryAfter = s.ShutdownSendRetryAfter

	return nil
}

// DefaultAdvertiseAddress sets the field AdvertiseAddress if unset. The field will be set based on the SecureServingOptions.
func (s *ServerRunOptions) DefaultAdvertiseAddress(secure *SecureServingOptions) error {
	if secure == nil {
		return nil
	}

	if s.AdvertiseAddress == nil || s.AdvertiseAddress.IsUnspecified() {
		hostIP, err := secure.DefaultExternalAddress()
		if err != nil {
			return fmt.Errorf("Unable to find suitable network address.error='%v'. "+
				"Try to set the AdvertiseAddress directly or provide a valid BindAddress to fix this.", err)
		}
		s.AdvertiseAddress = hostIP
	}

	return nil
}

// Validate checks validation of ServerRunOptions
func (s *ServerRunOptions) Validate() []error {
	errors := []error{}

	if s.LivezGracePeriod < 0 {
		errors = append(errors, fmt.Errorf("--livez-grace-period can not be a negative value"))
	}

	if s.MaxRequestsInFlight < 0 {
		errors = append(errors, fmt.Errorf("--max-requests-inflight can not be negative value"))
	}
	if s.MaxMutatingRequestsInFlight < 0 {
		errors = append(errors, fmt.Errorf("--max-mutating-requests-inflight can not be negative value"))
	}

	if s.RequestTimeout.Nanoseconds() < 0 {
		errors = append(errors, fmt.Errorf("--request-timeout can not be negative value"))
	}

	if s.GoawayChance < 0 || s.GoawayChance > 0.02 {
		errors = append(errors, fmt.Errorf("--goaway-chance can not be less than 0 or greater than 0.02"))
	}

	if s.MinRequestTimeout < 0 {
		errors = append(errors, fmt.Errorf("--min-request-timeout can not be negative value"))
	}

	if s.ShutdownDelayDuration < 0 {
		errors = append(errors, fmt.Errorf("--shutdown-delay-duration can not be negative value"))
	}

	if s.JSONPatchMaxCopyBytes < 0 {
		errors = append(errors, fmt.Errorf("ServerRunOptions.JSONPatchMaxCopyBytes can not be negative value"))
	}

	if s.MaxRequestBodyBytes < 0 {
		errors = append(errors, fmt.Errorf("ServerRunOptions.MaxRequestBodyBytes can not be negative value"))
	}

	if err := validateHSTSDirectives(s.HSTSDirectives); err != nil {
		errors = append(errors, err)
	}
	return errors
}

func validateHSTSDirectives(hstsDirectives []string) error {
	// HSTS Headers format: Strict-Transport-Security:max-age=expireTime [;includeSubDomains] [;preload]
	// See https://tools.ietf.org/html/rfc6797#section-6.1 for more information
	allErrors := []error{}
	for _, hstsDirective := range hstsDirectives {
		if len(strings.TrimSpace(hstsDirective)) == 0 {
			allErrors = append(allErrors, fmt.Errorf("empty value in strict-transport-security-directives"))
			continue
		}
		if hstsDirective != "includeSubDomains" && hstsDirective != "preload" {
			maxAgeDirective := strings.Split(hstsDirective, "=")
			if len(maxAgeDirective) != 2 || maxAgeDirective[0] != "max-age" {
				allErrors = append(allErrors, fmt.Errorf("--strict-transport-security-directives invalid, allowed values: max-age=expireTime, includeSubDomains, preload. see https://tools.ietf.org/html/rfc6797#section-6.1 for more information"))
			}
		}
	}
	return errors.NewAggregate(allErrors)
}

// AddUniversalFlags adds flags for a specific APIServer to the specified FlagSet
func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
	// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
	// arrange these text blocks sensibly. Grrr.

	fs.IPVar(&s.AdvertiseAddress, "advertise-address", s.AdvertiseAddress, ""+
		"The IP address on which to advertise the apiserver to members of the cluster. This "+
		"address must be reachable by the rest of the cluster. If blank, the --bind-address "+
		"will be used. If --bind-address is unspecified, the host's default interface will "+
		"be used.")

	fs.StringSliceVar(&s.CorsAllowedOriginList, "cors-allowed-origins", s.CorsAllowedOriginList, ""+
		"List of allowed origins for CORS, comma separated.  An allowed origin can be a regular "+
		"expression to support subdomain matching. If this list is empty CORS will not be enabled.")

	fs.StringSliceVar(&s.HSTSDirectives, "strict-transport-security-directives", s.HSTSDirectives, ""+
		"List of directives for HSTS, comma separated. If this list is empty, then HSTS directives will not "+
		"be added. Example: 'max-age=31536000,includeSubDomains,preload'")

	fs.StringVar(&s.ExternalHost, "external-hostname", s.ExternalHost,
		"The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs or OpenID Discovery).")

	deprecatedMasterServiceNamespace := metav1.NamespaceDefault
	fs.StringVar(&deprecatedMasterServiceNamespace, "master-service-namespace", deprecatedMasterServiceNamespace, ""+
		"DEPRECATED: the namespace from which the Kubernetes master services should be injected into pods.")
	fs.MarkDeprecated("master-service-namespace", "This flag will be removed in v1.27")

	fs.IntVar(&s.MaxRequestsInFlight, "max-requests-inflight", s.MaxRequestsInFlight, ""+
		"This and --max-mutating-requests-inflight are summed to determine the server's total concurrency limit "+
		"(which must be positive) if --enable-priority-and-fairness is true. "+
		"Otherwise, this flag limits the maximum number of non-mutating requests in flight, "+
		"or a zero value disables the limit completely.")

	fs.IntVar(&s.MaxMutatingRequestsInFlight, "max-mutating-requests-inflight", s.MaxMutatingRequestsInFlight, ""+
		"This and --max-requests-inflight are summed to determine the server's total concurrency limit "+
		"(which must be positive) if --enable-priority-and-fairness is true. "+
		"Otherwise, this flag limits the maximum number of mutating requests in flight, "+
		"or a zero value disables the limit completely.")

	fs.DurationVar(&s.RequestTimeout, "request-timeout", s.RequestTimeout, ""+
		"An optional field indicating the duration a handler must keep a request open before timing "+
		"it out. This is the default request timeout for requests but may be overridden by flags such as "+
		"--min-request-timeout for specific types of requests.")

	fs.Float64Var(&s.GoawayChance, "goaway-chance", s.GoawayChance, ""+
		"To prevent HTTP/2 clients from getting stuck on a single apiserver, randomly close a connection (GOAWAY). "+
		"The client's other in-flight requests won't be affected, and the client will reconnect, likely landing on a different apiserver after going through the load balancer again. "+
		"This argument sets the fraction of requests that will be sent a GOAWAY. Clusters with single apiservers, or which don't use a load balancer, should NOT enable this. "+
		"Min is 0 (off), Max is .02 (1/50 requests); .001 (1/1000) is a recommended starting point.")

	fs.DurationVar(&s.LivezGracePeriod, "livez-grace-period", s.LivezGracePeriod, ""+
		"This option represents the maximum amount of time it should take for apiserver to complete its startup sequence "+
		"and become live. From apiserver's start time to when this amount of time has elapsed, /livez will assume "+
		"that unfinished post-start hooks will complete successfully and therefore return true.")

	fs.IntVar(&s.MinRequestTimeout, "min-request-timeout", s.MinRequestTimeout, ""+
		"An optional field indicating the minimum number of seconds a handler must keep "+
		"a request open before timing it out. Currently only honored by the watch request "+
		"handler, which picks a randomized value above this number as the connection timeout, "+
		"to spread out load.")

	fs.BoolVar(&s.EnablePriorityAndFairness, "enable-priority-and-fairness", s.EnablePriorityAndFairness, ""+
		"If true and the APIPriorityAndFairness feature gate is enabled, replace the max-in-flight handler with an enhanced one that queues and dispatches with priority and fairness")

	fs.DurationVar(&s.ShutdownDelayDuration, "shutdown-delay-duration", s.ShutdownDelayDuration, ""+
		"Time to delay the termination. During that time the server keeps serving requests normally. The endpoints /healthz and /livez "+
		"will return success, but /readyz immediately returns failure. Graceful termination starts after this delay "+
		"has elapsed. This can be used to allow load balancer to stop sending traffic to this server.")

	fs.BoolVar(&s.ShutdownSendRetryAfter, "shutdown-send-retry-after", s.ShutdownSendRetryAfter, ""+
		"If true the HTTP Server will continue listening until all non long running request(s) in flight have been drained, "+
		"during this window all incoming requests will be rejected with a status code 429 and a 'Retry-After' response header, "+
		"in addition 'Connection: close' response header is set in order to tear down the TCP connection when idle.")

	utilfeature.DefaultMutableFeatureGate.AddFlag(fs)
}
<|endoftext|>