<commit_before>// The goapp command implements a simple App Engine app to demonstrate how to
// use the Service Control API v2 for admission control. For more information,
// see https://cloud.google.com/service-infrastructure/docs/admission-control.
package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	// WARNING:`go get google.golang.org/api/servicecontrol/v2" may take
	// 30 minutes or longer, depending on your network speed.
	"google.golang.org/api/servicecontrol/v2"
)

// Check calls Service Control API v2 for admission control.
// Name specifies the target resource name. Permission specifies
// the required permission on the target resource.
func check(w http.ResponseWriter, r *http.Request, name string, permission string) (string, error) {
	client, err := servicecontrol.NewService(r.Context())
	if err != nil {
		return "", err
	}
	// Construct CheckRequest from the incoming HTTP request.
	// The code assumes the incoming request processed by App Engine ingress.
	checkRequest := &servicecontrol.CheckRequest{
		ServiceConfigId: "latest",
		Attributes: &servicecontrol.AttributeContext{
			Origin: &servicecontrol.Peer{
				Ip: r.Header.Get("x-appengine-user-ip"),
			},
			Api: &servicecontrol.Api{
				Service:   "endpointsapis.appspot.com",
				Operation: "google.example.endpointsapis.v1.Workspaces.GetWorkspace",
				Version:   "v1",
				Protocol:  r.Header.Get("x-forwarded-proto"),
			},
			Request: &servicecontrol.Request{
				Id:     r.Header.Get("x-appengine-request-log-id"),
				Time:   time.Now().UTC().Format(time.RFC3339),
				Method: r.Method,
				Scheme: r.Header.Get("x-forwarded-proto"),
				Host:   r.Host,
				Path:   r.URL.Path,
				Headers: map[string]string{
					"authorization": r.Header.Get("authorization"),
					"user-agent":    r.Header.Get("user-agent"),
					"origin":        r.Header.Get("origin"),
					"referer":       r.Header.Get("referer"),
				},
			},
		},
		Resources: []*servicecontrol.ResourceInfo{
			{
				Name:       name,
				Type:       "endpointsapis.appspot.com/Workspace",
				Permission: permission,
			},
		},
	}
	response, err := client.Services.Check("endpointsapis.appspot.com", checkRequest).Do()
	if err != nil {
		return "", err
	}
	responseJSON, err := response.MarshalJSON()
	if err != nil {
		return "", err
	}
	return string(responseJSON), nil
}

func admission(w http.ResponseWriter, r *http.Request) (string, error) {
	// Split the request path.
	segments := strings.Split(r.URL.Path, "/")

	// The request path must match "/v1/projects/*/locations/*/workspaces/*" or
	// "/v1/projects/*/locations/*/workspaces". They correspond to the
	// GetWorkspace() and ListWorkspaces() methods defined in ../v1/workspace.proto.
	if segments[0] != "" || segments[1] != "v1" || segments[2] != "projects" || segments[4] != "locations" || segments[6] != "workspaces" || len(segments) > 8 {
		return "", errors.New("Resource '" + r.URL.Path + "' not found.")
	}
	// Skip prefix "/v1/".
	resource := r.URL.Path[4:]
	permission := "endpointsapis.appspot.com/workspaces.list"
	if len(segments) == 8 {
		permission = "endpointsapis.appspot.com/workspaces.get"
	}
	return check(w, r, resource, permission)
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	// Perform admission control.
	result, err := admission(w, r)

	// Print the admission control result.
	if err != nil {
		fmt.Fprintln(w, "Error:")
		fmt.Fprintln(w, err.Error())
	} else {
		fmt.Fprintln(w, "CheckResponse:")
		fmt.Fprintln(w, result)
	}

	// Print all environment variables.
	fmt.Fprintln(w, "Environments:")
	fmt.Fprintln(w, strings.Join(os.Environ(), "\n"))

	// Print all request headers.
	fmt.Fprintln(w, "Headers:")
	for key, values := range r.Header {
		for _, value := range values {
			fmt.Fprintf(w, "%v: %v\n", key, value)
		}
	}
}

func main() {
	http.HandleFunc("/", indexHandler)

	port := os.Getenv("PORT")

	log.Printf("Listen and serve on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>feat: Integrate with Report v2 in the go app for the Example API.<commit_after>// The goapp command implements a simple App Engine app to demonstrate how to
// use the Service Control API v2 for admission control. For more information,
// see https://cloud.google.com/service-infrastructure/docs/admission-control.
package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	// WARNING:`go get google.golang.org/api/servicecontrol/v2" may take
	// 30 minutes or longer, depending on your network speed.
	"google.golang.org/api/servicecontrol/v2"
)

// Check calls Service Control API v2 for admission control.
// Name specifies the target resource name. Permission specifies
// the required permission on the target resource. Received
// specifies the timestamp when the request is received.
func check(w http.ResponseWriter, r *http.Request, name string, permission string, received time.Time, client *servicecontrol.Service) (string, error) {
	// Construct CheckRequest from the incoming HTTP request.
	// The code assumes the incoming request processed by App Engine ingress.
	req := &servicecontrol.CheckRequest{
		ServiceConfigId: "latest",
		Attributes: &servicecontrol.AttributeContext{
			Origin: &servicecontrol.Peer{
				Ip: r.Header.Get("x-appengine-user-ip"),
			},
			Api: &servicecontrol.Api{
				Service:   "endpointsapis.appspot.com",
				Operation: "google.example.endpointsapis.v1.Workspaces.GetWorkspace",
				Version:   "v1",
				Protocol:  r.Header.Get("x-forwarded-proto"),
			},
			Request: &servicecontrol.Request{
				Id:     r.Header.Get("x-appengine-request-log-id"),
				Time:   received.UTC().Format(time.RFC3339),
				Method: r.Method,
				Scheme: r.Header.Get("x-forwarded-proto"),
				Host:   r.Host,
				Path:   r.URL.Path,
				Headers: map[string]string{
					"authorization": r.Header.Get("authorization"),
					"user-agent":    r.Header.Get("user-agent"),
					"origin":        r.Header.Get("origin"),
					"referer":       r.Header.Get("referer"),
				},
			},
			Resource: &servicecontrol.Resource{
				Name: name,
			},
		},
		Resources: []*servicecontrol.ResourceInfo{
			{
				Name:       name,
				Type:       "endpointsapis.appspot.com/Workspace",
				Permission: permission,
			},
		},
	}
	resp, err := client.Services.Check("endpointsapis.appspot.com", req).Do()
	if err != nil {
		return "", err
	}
	json, err := resp.MarshalJSON()
	if err != nil {
		return "", err
	}
	return string(json), nil
}

// Report calls Service Control API v2 for telemetry reporting.
// Name specifies the target resource name. ResponseCode specifies
// the response code returned to user. Received specifies the
// timestamp when the request is received.
func report(w http.ResponseWriter, r *http.Request, name string, responseCode int64, received time.Time, client *servicecontrol.Service) (string, error) {
	// Construct ReportRequest from the incoming HTTP request.
	// The code assumes the incoming request processed by App Engine ingress.
	req := &servicecontrol.ReportRequest{
		ServiceConfigId: "latest",
		Operations: []*servicecontrol.AttributeContext{
			{
				Api: &servicecontrol.Api{
					Service:   "endpointsapis.appspot.com",
					Operation: "google.example.endpointsapis.v1.Workspaces.GetWorkspace",
					Version:   "v1",
					Protocol:  r.Header.Get("x-forwarded-proto"),
				},
				Request: &servicecontrol.Request{
					Size: r.ContentLength,
					Time: received.UTC().Format(time.RFC3339),
				},
				Response: &servicecontrol.Response{
					Time: time.Now().UTC().Format(time.RFC3339),
					Code: responseCode,
					Headers: map[string]string{
						"x-backend-latency": "0.007",
					},
				},
				Destination: &servicecontrol.Peer{
					RegionCode: "us-central1",
				},
				Resource: &servicecontrol.Resource{
					Name: name,
				},
			},
		},
	}
	_, err := client.Services.Report("endpointsapis.appspot.com", req).Do()
	if err != nil {
		return "", err
	}
	return "{}", nil
}

// Parse processes the request path and extract the resource name and
// permissions.
func parse(r *http.Request) (string, string, error) {
	// Split the request path.
	segments := strings.Split(r.URL.Path, "/")

	// The request path must match "/v1/projects/*/locations/*/workspaces/*" or
	// "/v1/projects/*/locations/*/workspaces". They correspond to the
	// GetWorkspace() and ListWorkspaces() methods defined in ../v1/workspace.proto.
	if segments[0] != "" || segments[1] != "v1" || segments[2] != "projects" || segments[4] != "locations" || segments[6] != "workspaces" || len(segments) > 8 {
		return "", "", errors.New("Resource '" + r.URL.Path + "' not found.")
	}

	// Skip prefix "/v1/".
	resource := r.URL.Path[4:]
	permission := "endpointsapis.appspot.com/workspaces.list"
	if len(segments) == 8 {
		permission = "endpointsapis.appspot.com/workspaces.get"
	}
	return resource, permission, nil
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	received := time.Now()

	// Create a client for Service Control API v2.
	client, err := servicecontrol.NewService(r.Context())
	if err != nil {
		fmt.Fprintln(w, "Error:")
		fmt.Fprintln(w, err.Error())
		return
	}

	resource, permission, err := parse(r)
	if err != nil {
		fmt.Fprintln(w, "Error:")
		fmt.Fprintln(w, err.Error())
		return
	}

	// Perform admission control.
	result, err := check(w, r, resource, permission, received, client)

	var responseCode int64 = 200
	// Print the admission control result.
	if err != nil {
		fmt.Fprintln(w, "Error:")
		fmt.Fprintln(w, err.Error())
		responseCode = 403
	} else {
		fmt.Fprintln(w, "CheckResponse:")
		fmt.Fprintln(w, result)
	}

	// Print all environment variables.
	fmt.Fprintln(w, "Environments:")
	fmt.Fprintln(w, strings.Join(os.Environ(), "\n"))

	// Print all request headers.
	fmt.Fprintln(w, "Headers:")
	for key, values := range r.Header {
		for _, value := range values {
			fmt.Fprintf(w, "%v: %v\n", key, value)
		}
	}

	// Perform telemetry report.
	report(w, r, resource, responseCode, received, client)
}

func main() {
	http.HandleFunc("/", indexHandler)

	port := os.Getenv("PORT")

	log.Printf("Listen and serve on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package postgres

import (
	"fmt"
	"github.com/rbastic/dyndao/schema"
	sg "github.com/rbastic/dyndao/sqlgen"
	"strings"
)

func CreateTable(g *sg.SQLBuilder, s *schema.Schema, table string) (string, error) {
	return g.CoreCreateTable(g, s, table, false)
}

var (
	identityStr = "SERIAL PRIMARY KEY"
)

func RenderCreateColumn(sg *sg.SQLBuilder, t *schema.Table, f *schema.Column) string {
	dataType := strings.ToUpper(f.DBType)

	notNull := ""
	identity := ""
	unique := ""

	if f.IsIdentity {
		identity = identityStr
	}
	if f.AllowNull {
		notNull = "NULL"
	} else {
		notNull = "NOT NULL"
	}

	dataType = mapType(dataType)

	if f.Length > 0 {
		dataType = fmt.Sprintf("%s(%d)", dataType, f.Length)
	}

	if f.IsUnique {
		unique = "UNIQUE"
	}

	if f.IsIdentity {
		return strings.Join([]string{f.Name, identity, notNull, unique}, " ")
	}
	return strings.Join([]string{f.Name, dataType, identity, notNull, unique}, " ")
}

func mapType(s string) string {
	switch s {
	case "number":
		fallthrough
	case "NUMBER":
		fallthrough
	case "integer":
		fallthrough
	case "INTEGER":
		return "INT"
	case "BLOB":
		fallthrough
	case "CLOB":
		return "TEXT"
	case "FLOAT":
		return "FLOAT"
	case "json":
		fallthrough
	case "JSON":
		// NOTE: We use JSONB behind the scenes for performance.
		return "JSONB"
	default:
		return s
	}
}
<commit_msg>mark this area with a comment to revisit it<commit_after>package postgres

import (
	"fmt"
	"github.com/rbastic/dyndao/schema"
	sg "github.com/rbastic/dyndao/sqlgen"
	"strings"
)

func CreateTable(g *sg.SQLBuilder, s *schema.Schema, table string) (string, error) {
	return g.CoreCreateTable(g, s, table, false)
}

var (
	identityStr = "SERIAL PRIMARY KEY"
)

func RenderCreateColumn(sg *sg.SQLBuilder, t *schema.Table, f *schema.Column) string {
	dataType := strings.ToUpper(f.DBType)

	notNull := ""
	identity := ""
	unique := ""

	if f.IsIdentity {
		identity = identityStr
	}
	if f.AllowNull {
		notNull = "NULL"
	} else {
		notNull = "NOT NULL"
	}

	dataType = mapType(dataType)

	if f.Length > 0 {
		dataType = fmt.Sprintf("%s(%d)", dataType, f.Length)
	}

	if f.IsUnique {
		unique = "UNIQUE"
	}

	if f.IsIdentity {
		return strings.Join([]string{f.Name, identity, notNull, unique}, " ")
	}
	return strings.Join([]string{f.Name, dataType, identity, notNull, unique}, " ")
}

func mapType(s string) string {
	switch s {
	case "number":
		fallthrough
	case "NUMBER":
		fallthrough
	case "integer":
		fallthrough
	case "INTEGER":
		return "INT"
	case "BLOB":
		fallthrough
	case "CLOB":
		return "TEXT"
	case "FLOAT":
		return "FLOAT"
	case "json":
		fallthrough
	case "JSON":
		// NOTE: We use JSONB behind the scenes for performance.
		// TODO FIXME Not sure I actually want to make this decision at this stage...
		// It's a user decision, not a package decision.
		return "JSONB"
	default:
		return s
	}
}
<|endoftext|>


<commit_before>package dns

import (
	"fmt"
	"strconv"
	"strings"
)

// Parse the $GENERATE statement as used in BIND9 zones.
// See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
// We are called after '$GENERATE '. After which we expect:
// * the range (12-24/2)
// * lhs (ownername)
// * [[ttl][class]]
// * type
// * rhs (rdata)
func generate(l lex, c chan lex, t chan Token, o string) string {
	step := 1
	if i := strings.IndexAny(l.token, "/"); i != -1 {
		if i+1 == len(l.token) {
			return "bad step in $GENERATE range"
		}
		if s, e := strconv.Atoi(l.token[i+1:]); e != nil {
			return "bad step in $GENERATE range"
		} else {
			if s < 0 {
				return "bad step in $GENERATE range"
			}
			step = s
		}
		l.token = l.token[:i]
	}
	sx := strings.SplitN(l.token, "-", 2)
	if len(sx) != 2 {
		return "bad start/stop in $GENERATE range"
	}
	start, err := strconv.Atoi(sx[0])
	if err != nil {
		return "bad start in $GENERATE range"
	}
	end, err := strconv.Atoi(sx[1])
	if err != nil {
		return "bad end in $GENERATE range"
	}
	if end < 0 || start < 0 || end <= start {
		return "bad range in $GENERATE range"
	}

	<-c // _BLANK
	// Create a complete new string, which we then parse again.
	s := ""
BuildRR:
	l = <-c
	if l.value != _NEWLINE && l.value != _EOF {
		s += l.token
		goto BuildRR
	}
	for i := start; i <= end; i += step {
		escape := false
		dom := ""
		// Defaults
		mod := "%d"
		offset := 0
		var err error
		// Build the domain name.
		for j := 0; j < len(s); j++ { // No 'range' because we need to jump around
			switch s[j] {
			case '\\':
				if escape {
					dom += "\\"
					escape = false
					continue
				}
				escape = true
			case '$':
				mod = "%d"
				offset = 0
				if escape {
					dom += "$"
					escape = false
					continue
				}
				escape = false
				if j+1 >= len(s) { // End of the string
					dom += fmt.Sprintf(mod, i+offset)
					continue
				} else {
					if s[j+1] == '$' {
						dom += "$"
						j++
						continue
					}
				}
				// Search for { and }
				if s[j+1] == '{' { // Modifier block
					sep := strings.Index(s[j+2:], "}")
					if sep == -1 {
						return "bad modifier in $GENERATE"
					}
					//println("checking", s[j+2:j+2+sep])
					mod, offset, err = modToPrintf(s[j+2 : j+2+sep])
					if err != nil {
						return "bad modifier in $GENERATE"
					}
					j += 2 + sep // Jump to it
				}
				//println("mod", mod)
				dom += fmt.Sprintf(mod, i+offset)
			default:
				if escape { // Pretty useless here
					escape = false
					continue
				}
				dom += string(s[j])
			}
		}
		// Re-parse the RR and send it on the current channel t
		rx, err := NewRR("$ORIGIN " + o + "\n" + dom)
		if err != nil {
			return err.(*ParseError).err
		}
		t <- Token{RR: rx}
	}
	return ""
}

// Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
func modToPrintf(s string) (string, int, error) {
	xs := strings.SplitN(s, ",", 3)
	if len(xs) != 3 {
		return "", 0, nil // make error
	}
	// xs[0] is offset, xs[1] is width, xs[2] is base
	if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" {
		return "", 0, nil // make error
	}
	offset, err := strconv.Atoi(xs[0])
	if err != nil {
		return "", 0, err
	}
	width, err := strconv.Atoi(xs[1])
	if err != nil {
		return "", offset, err
	}
	printf := "%"
	switch {
	case width < 0:
		return "", offset, nil // make error
	case width == 0:
		printf += xs[1]
	default:
		printf += "0" + xs[1]
	}
	printf += xs[2]
	return printf, offset, nil
}
<commit_msg>Fix the error reporting<commit_after>package dns

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

// Parse the $GENERATE statement as used in BIND9 zones.
// See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
// We are called after '$GENERATE '. After which we expect:
// * the range (12-24/2)
// * lhs (ownername)
// * [[ttl][class]]
// * type
// * rhs (rdata)
func generate(l lex, c chan lex, t chan Token, o string) string {
	step := 1
	if i := strings.IndexAny(l.token, "/"); i != -1 {
		if i+1 == len(l.token) {
			return "bad step in $GENERATE range"
		}
		if s, e := strconv.Atoi(l.token[i+1:]); e != nil {
			return "bad step in $GENERATE range"
		} else {
			if s < 0 {
				return "bad step in $GENERATE range"
			}
			step = s
		}
		l.token = l.token[:i]
	}
	sx := strings.SplitN(l.token, "-", 2)
	if len(sx) != 2 {
		return "bad start-stop in $GENERATE range"
	}
	start, err := strconv.Atoi(sx[0])
	if err != nil {
		return "bad start in $GENERATE range"
	}
	end, err := strconv.Atoi(sx[1])
	if err != nil {
		return "bad stop in $GENERATE range"
	}
	if end < 0 || start < 0 || end <= start {
		return "bad range in $GENERATE range"
	}

	<-c // _BLANK
	// Create a complete new string, which we then parse again.
	s := ""
BuildRR:
	l = <-c
	if l.value != _NEWLINE && l.value != _EOF {
		s += l.token
		goto BuildRR
	}
	for i := start; i <= end; i += step {
		var (
			escape bool
			dom string
			mod string
			offset int
			err error
		)

		for j := 0; j < len(s); j++ { // No 'range' because we need to jump around
			switch s[j] {
			case '\\':
				if escape {
					dom += "\\"
					escape = false
					continue
				}
				escape = true
			case '$':
				mod = "%d"
				offset = 0
				if escape {
					dom += "$"
					escape = false
					continue
				}
				escape = false
				if j+1 >= len(s) { // End of the string
					dom += fmt.Sprintf(mod, i+offset)
					continue
				} else {
					if s[j+1] == '$' {
						dom += "$"
						j++
						continue
					}
				}
				// Search for { and }
				if s[j+1] == '{' { // Modifier block
					sep := strings.Index(s[j+2:], "}")
					if sep == -1 {
						return "bad modifier in $GENERATE"
					}
					//println("checking", s[j+2:j+2+sep])
					mod, offset, err = modToPrintf(s[j+2 : j+2+sep])
					if err != nil {
						return "bad modifier in $GENERATE"
					}
					j += 2 + sep // Jump to it
				}
				//println("mod", mod)
				dom += fmt.Sprintf(mod, i+offset)
			default:
				if escape { // Pretty useless here
					escape = false
					continue
				}
				dom += string(s[j])
			}
		}
		// Re-parse the RR and send it on the current channel t
		rx, err := NewRR("$ORIGIN " + o + "\n" + dom)
		if err != nil {
			return err.(*ParseError).err
		}
		t <- Token{RR: rx}
	}
	return ""
}

// Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
func modToPrintf(s string) (string, int, error) {
	xs := strings.SplitN(s, ",", 3)
	if len(xs) != 3 {
		return "", 0, errors.New("fubar")
	}
	// xs[0] is offset, xs[1] is width, xs[2] is base
	if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" {
		return "", 0, errors.New("fubar")
	}
	offset, err := strconv.Atoi(xs[0])
	if err != nil {
		return "", 0, err
	}
	width, err := strconv.Atoi(xs[1])
	if err != nil {
		return "", offset, err
	}
	printf := "%"
	switch {
	case width < 0:
		return "", offset, errors.New("fubar")
	case width == 0:
		printf += xs[1]
	default:
		printf += "0" + xs[1]
	}
	printf += xs[2]
	return printf, offset, nil
}
<|endoftext|>


<commit_before>package controller

import (
	"fmt"
	mongomodels "koding/db/models"
	"koding/db/mongodb/modelhelper"
	"socialapi/models"
)

func (mwc *Controller) migrateAllTags() error {
	o := modelhelper.Options{
		Sort: "meta.createdAt",
	}
	s := modelhelper.Selector{
		"socialApiChannelId": modelhelper.Selector{"$exists": false},
	}
	errCount := 0

	handleError := func(t *mongomodels.Tag, err error) {
		mwc.log.Error("an error occured for %s: %s", t.Id.Hex(), err)
		errCount++
	}

	for {
		o.Skip = errCount
		tag, err := modelhelper.GetTag(s, o)
		if err != nil {
			if err == modelhelper.ErrNotFound {
				mwc.log.Notice("Tag migration completed with %d errors", errCount)
				return nil
			}
			return fmt.Errorf("tag cannot be fetched: %s", err)
		}
		c, err := createTagChannel(tag)
		if err != nil {
			handleError(tag, err)
			continue
		}

		if err := completeTagMigration(tag, c); err != nil {
			handleError(tag, err)
			continue
		}

	}

	return nil
}

func createTagChannel(t *mongomodels.Tag) (*models.Channel, error) {
	creatorId, err := fetchTagCreatorId(t)
	if err != nil {
		return nil, err
	}

	c := models.NewChannel()
	c.CreatorId = creatorId
	c.Name = t.Slug
	c.GroupName = t.Group // create group if needed
	// = t.Category "user-tag", "system tag" mevzusu ama bug isi hala var mi bilmiyorum
	c.Purpose = "Channel for " + c.Name + " topic"
	c.TypeConstant = models.Channel_TYPE_TOPIC
	c.PrivacyConstant = models.Channel_PRIVACY_PRIVATE
	c.CreatedAt = t.Meta.CreatedAt
	c.UpdatedAt = t.Meta.ModifiedAt
	if err := c.CreateRaw(); err != nil {
		return nil, err
	}

	return c, nil
}

func fetchTagCreatorId(t *mongomodels.Tag) (int64, error) {
	s := modelhelper.Selector{
		"sourceId": t.Id,
		"as":       "related",
	}
	r, err := modelhelper.GetRelationship(s)
	if err != nil {
		return 0, fmt.Errorf("Tag creator cannot be fetched: %s", err)
	}
	a := models.NewAccount()
	a.OldId = r.TargetId.Hex()

	if err := a.FetchOrCreate(); err != nil {
		return 0, fmt.Errorf("Tag creator cannot be created: %s", err)
	}

	return a.Id, nil
}

func (mwc *Controller) createTagFollowers(t *mongomodels.Tag, channelId int64) error {

	return modelhelper.UpdateTag(tag)
}
<commit_msg>Migration: Tag follower migrator is added<commit_after>package controller

import (
	"fmt"
	mongomodels "koding/db/models"
	"koding/db/mongodb/modelhelper"
	"socialapi/models"

	"github.com/jinzhu/gorm"
)

func (mwc *Controller) migrateAllTags() error {
	o := modelhelper.Options{
		Sort: "meta.createdAt",
	}
	s := modelhelper.Selector{
		"socialApiChannelId": modelhelper.Selector{"$exists": false},
	}
	errCount := 0

	handleError := func(t *mongomodels.Tag, err error) {
		mwc.log.Error("an error occured for tag %s: %s", t.Id.Hex(), err)
		errCount++
	}

	for {
		o.Skip = errCount
		tag, err := modelhelper.GetTag(s, o)
		if err != nil {
			if err == modelhelper.ErrNotFound {
				mwc.log.Notice("Tag migration completed with %d errors", errCount)
				return nil
			}
			return fmt.Errorf("tag cannot be fetched: %s", err)
		}
		channelId, err := createTagChannel(tag)
		if err != nil {
			handleError(tag, err)
			continue
		}
		if err := mwc.createTagFollowers(tag, channelId); err != nil {
			handleError(tag, err)
			continue
		}

		if err := completeTagMigration(tag, channelId); err != nil {
			handleError(tag, err)
			continue
		}

	}

	return nil
}

func createTagChannel(t *mongomodels.Tag) (int64, error) {
	creatorId, err := fetchTagCreatorId(t)
	if err != nil {
		return 0, err
	}

	c := models.NewChannel()

	channelId, err := c.FetchChannelIdByNameAndGroupName(t.Slug, t.Group)
	if err == nil {
		return channelId, nil
	}
	if err != gorm.RecordNotFound {
		return 0, err
	}

	c.CreatorId = creatorId
	c.Name = t.Slug
	c.GroupName = t.Group // create group if needed
	c.Purpose = "Channel for " + c.Name + " topic"
	c.TypeConstant = models.Channel_TYPE_TOPIC
	c.PrivacyConstant = models.Channel_PRIVACY_PRIVATE
	c.CreatedAt = t.Meta.CreatedAt
	c.UpdatedAt = t.Meta.ModifiedAt
	if err := c.CreateRaw(); err != nil {
		return 0, err
	}

	return c.Id, nil
}

func fetchTagCreatorId(t *mongomodels.Tag) (int64, error) {
	s := modelhelper.Selector{
		"sourceId": t.Id,
		"as":       "related",
	}
	r, err := modelhelper.GetRelationship(s)
	if err != nil {
		return 0, fmt.Errorf("Tag creator cannot be fetched: %s", err)
	}
	a := models.NewAccount()
	a.OldId = r.TargetId.Hex()

	if err := a.FetchOrCreate(); err != nil {
		return 0, fmt.Errorf("Tag creator cannot be created: %s", err)
	}

	return a.Id, nil
}

func (mwc *Controller) createTagFollowers(t *mongomodels.Tag, channelId int64) error {
	s := modelhelper.Selector{
		"sourceId":   t.Id,
		"as":         "follower",
		"targetName": "JAccount",
	}
	iter := modelhelper.GetRelationshipIter(s)
	defer iter.Close()
	var r mongomodels.Relationship
	for iter.Next(&r) {
		if r.MigrationStatus == "Completed" {
			continue
		}
		// fetch follower
		a := models.NewAccount()
		a.OldId = r.TargetId.Hex()
		err := a.FetchOrCreate()
		if err != nil {
			mwc.log.Error("Tag follower cannot be fetched: %s", err)
			continue
		}

		cp := models.NewChannelParticipant()
		cp.ChannelId = channelId
		cp.AccountId = a.Id
		cp.StatusConstant = models.ChannelParticipant_STATUS_ACTIVE
		cp.LastSeenAt = r.TimeStamp
		cp.UpdatedAt = r.TimeStamp
		cp.CreatedAt = r.TimeStamp
		if err := cp.CreateRaw(); err != nil {
			mwc.log.Error("Tag follower cannot be created: %s", err)
			continue
		}

		r.MigrationStatus = "Completed"
		if err := modelhelper.UpdateRelationship(&r); err != nil {
			mwc.log.Error("Tag follower cannot be flagged as migrated: %s", err)
		}
	}

	return iter.Err()
}

func completeTagMigration(tag *mongomodels.Tag, channelId int64) error {
	tag.SocialApiChannelId = channelId

	return modelhelper.UpdateTag(tag)
}
<|endoftext|>


<commit_before>package filesys

import (
	"context"
	"fmt"
	"io"
	"math"
	"net/http"
	"os"
	"time"

	"github.com/seaweedfs/fuse"
	"github.com/seaweedfs/fuse/fs"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

type FileHandle struct {
	// cache file has been written to
	dirtyPages  *ContinuousDirtyPages
	contentType string
	handle      uint64

	f         *File
	RequestId fuse.RequestID // unique ID for request
	NodeId    fuse.NodeID    // file or directory the request is about
	Uid       uint32         // user ID of process making request
	Gid       uint32         // group ID of process making request

}

func newFileHandle(file *File, uid, gid uint32) *FileHandle {
	fh := &FileHandle{
		f:          file,
		dirtyPages: newDirtyPages(file),
		Uid:        uid,
		Gid:        gid,
	}
	if fh.f.entry != nil {
		fh.f.entry.Attributes.FileSize = filer2.FileSize(fh.f.entry)
	}
	return fh
}

var _ = fs.Handle(&FileHandle{})

// var _ = fs.HandleReadAller(&FileHandle{})
var _ = fs.HandleReader(&FileHandle{})
var _ = fs.HandleFlusher(&FileHandle{})
var _ = fs.HandleWriter(&FileHandle{})
var _ = fs.HandleReleaser(&FileHandle{})

func (fh *FileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {

	glog.V(4).Infof("%s read fh %d: [%d,%d) size %d resp.Data len=%d cap=%d", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(req.Size), req.Size, len(resp.Data), cap(resp.Data))

	buff := resp.Data[:cap(resp.Data)]
	if req.Size > cap(resp.Data) {
		// should not happen
		buff = make([]byte, req.Size)
	}

	totalRead, err := fh.readFromChunks(buff, req.Offset)
	if err == nil {
		maxStop := fh.readFromDirtyPages(buff, req.Offset)
		totalRead = max(maxStop - req.Offset, totalRead)
	}

	totalRead = min(int64(len(buff)), totalRead)
	resp.Data = buff[:totalRead]

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	return err
}

func (fh *FileHandle) readFromDirtyPages(buff []byte, startOffset int64) (maxStop int64) {
	return fh.dirtyPages.ReadDirtyData(buff, startOffset)
}

func (fh *FileHandle) readFromChunks(buff []byte, offset int64) (int64, error) {

	fileSize := int64(filer2.FileSize(fh.f.entry))

	if fileSize == 0 {
		glog.V(1).Infof("empty fh %v", fh.f.fullpath())
		return 0, io.EOF
	}

	var chunkResolveErr error
	if fh.f.entryViewCache == nil {
		fh.f.entryViewCache, chunkResolveErr = filer2.NonOverlappingVisibleIntervals(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		if chunkResolveErr != nil {
			return 0, fmt.Errorf("fail to resolve chunk manifest: %v", chunkResolveErr)
		}
		fh.f.reader = nil
	}

	if fh.f.reader == nil {
		chunkViews := filer2.ViewFromVisibleIntervals(fh.f.entryViewCache, 0, math.MaxInt32)
		fh.f.reader = filer2.NewChunkReaderAtFromClient(fh.f.wfs, chunkViews, fh.f.wfs.chunkCache, fileSize)
	}

	totalRead, err := fh.f.reader.ReadAt(buff, offset)

	if err == io.EOF {
		err = nil
	}

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
	}

	// glog.V(0).Infof("file handle read %s [%d,%d] %d : %v", fh.f.fullpath(), offset, offset+int64(totalRead), totalRead, err)

	return int64(totalRead), err
}

// Write to the file handle
func (fh *FileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {

	// write the request to volume servers
	data := make([]byte, len(req.Data))
	copy(data, req.Data)

	fh.f.entry.Attributes.FileSize = uint64(max(req.Offset+int64(len(data)), int64(fh.f.entry.Attributes.FileSize)))
	glog.V(5).Infof("%v write [%d,%d)", fh.f.fullpath(), req.Offset, req.Offset+int64(len(req.Data)))

	chunks, err := fh.dirtyPages.AddPage(req.Offset, data)
	if err != nil {
		glog.Errorf("%v write fh %d: [%d,%d): %v", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(len(data)), err)
		return fuse.EIO
	}

	resp.Size = len(data)

	if req.Offset == 0 {
		// detect mime type
		fh.contentType = http.DetectContentType(data)
		fh.f.dirtyMetadata = true
	}

	if len(chunks) > 0 {

		fh.f.addChunks(chunks)

		fh.f.dirtyMetadata = true
	}

	return nil
}

func (fh *FileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) error {

	glog.V(4).Infof("Release %v fh %d", fh.f.fullpath(), fh.handle)

	fh.f.isOpen--

	if fh.f.isOpen <= 0 {
		fh.dirtyPages.releaseResource()
		fh.f.wfs.ReleaseHandle(fh.f.fullpath(), fuse.HandleID(fh.handle))
	}
	fh.f.entryViewCache = nil
	fh.f.reader = nil

	return nil
}

func (fh *FileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) error {
	// fflush works at fh level
	// send the data to the OS
	glog.V(5).Infof("Flush %s fh %d %v", fh.f.fullpath(), fh.handle, req)

	chunks, err := fh.dirtyPages.FlushToStorage()
	if err != nil {
		glog.Errorf("flush %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	if len(chunks) > 0 {
		fh.f.addChunks(chunks)
		fh.f.dirtyMetadata = true
	}

	if !fh.f.dirtyMetadata {
		return nil
	}

	err = fh.f.wfs.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		if fh.f.entry.Attributes != nil {
			fh.f.entry.Attributes.Mime = fh.contentType
			if fh.f.entry.Attributes.Uid == 0 {
				fh.f.entry.Attributes.Uid = req.Uid
			}
			if fh.f.entry.Attributes.Gid == 0 {
				fh.f.entry.Attributes.Gid = req.Gid
			}
			if fh.f.entry.Attributes.Crtime == 0 {
				fh.f.entry.Attributes.Crtime = time.Now().Unix()
			}
			fh.f.entry.Attributes.Mtime = time.Now().Unix()
			fh.f.entry.Attributes.FileMode = uint32(os.FileMode(fh.f.entry.Attributes.FileMode) &^ fh.f.wfs.option.Umask)
			fh.f.entry.Attributes.Collection = fh.dirtyPages.collection
			fh.f.entry.Attributes.Replication = fh.dirtyPages.replication
		}

		request := &filer_pb.CreateEntryRequest{
			Directory: fh.f.dir.FullPath(),
			Entry:     fh.f.entry,
		}

		glog.V(4).Infof("%s set chunks: %v", fh.f.fullpath(), len(fh.f.entry.Chunks))
		for i, chunk := range fh.f.entry.Chunks {
			glog.V(4).Infof("%s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		chunks, garbages := filer2.CompactFileChunks(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		chunks, manifestErr := filer2.MaybeManifestize(fh.f.wfs.saveDataAsChunk(fh.f.dir.FullPath()), chunks)
		if manifestErr != nil {
			// not good, but should be ok
			glog.V(0).Infof("MaybeManifestize: %v", manifestErr)
		}
		fh.f.entry.Chunks = chunks
		// fh.f.entryViewCache = nil

		// special handling of one chunk md5
		if len(chunks) == 1 {
		}

		if err := filer_pb.CreateEntry(client, request); err != nil {
			glog.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
			return fmt.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
		}

		fh.f.wfs.metaCache.InsertEntry(context.Background(), filer2.FromPbEntry(request.Directory, request.Entry))

		fh.f.wfs.deleteFileChunks(garbages)
		for i, chunk := range garbages {
			glog.V(4).Infof("garbage %s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		return nil
	})

	if err == nil {
		fh.f.dirtyMetadata = false
	}

	if err != nil {
		glog.Errorf("%v fh %d flush: %v", fh.f.fullpath(), fh.handle, err)
		return fuse.EIO
	}

	return nil
}
<commit_msg>report error first<commit_after>package filesys

import (
	"context"
	"fmt"
	"io"
	"math"
	"net/http"
	"os"
	"time"

	"github.com/seaweedfs/fuse"
	"github.com/seaweedfs/fuse/fs"

	"github.com/chrislusf/seaweedfs/weed/filer2"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

type FileHandle struct {
	// cache file has been written to
	dirtyPages  *ContinuousDirtyPages
	contentType string
	handle      uint64

	f         *File
	RequestId fuse.RequestID // unique ID for request
	NodeId    fuse.NodeID    // file or directory the request is about
	Uid       uint32         // user ID of process making request
	Gid       uint32         // group ID of process making request

}

func newFileHandle(file *File, uid, gid uint32) *FileHandle {
	fh := &FileHandle{
		f:          file,
		dirtyPages: newDirtyPages(file),
		Uid:        uid,
		Gid:        gid,
	}
	if fh.f.entry != nil {
		fh.f.entry.Attributes.FileSize = filer2.FileSize(fh.f.entry)
	}
	return fh
}

var _ = fs.Handle(&FileHandle{})

// var _ = fs.HandleReadAller(&FileHandle{})
var _ = fs.HandleReader(&FileHandle{})
var _ = fs.HandleFlusher(&FileHandle{})
var _ = fs.HandleWriter(&FileHandle{})
var _ = fs.HandleReleaser(&FileHandle{})

func (fh *FileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {

	glog.V(4).Infof("%s read fh %d: [%d,%d) size %d resp.Data len=%d cap=%d", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(req.Size), req.Size, len(resp.Data), cap(resp.Data))

	buff := resp.Data[:cap(resp.Data)]
	if req.Size > cap(resp.Data) {
		// should not happen
		buff = make([]byte, req.Size)
	}

	totalRead, err := fh.readFromChunks(buff, req.Offset)
	if err == nil {
		maxStop := fh.readFromDirtyPages(buff, req.Offset)
		totalRead = max(maxStop - req.Offset, totalRead)
	}

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	totalRead = min(int64(len(buff)), totalRead)
	resp.Data = buff[:totalRead]

	return err
}

func (fh *FileHandle) readFromDirtyPages(buff []byte, startOffset int64) (maxStop int64) {
	return fh.dirtyPages.ReadDirtyData(buff, startOffset)
}

func (fh *FileHandle) readFromChunks(buff []byte, offset int64) (int64, error) {

	fileSize := int64(filer2.FileSize(fh.f.entry))

	if fileSize == 0 {
		glog.V(1).Infof("empty fh %v", fh.f.fullpath())
		return 0, io.EOF
	}

	var chunkResolveErr error
	if fh.f.entryViewCache == nil {
		fh.f.entryViewCache, chunkResolveErr = filer2.NonOverlappingVisibleIntervals(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		if chunkResolveErr != nil {
			return 0, fmt.Errorf("fail to resolve chunk manifest: %v", chunkResolveErr)
		}
		fh.f.reader = nil
	}

	if fh.f.reader == nil {
		chunkViews := filer2.ViewFromVisibleIntervals(fh.f.entryViewCache, 0, math.MaxInt32)
		fh.f.reader = filer2.NewChunkReaderAtFromClient(fh.f.wfs, chunkViews, fh.f.wfs.chunkCache, fileSize)
	}

	totalRead, err := fh.f.reader.ReadAt(buff, offset)

	if err == io.EOF {
		err = nil
	}

	if err != nil {
		glog.Errorf("file handle read %s: %v", fh.f.fullpath(), err)
	}

	// glog.V(0).Infof("file handle read %s [%d,%d] %d : %v", fh.f.fullpath(), offset, offset+int64(totalRead), totalRead, err)

	return int64(totalRead), err
}

// Write to the file handle
func (fh *FileHandle) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {

	// write the request to volume servers
	data := make([]byte, len(req.Data))
	copy(data, req.Data)

	fh.f.entry.Attributes.FileSize = uint64(max(req.Offset+int64(len(data)), int64(fh.f.entry.Attributes.FileSize)))
	glog.V(5).Infof("%v write [%d,%d)", fh.f.fullpath(), req.Offset, req.Offset+int64(len(req.Data)))

	chunks, err := fh.dirtyPages.AddPage(req.Offset, data)
	if err != nil {
		glog.Errorf("%v write fh %d: [%d,%d): %v", fh.f.fullpath(), fh.handle, req.Offset, req.Offset+int64(len(data)), err)
		return fuse.EIO
	}

	resp.Size = len(data)

	if req.Offset == 0 {
		// detect mime type
		fh.contentType = http.DetectContentType(data)
		fh.f.dirtyMetadata = true
	}

	if len(chunks) > 0 {

		fh.f.addChunks(chunks)

		fh.f.dirtyMetadata = true
	}

	return nil
}

func (fh *FileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) error {

	glog.V(4).Infof("Release %v fh %d", fh.f.fullpath(), fh.handle)

	fh.f.isOpen--

	if fh.f.isOpen <= 0 {
		fh.dirtyPages.releaseResource()
		fh.f.wfs.ReleaseHandle(fh.f.fullpath(), fuse.HandleID(fh.handle))
	}
	fh.f.entryViewCache = nil
	fh.f.reader = nil

	return nil
}

func (fh *FileHandle) Flush(ctx context.Context, req *fuse.FlushRequest) error {
	// fflush works at fh level
	// send the data to the OS
	glog.V(5).Infof("Flush %s fh %d %v", fh.f.fullpath(), fh.handle, req)

	chunks, err := fh.dirtyPages.FlushToStorage()
	if err != nil {
		glog.Errorf("flush %s: %v", fh.f.fullpath(), err)
		return fuse.EIO
	}

	if len(chunks) > 0 {
		fh.f.addChunks(chunks)
		fh.f.dirtyMetadata = true
	}

	if !fh.f.dirtyMetadata {
		return nil
	}

	err = fh.f.wfs.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {

		if fh.f.entry.Attributes != nil {
			fh.f.entry.Attributes.Mime = fh.contentType
			if fh.f.entry.Attributes.Uid == 0 {
				fh.f.entry.Attributes.Uid = req.Uid
			}
			if fh.f.entry.Attributes.Gid == 0 {
				fh.f.entry.Attributes.Gid = req.Gid
			}
			if fh.f.entry.Attributes.Crtime == 0 {
				fh.f.entry.Attributes.Crtime = time.Now().Unix()
			}
			fh.f.entry.Attributes.Mtime = time.Now().Unix()
			fh.f.entry.Attributes.FileMode = uint32(os.FileMode(fh.f.entry.Attributes.FileMode) &^ fh.f.wfs.option.Umask)
			fh.f.entry.Attributes.Collection = fh.dirtyPages.collection
			fh.f.entry.Attributes.Replication = fh.dirtyPages.replication
		}

		request := &filer_pb.CreateEntryRequest{
			Directory: fh.f.dir.FullPath(),
			Entry:     fh.f.entry,
		}

		glog.V(4).Infof("%s set chunks: %v", fh.f.fullpath(), len(fh.f.entry.Chunks))
		for i, chunk := range fh.f.entry.Chunks {
			glog.V(4).Infof("%s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		chunks, garbages := filer2.CompactFileChunks(filer2.LookupFn(fh.f.wfs), fh.f.entry.Chunks)
		chunks, manifestErr := filer2.MaybeManifestize(fh.f.wfs.saveDataAsChunk(fh.f.dir.FullPath()), chunks)
		if manifestErr != nil {
			// not good, but should be ok
			glog.V(0).Infof("MaybeManifestize: %v", manifestErr)
		}
		fh.f.entry.Chunks = chunks
		// fh.f.entryViewCache = nil

		// special handling of one chunk md5
		if len(chunks) == 1 {
		}

		if err := filer_pb.CreateEntry(client, request); err != nil {
			glog.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
			return fmt.Errorf("fh flush create %s: %v", fh.f.fullpath(), err)
		}

		fh.f.wfs.metaCache.InsertEntry(context.Background(), filer2.FromPbEntry(request.Directory, request.Entry))

		fh.f.wfs.deleteFileChunks(garbages)
		for i, chunk := range garbages {
			glog.V(4).Infof("garbage %s chunks %d: %v [%d,%d)", fh.f.fullpath(), i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		return nil
	})

	if err == nil {
		fh.f.dirtyMetadata = false
	}

	if err != nil {
		glog.Errorf("%v fh %d flush: %v", fh.f.fullpath(), fh.handle, err)
		return fuse.EIO
	}

	return nil
}
<|endoftext|>


<commit_before>package whirlytubes

import (
	"bufio"
	"fmt"
	"net"
	"regexp"
)

type Address interface {
	Send(string) error
	Receive() (string, error)
	Verify() (bool, error)
}

type TcpAddress struct {
	Addr string
	Cnxn net.TCPConn
}

func (addr TcpAddress) Verify() (b bool, err error) {
	b, err = regexp.MatchString(".*:.*", addr.Addr) //fix connection for address, store connection in address
	return
}

func (addr TcpAddress) Send(msg string) (err error) {
	conn, err := net.Dial("tcp", addr.Addr)
	if err != nil {
		return
	}
	_, err = fmt.Fprint(conn, msg) //add writing capabilities
}

func (addr TcpAddress) Receive() (msg string, err error) {
	conn, err := net.Dial("tcp", addr.Addr)
	if err != nil {
		return "", err
	}
	msg, err := bufio.NewReader(conn).ReadString('\n')
	return
}
<commit_msg>added init function for addresses<commit_after>package whirlytubes

import (
	"bufio"
	"fmt"
	"net"
	"regexp"
)

type Address interface {
	Send(string) error
	Receive() (string, error)
	verify() (bool, error)
	Init(string) error
}

type TcpAddress struct {
	Addr string
	Cnxn net.TCPConn
}

func (addr TcpAddress) verify() (b bool, err error) {
	b, err = regexp.MatchString(".*:.*", addr.Addr) //fix connection for address, store connection in address
	return
}

func (addr TcpAddress) Init(a string) error {
	addr.Addr = a
	b, err := addr.verify()
	if err != nil {
		return err
	}
	if !b {
		addr.Addr = nil
		return fmt.Errorf("Address Initialization: malformed address: %s\n\tshould be I.P.add.ress:port\n", a)
	}
	return nil
}
func (addr TcpAddress) Send(msg string) (err error) {
	conn, err := net.Dial("tcp", addr.Addr)
	if err != nil {
		return
	}
	_, err = fmt.Fprint(conn, msg) //add writing capabilities
}

func (addr TcpAddress) Receive() (msg string, err error) {
	conn, err := net.Dial("tcp", addr.Addr)
	if err != nil {
		return "", err
	}
	msg, err := bufio.NewReader(conn).ReadString('\n')
	return
}
<|endoftext|>


<commit_before><commit_msg>Marking experiment failed when suggestion fails (#773)<commit_after><|endoftext|>


<commit_before>package healthsyncer

import (
	"context"
	"reflect"
	"sort"
	"time"

	"github.com/pkg/errors"
	"github.com/rancher/norman/condition"
	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
	corev1 "github.com/rancher/rancher/pkg/generated/norman/core/v1"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/types/config"
	"github.com/rancher/wrangler/pkg/ticker"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
)

const (
	syncInterval = 15 * time.Second
)

type ClusterControllerLifecycle interface {
	Stop(cluster *v3.Cluster)
}

type HealthSyncer struct {
	ctx               context.Context
	clusterName       string
	clusterLister     v3.ClusterLister
	clusters          v3.ClusterInterface
	componentStatuses corev1.ComponentStatusInterface
	namespaces        corev1.NamespaceInterface
	k8s               kubernetes.Interface
}

func Register(ctx context.Context, workload *config.UserContext) {
	h := &HealthSyncer{
		ctx:               ctx,
		clusterName:       workload.ClusterName,
		clusterLister:     workload.Management.Management.Clusters("").Controller().Lister(),
		clusters:          workload.Management.Management.Clusters(""),
		componentStatuses: workload.Core.ComponentStatuses(""),
		namespaces:        workload.Core.Namespaces(""),
		k8s:               workload.K8sClient,
	}

	go h.syncHealth(ctx, syncInterval)
}

func (h *HealthSyncer) syncHealth(ctx context.Context, syncHealth time.Duration) {
	for range ticker.Context(ctx, syncHealth) {
		err := h.updateClusterHealth()
		if err != nil && !apierrors.IsConflict(err) {
			logrus.Error(err)
		}
	}
}

func (h *HealthSyncer) getComponentStatus(cluster *v3.Cluster) error {
	ctx, cancel := context.WithTimeout(h.ctx, 5*time.Second)
	defer cancel()

	// Prior to k8s v1.14, we only needed to list the ComponentStatuses from the user cluster.
	// As of k8s v1.14, kubeapi returns a successful ComponentStatuses response even if etcd is not available.
	// To work around this, now we try to get a namespace from the API, even if not found, it means the API is up.
	if _, err := h.k8s.CoreV1().Namespaces().Get(ctx, "kube-system", metav1.GetOptions{}); err != nil && !apierrors.IsNotFound(err) {
		return condition.Error("ComponentStatsFetchingFailure", errors.Wrap(err, "Failed to communicate with API server"))
	}

	cses, err := h.componentStatuses.List(metav1.ListOptions{})
	if err != nil {
		return condition.Error("ComponentStatsFetchingFailure", errors.Wrap(err, "Failed to communicate with API server"))
	}
	cluster.Status.ComponentStatuses = []v32.ClusterComponentStatus{}
	for _, cs := range cses.Items {
		clusterCS := convertToClusterComponentStatus(&cs)
		cluster.Status.ComponentStatuses = append(cluster.Status.ComponentStatuses, *clusterCS)
	}
	sort.Slice(cluster.Status.ComponentStatuses, func(i, j int) bool {
		return cluster.Status.ComponentStatuses[i].Name < cluster.Status.ComponentStatuses[j].Name
	})
	return nil
}

func (h *HealthSyncer) updateClusterHealth() error {
	oldCluster, err := h.getCluster()
	if err != nil {
		return err
	}
	cluster := oldCluster.DeepCopy()
	if !v32.ClusterConditionProvisioned.IsTrue(cluster) {
		logrus.Debugf("Skip updating cluster health - cluster [%s] not provisioned yet", h.clusterName)
		return nil
	}

	newObj, err := v32.ClusterConditionReady.Do(cluster, func() (runtime.Object, error) {
		for i := 0; ; i++ {
			err := h.getComponentStatus(cluster)
			if err == nil || i > 1 {
				return cluster, errors.Wrap(err, "cluster health check failed")
			}
			select {
			case <-h.ctx.Done():
				return cluster, err
			case <-time.After(5 * time.Second):
			}
		}
	})

	if err == nil {
		v32.ClusterConditionWaiting.True(newObj)
		v32.ClusterConditionWaiting.Message(newObj, "")
	}

	if !reflect.DeepEqual(oldCluster, newObj) {
		if _, err := h.clusters.Update(newObj.(*v3.Cluster)); err != nil {
			return errors.Wrapf(err, "[updateClusterHealth] Failed to update cluster [%s]", cluster.Name)
		}
	}

	// Purposefully not return error.  This is so when the cluster goes unavailable we don't just keep failing
	// which will essentially keep the controller alive forever, instead of shutting down.
	return nil
}

func (h *HealthSyncer) getCluster() (*v3.Cluster, error) {
	return h.clusterLister.Get("", h.clusterName)
}

func convertToClusterComponentStatus(cs *v1.ComponentStatus) *v32.ClusterComponentStatus {
	return &v32.ClusterComponentStatus{
		Name:       cs.Name,
		Conditions: cs.Conditions,
	}
}
<commit_msg>Update error message to be more explicit<commit_after>package healthsyncer

import (
	"context"
	"reflect"
	"sort"
	"time"

	"github.com/pkg/errors"
	"github.com/rancher/norman/condition"
	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
	corev1 "github.com/rancher/rancher/pkg/generated/norman/core/v1"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/types/config"
	"github.com/rancher/wrangler/pkg/ticker"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
)

const (
	syncInterval = 15 * time.Second
)

type ClusterControllerLifecycle interface {
	Stop(cluster *v3.Cluster)
}

type HealthSyncer struct {
	ctx               context.Context
	clusterName       string
	clusterLister     v3.ClusterLister
	clusters          v3.ClusterInterface
	componentStatuses corev1.ComponentStatusInterface
	namespaces        corev1.NamespaceInterface
	k8s               kubernetes.Interface
}

func Register(ctx context.Context, workload *config.UserContext) {
	h := &HealthSyncer{
		ctx:               ctx,
		clusterName:       workload.ClusterName,
		clusterLister:     workload.Management.Management.Clusters("").Controller().Lister(),
		clusters:          workload.Management.Management.Clusters(""),
		componentStatuses: workload.Core.ComponentStatuses(""),
		namespaces:        workload.Core.Namespaces(""),
		k8s:               workload.K8sClient,
	}

	go h.syncHealth(ctx, syncInterval)
}

func (h *HealthSyncer) syncHealth(ctx context.Context, syncHealth time.Duration) {
	for range ticker.Context(ctx, syncHealth) {
		err := h.updateClusterHealth()
		if err != nil && !apierrors.IsConflict(err) {
			logrus.Error(err)
		}
	}
}

func (h *HealthSyncer) getComponentStatus(cluster *v3.Cluster) error {
	ctx, cancel := context.WithTimeout(h.ctx, 5*time.Second)
	defer cancel()

	// Prior to k8s v1.14, we only needed to list the ComponentStatuses from the user cluster.
	// As of k8s v1.14, kubeapi returns a successful ComponentStatuses response even if etcd is not available.
	// To work around this, now we try to get a namespace from the API, even if not found, it means the API is up.
	if _, err := h.k8s.CoreV1().Namespaces().Get(ctx, "kube-system", metav1.GetOptions{}); err != nil && !apierrors.IsNotFound(err) {
		return condition.Error("ComponentStatsFetchingFailure", errors.Wrap(err, "Failed to communicate with API server during namespace check"))
	}

	cses, err := h.componentStatuses.List(metav1.ListOptions{})
	if err != nil {
		return condition.Error("ComponentStatsFetchingFailure", errors.Wrap(err, "Failed to communicate with API server"))
	}
	cluster.Status.ComponentStatuses = []v32.ClusterComponentStatus{}
	for _, cs := range cses.Items {
		clusterCS := convertToClusterComponentStatus(&cs)
		cluster.Status.ComponentStatuses = append(cluster.Status.ComponentStatuses, *clusterCS)
	}
	sort.Slice(cluster.Status.ComponentStatuses, func(i, j int) bool {
		return cluster.Status.ComponentStatuses[i].Name < cluster.Status.ComponentStatuses[j].Name
	})
	return nil
}

func (h *HealthSyncer) updateClusterHealth() error {
	oldCluster, err := h.getCluster()
	if err != nil {
		return err
	}
	cluster := oldCluster.DeepCopy()
	if !v32.ClusterConditionProvisioned.IsTrue(cluster) {
		logrus.Debugf("Skip updating cluster health - cluster [%s] not provisioned yet", h.clusterName)
		return nil
	}

	newObj, err := v32.ClusterConditionReady.Do(cluster, func() (runtime.Object, error) {
		for i := 0; ; i++ {
			err := h.getComponentStatus(cluster)
			if err == nil || i > 1 {
				return cluster, errors.Wrap(err, "cluster health check failed")
			}
			select {
			case <-h.ctx.Done():
				return cluster, err
			case <-time.After(5 * time.Second):
			}
		}
	})

	if err == nil {
		v32.ClusterConditionWaiting.True(newObj)
		v32.ClusterConditionWaiting.Message(newObj, "")
	}

	if !reflect.DeepEqual(oldCluster, newObj) {
		if _, err := h.clusters.Update(newObj.(*v3.Cluster)); err != nil {
			return errors.Wrapf(err, "[updateClusterHealth] Failed to update cluster [%s]", cluster.Name)
		}
	}

	// Purposefully not return error.  This is so when the cluster goes unavailable we don't just keep failing
	// which will essentially keep the controller alive forever, instead of shutting down.
	return nil
}

func (h *HealthSyncer) getCluster() (*v3.Cluster, error) {
	return h.clusterLister.Get("", h.clusterName)
}

func convertToClusterComponentStatus(cs *v1.ComponentStatus) *v32.ClusterComponentStatus {
	return &v32.ClusterComponentStatus{
		Name:       cs.Name,
		Conditions: cs.Conditions,
	}
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
)

// TODO Comment it to make it understandable
// Mention the spec at https://github.com/composer/satis/blob/master/res/satis-schema.json
// and why we don't implement it here (we are running repositories code only)

// Satis reflects the a Satis configuration file.
type Satis struct {
	// config is the configuration provider object that has read the satis configuration file
	config Provider
	// List of repositories
	repositories map[string]SatisRepository
}

// SatisRepository reflects a single repository entry in satis `repositories` section
type SatisRepository struct {
	// Type is the repository type, like `git` or `svn`
	Type string `json:"type"`
	// URL is the URL of the repository that contains packages
	URL string `json:"url"`
}

// NewSatis will create a new satis configuration object.
// If no configuration is given, an error will be returned.
func NewSatis(c Provider) (*Satis, error) {
	if c == nil {
		return nil, errors.New("No conifguration provider applied")
	}

	// Read initial repositories
	repositories := []SatisRepository{}
	if v := c.Get("repositories").(*json.RawMessage); v != nil {
		err := json.Unmarshal(*v, &repositories)
		if err != nil {
			return nil, err
		}
	}

	// Deduplicate the repositories
	m := map[string]SatisRepository{}
	for _, v := range repositories {
		m[v.URL] = v
	}

	s := &Satis{
		config:       c,
		repositories: m,
	}
	return s, nil
}

func (s *Satis) AddRepository(u string) {
	r := SatisRepository{
		Type: "git",
		URL:  u,
	}

	s.repositories[r.URL] = r
}

func (s *Satis) AddRepositories(u ...string) {
	for _, r := range u {
		s.AddRepository(r)
	}
}

func (s *Satis) WriteFile(filename string, perm os.FileMode) error {
	contentMap := s.config.GetContentMap()
	m := make(map[string]*json.RawMessage, len(contentMap))
	for k, v := range contentMap {
		t := v.(json.RawMessage)
		m[k] = &t
	}

	repositories := s.GetRepositoriesAsSlice()
	rawRepositories, err := json.MarshalIndent(&repositories, "", "    ")
	if err != nil {
		return err
	}

	jsonRepositories := json.RawMessage(rawRepositories)
	m["repositories"] = &jsonRepositories

	b, err := json.MarshalIndent(&m, "", "    ")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filename, b, perm)
}

func (s *Satis) GetRepositoriesAsSlice() []SatisRepository {
	c := make([]SatisRepository, 0, len(s.repositories))
	for _, value := range s.repositories {
		c = append(c, value)
	}

	return c
}
<commit_msg>Add comment about viper PR to write a file<commit_after>package config

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
)

// TODO Comment it to make it understandable
// Mention the spec at https://github.com/composer/satis/blob/master/res/satis-schema.json
// and why we don't implement it here (we are running repositories code only)

// Satis reflects the a Satis configuration file.
type Satis struct {
	// config is the configuration provider object that has read the satis configuration file
	config Provider
	// List of repositories
	repositories map[string]SatisRepository
}

// SatisRepository reflects a single repository entry in satis `repositories` section
type SatisRepository struct {
	// Type is the repository type, like `git` or `svn`
	Type string `json:"type"`
	// URL is the URL of the repository that contains packages
	URL string `json:"url"`
}

// NewSatis will create a new satis configuration object.
// If no configuration is given, an error will be returned.
func NewSatis(c Provider) (*Satis, error) {
	if c == nil {
		return nil, errors.New("No conifguration provider applied")
	}

	// Read initial repositories
	repositories := []SatisRepository{}
	if v := c.Get("repositories").(*json.RawMessage); v != nil {
		err := json.Unmarshal(*v, &repositories)
		if err != nil {
			return nil, err
		}
	}

	// Deduplicate the repositories
	m := map[string]SatisRepository{}
	for _, v := range repositories {
		m[v.URL] = v
	}

	s := &Satis{
		config:       c,
		repositories: m,
	}
	return s, nil
}

func (s *Satis) AddRepository(u string) {
	r := SatisRepository{
		Type: "git",
		URL:  u,
	}

	s.repositories[r.URL] = r
}

func (s *Satis) AddRepositories(u ...string) {
	for _, r := range u {
		s.AddRepository(r)
	}
}

func (s *Satis) WriteFile(filename string, perm os.FileMode) error {

	// We maintain the Satis configuration file on our own.
	// This is not managed by viper.
	// Maybe it make sense to switch this in feature.
	// Viper is not able to write configuration files (yet).
	// A PR is available for this. See https://github.com/spf13/viper/pull/287

	contentMap := s.config.GetContentMap()
	m := make(map[string]*json.RawMessage, len(contentMap))
	for k, v := range contentMap {
		t := v.(json.RawMessage)
		m[k] = &t
	}

	repositories := s.GetRepositoriesAsSlice()
	rawRepositories, err := json.MarshalIndent(&repositories, "", "    ")
	if err != nil {
		return err
	}

	jsonRepositories := json.RawMessage(rawRepositories)
	m["repositories"] = &jsonRepositories

	b, err := json.MarshalIndent(&m, "", "    ")
	if err != nil {
		return err
	}

	return ioutil.WriteFile(filename, b, perm)
}

func (s *Satis) GetRepositoriesAsSlice() []SatisRepository {
	c := make([]SatisRepository, 0, len(s.repositories))
	for _, value := range s.repositories {
		c = append(c, value)
	}

	return c
}
<|endoftext|>


<commit_before>package aws

import (
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_instance_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)
	delete(rs.Attributes, "source_dest_check")

	// Figure out user data
	userData := ""
	if attr, ok := d.Attributes["user_data"]; ok {
		userData = attr.NewExtra.(string)
	}

	// Build the creation struct
	runOpts := &ec2.RunInstances{
		ImageId:      rs.Attributes["ami"],
		InstanceType: rs.Attributes["instance_type"],
		KeyName:      rs.Attributes["key_name"],
		SubnetId:     rs.Attributes["subnet_id"],
		UserData:     []byte(userData),
	}
	if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				var g ec2.SecurityGroup
				if runOpts.SubnetId != "" {
					g.Id = str
				} else {
					g.Name = str
				}

				runOpts.SecurityGroups = append(runOpts.SecurityGroups, g)
			}
		}
	}

	// Create the instance
	log.Printf("[DEBUG] Run configuration: %#v", runOpts)
	runResp, err := ec2conn.RunInstances(runOpts)
	if err != nil {
		return nil, fmt.Errorf("Error launching source instance: %s", err)
	}

	instance := &runResp.Instances[0]
	log.Printf("[INFO] Instance ID: %s", instance.InstanceId)

	// Store the resulting ID so we can look this up later
	rs.ID = instance.InstanceId

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		instance.InstanceId)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending"},
		Target:     "running",
		Refresh:    InstanceStateRefreshFunc(ec2conn, instance.InstanceId),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	instanceRaw, err := stateConf.WaitForState()

	if err != nil {
		return rs, fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			instance.InstanceId, err)
	}

	instance = instanceRaw.(*ec2.Instance)

	// Initialize the connection info
	rs.ConnInfo["type"] = "ssh"
	rs.ConnInfo["host"] = instance.PublicIpAddress

	// Set our attributes
	rs, err = resource_aws_instance_update_state(rs, instance)
	if err != nil {
		return rs, err
	}

	// Update if we need to
	return resource_aws_instance_update(rs, d, meta)
}

func resource_aws_instance_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn
	rs := s.MergeDiff(d)

	modify := false
	opts := new(ec2.ModifyInstance)

	if attr, ok := d.Attributes["source_dest_check"]; ok {
		modify = true
		opts.SourceDestCheck = attr.New != "" && attr.New != "false"
		opts.SetSourceDestCheck = true
		rs.Attributes["source_dest_check"] = strconv.FormatBool(
			opts.SourceDestCheck)
	}

	if modify {
		log.Printf("[INFO] Modifing instance %s: %#v", s.ID, opts)
		if _, err := ec2conn.ModifyInstance(s.ID, opts); err != nil {
			return s, err
		}

		// TODO(mitchellh): wait for the attributes we modified to
		// persist the change...
	}

	return rs, nil
}

func resource_aws_instance_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[INFO] Terminating instance: %s", s.ID)
	if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil {
		return fmt.Errorf("Error terminating instance: %s", err)
	}

	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become terminated",
		s.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending", "running", "shutting-down", "stopped", "stopping"},
		Target:     "terminated",
		Refresh:    InstanceStateRefreshFunc(ec2conn, s.ID),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err := stateConf.WaitForState()

	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to terminate: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_instance_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"ami":               diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"instance_type":     diff.AttrTypeCreate,
			"key_name":          diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate,
			"subnet_id":         diff.AttrTypeCreate,
			"source_dest_check": diff.AttrTypeUpdate,
			"user_data":         diff.AttrTypeCreate,
		},

		ComputedAttrs: []string{
			"availability_zone",
			"key_name",
			"public_dns",
			"public_ip",
			"private_dns",
			"private_ip",
			"security_groups",
			"subnet_id",
		},

		PreProcess: map[string]diff.PreProcessFunc{
			"user_data": func(v string) string {
				hash := sha1.Sum([]byte(v))
				return hex.EncodeToString(hash[:])
			},
		},
	}

	return b.Diff(s, c)
}

func resource_aws_instance_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter())
	if err != nil {
		// If the instance was not found, return nil so that we can show
		// that the instance is gone.
		if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
			return nil, nil
		}

		// Some other error, report it
		return s, err
	}

	// If nothing was found, then return no state
	if len(resp.Reservations) == 0 {
		return nil, nil
	}

	instance := &resp.Reservations[0].Instances[0]

	// If the instance is terminated, then it is gone
	if instance.State.Name == "terminated" {
		return nil, nil
	}

	return resource_aws_instance_update_state(s, instance)
}

func resource_aws_instance_update_state(
	s *terraform.ResourceState,
	instance *ec2.Instance) (*terraform.ResourceState, error) {
	s.Attributes["availability_zone"] = instance.AvailZone
	s.Attributes["key_name"] = instance.KeyName
	s.Attributes["public_dns"] = instance.DNSName
	s.Attributes["public_ip"] = instance.PublicIpAddress
	s.Attributes["private_dns"] = instance.PrivateDNSName
	s.Attributes["private_ip"] = instance.PrivateIpAddress
	s.Attributes["subnet_id"] = instance.SubnetId
	s.Dependencies = nil

	// Extract the existing security groups
	useID := false
	if raw := flatmap.Expand(s.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				if strings.Contains(str, "sg-") {
					useID = true
					break
				}
			}
		}
	}

	// Build up the security groups
	sgs := make([]string, len(instance.SecurityGroups))
	for i, sg := range instance.SecurityGroups {
		if instance.SubnetId != "" && useID {
			sgs[i] = sg.Id
		} else {
			sgs[i] = sg.Name
		}

		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: sg.Id},
		)
	}
	flatmap.Map(s.Attributes).Merge(flatmap.Flatten(map[string]interface{}{
		"security_groups": sgs,
	}))

	if instance.SubnetId != "" {
		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: instance.SubnetId},
		)
	}

	return s, nil
}

// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an EC2 instance.
func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
				// Set this to nil as if we didn't find anything.
				resp = nil
			} else {
				log.Printf("Error on InstanceStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		i := &resp.Reservations[0].Instances[0]
		return i, i.State.Name, nil
	}
}
<commit_msg>provider/aws: More strict check<commit_after>package aws

import (
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/ec2"
)

func resource_aws_instance_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)
	delete(rs.Attributes, "source_dest_check")

	// Figure out user data
	userData := ""
	if attr, ok := d.Attributes["user_data"]; ok {
		userData = attr.NewExtra.(string)
	}

	// Build the creation struct
	runOpts := &ec2.RunInstances{
		ImageId:      rs.Attributes["ami"],
		InstanceType: rs.Attributes["instance_type"],
		KeyName:      rs.Attributes["key_name"],
		SubnetId:     rs.Attributes["subnet_id"],
		UserData:     []byte(userData),
	}
	if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				var g ec2.SecurityGroup
				if runOpts.SubnetId != "" {
					g.Id = str
				} else {
					g.Name = str
				}

				runOpts.SecurityGroups = append(runOpts.SecurityGroups, g)
			}
		}
	}

	// Create the instance
	log.Printf("[DEBUG] Run configuration: %#v", runOpts)
	runResp, err := ec2conn.RunInstances(runOpts)
	if err != nil {
		return nil, fmt.Errorf("Error launching source instance: %s", err)
	}

	instance := &runResp.Instances[0]
	log.Printf("[INFO] Instance ID: %s", instance.InstanceId)

	// Store the resulting ID so we can look this up later
	rs.ID = instance.InstanceId

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		instance.InstanceId)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending"},
		Target:     "running",
		Refresh:    InstanceStateRefreshFunc(ec2conn, instance.InstanceId),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	instanceRaw, err := stateConf.WaitForState()

	if err != nil {
		return rs, fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			instance.InstanceId, err)
	}

	instance = instanceRaw.(*ec2.Instance)

	// Initialize the connection info
	rs.ConnInfo["type"] = "ssh"
	rs.ConnInfo["host"] = instance.PublicIpAddress

	// Set our attributes
	rs, err = resource_aws_instance_update_state(rs, instance)
	if err != nil {
		return rs, err
	}

	// Update if we need to
	return resource_aws_instance_update(rs, d, meta)
}

func resource_aws_instance_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn
	rs := s.MergeDiff(d)

	modify := false
	opts := new(ec2.ModifyInstance)

	if attr, ok := d.Attributes["source_dest_check"]; ok {
		modify = true
		opts.SourceDestCheck = attr.New != "" && attr.New != "false"
		opts.SetSourceDestCheck = true
		rs.Attributes["source_dest_check"] = strconv.FormatBool(
			opts.SourceDestCheck)
	}

	if modify {
		log.Printf("[INFO] Modifing instance %s: %#v", s.ID, opts)
		if _, err := ec2conn.ModifyInstance(s.ID, opts); err != nil {
			return s, err
		}

		// TODO(mitchellh): wait for the attributes we modified to
		// persist the change...
	}

	return rs, nil
}

func resource_aws_instance_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	log.Printf("[INFO] Terminating instance: %s", s.ID)
	if _, err := ec2conn.TerminateInstances([]string{s.ID}); err != nil {
		return fmt.Errorf("Error terminating instance: %s", err)
	}

	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become terminated",
		s.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"pending", "running", "shutting-down", "stopped", "stopping"},
		Target:     "terminated",
		Refresh:    InstanceStateRefreshFunc(ec2conn, s.ID),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err := stateConf.WaitForState()

	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to terminate: %s",
			s.ID, err)
	}

	return nil
}

func resource_aws_instance_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {
	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"ami":               diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"instance_type":     diff.AttrTypeCreate,
			"key_name":          diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate,
			"subnet_id":         diff.AttrTypeCreate,
			"source_dest_check": diff.AttrTypeUpdate,
			"user_data":         diff.AttrTypeCreate,
		},

		ComputedAttrs: []string{
			"availability_zone",
			"key_name",
			"public_dns",
			"public_ip",
			"private_dns",
			"private_ip",
			"security_groups",
			"subnet_id",
		},

		PreProcess: map[string]diff.PreProcessFunc{
			"user_data": func(v string) string {
				hash := sha1.Sum([]byte(v))
				return hex.EncodeToString(hash[:])
			},
		},
	}

	return b.Diff(s, c)
}

func resource_aws_instance_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	ec2conn := p.ec2conn

	resp, err := ec2conn.Instances([]string{s.ID}, ec2.NewFilter())
	if err != nil {
		// If the instance was not found, return nil so that we can show
		// that the instance is gone.
		if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
			return nil, nil
		}

		// Some other error, report it
		return s, err
	}

	// If nothing was found, then return no state
	if len(resp.Reservations) == 0 {
		return nil, nil
	}

	instance := &resp.Reservations[0].Instances[0]

	// If the instance is terminated, then it is gone
	if instance.State.Name == "terminated" {
		return nil, nil
	}

	return resource_aws_instance_update_state(s, instance)
}

func resource_aws_instance_update_state(
	s *terraform.ResourceState,
	instance *ec2.Instance) (*terraform.ResourceState, error) {
	s.Attributes["availability_zone"] = instance.AvailZone
	s.Attributes["key_name"] = instance.KeyName
	s.Attributes["public_dns"] = instance.DNSName
	s.Attributes["public_ip"] = instance.PublicIpAddress
	s.Attributes["private_dns"] = instance.PrivateDNSName
	s.Attributes["private_ip"] = instance.PrivateIpAddress
	s.Attributes["subnet_id"] = instance.SubnetId
	s.Dependencies = nil

	// Extract the existing security groups
	useID := false
	if raw := flatmap.Expand(s.Attributes, "security_groups"); raw != nil {
		if sgs, ok := raw.([]interface{}); ok {
			for _, sg := range sgs {
				str, ok := sg.(string)
				if !ok {
					continue
				}

				if strings.HasPrefix(str, "sg-") {
					useID = true
					break
				}
			}
		}
	}

	// Build up the security groups
	sgs := make([]string, len(instance.SecurityGroups))
	for i, sg := range instance.SecurityGroups {
		if instance.SubnetId != "" && useID {
			sgs[i] = sg.Id
		} else {
			sgs[i] = sg.Name
		}

		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: sg.Id},
		)
	}
	flatmap.Map(s.Attributes).Merge(flatmap.Flatten(map[string]interface{}{
		"security_groups": sgs,
	}))

	if instance.SubnetId != "" {
		s.Dependencies = append(s.Dependencies,
			terraform.ResourceDependency{ID: instance.SubnetId},
		)
	}

	return s, nil
}

// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an EC2 instance.
func InstanceStateRefreshFunc(conn *ec2.EC2, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.Instances([]string{instanceID}, ec2.NewFilter())
		if err != nil {
			if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidInstanceID.NotFound" {
				// Set this to nil as if we didn't find anything.
				resp = nil
			} else {
				log.Printf("Error on InstanceStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil || len(resp.Reservations) == 0 || len(resp.Reservations[0].Instances) == 0 {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		i := &resp.Reservations[0].Instances[0]
		return i, i.State.Name, nil
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2018-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/btcsuite/btcd/wire"
)

var (
	// manyInputsBenchTx is a transaction that contains a lot of inputs which is
	// useful for benchmarking signature hash calculation.
	manyInputsBenchTx wire.MsgTx

	// A mock previous output script to use in the signing benchmark.
	prevOutScript = hexToBytes("a914f5916158e3e2c4551c1796708db8367207ed13bb87")
)

func init() {
	// tx 620f57c92cf05a7f7e7f7d28255d5f7089437bc48e34dcfebf7751d08b7fb8f5
	txHex, err := ioutil.ReadFile("data/many_inputs_tx.hex")
	if err != nil {
		panic(fmt.Sprintf("unable to read benchmark tx file: %v", err))
	}

	txBytes := hexToBytes(string(txHex))
	err = manyInputsBenchTx.Deserialize(bytes.NewReader(txBytes))
	if err != nil {
		panic(err)
	}
}

// BenchmarkCalcSigHash benchmarks how long it takes to calculate the signature
// hashes for all inputs of a transaction with many inputs.
func BenchmarkCalcSigHash(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for j := 0; j < len(manyInputsBenchTx.TxIn); j++ {
			_, err := CalcSignatureHash(prevOutScript, SigHashAll,
				&manyInputsBenchTx, j)
			if err != nil {
				b.Fatalf("failed to calc signature hash: %v", err)
			}
		}
	}
}

// BenchmarkCalcWitnessSigHash benchmarks how long it takes to calculate the
// witness signature hashes for all inputs of a transaction with many inputs.
func BenchmarkCalcWitnessSigHash(b *testing.B) {
	sigHashes := NewTxSigHashes(&manyInputsBenchTx)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for j := 0; j < len(manyInputsBenchTx.TxIn); j++ {
			_, err := CalcWitnessSigHash(
				prevOutScript, sigHashes, SigHashAll,
				&manyInputsBenchTx, j, 5,
			)
			if err != nil {
				b.Fatalf("failed to calc signature hash: %v", err)
			}
		}
	}
}

// genComplexScript returns a script comprised of half as many opcodes as the
// maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
func genComplexScript() ([]byte, error) {
	var scriptLen int
	builder := NewScriptBuilder()
	for i := 0; i < MaxOpsPerScript/2; i++ {
		builder.AddOp(OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, MaxScriptElementSize)
	for i := 0; i < (MaxScriptSize-scriptLen)/(MaxScriptElementSize+3); i++ {
		builder.AddData(maxData)
	}
	return builder.Script()
}

// BenchmarkScriptParsing benchmarks how long it takes to parse a very large
// script.
func BenchmarkScriptParsing(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	const scriptVersion = 0
	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		tokenizer := MakeScriptTokenizer(scriptVersion, script)
		for tokenizer.Next() {
			_ = tokenizer.Opcode()
			_ = tokenizer.Data()
			_ = tokenizer.ByteIndex()
		}
		if err := tokenizer.Err(); err != nil {
			b.Fatalf("failed to parse script: %v", err)
		}
	}
}

// BenchmarkDisasmString benchmarks how long it takes to disassemble a very
// large script.
func BenchmarkDisasmString(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_, err := DisasmString(script)
		if err != nil {
			b.Fatalf("failed to disasm script: %v", err)
		}
	}
}

// BenchmarkIsPubKeyScript benchmarks how long it takes to analyze a very large
// script to determine if it is a standard pay-to-pubkey script.
func BenchmarkIsPubKeyScript(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPayToPubKey(script)
	}
}

// BenchmarkIsPubKeyHashScript benchmarks how long it takes to analyze a very
// large script to determine if it is a standard pay-to-pubkey-hash script.
func BenchmarkIsPubKeyHashScript(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPayToPubKeyHash(script)
	}
}

// BenchmarkIsPayToScriptHash benchmarks how long it takes IsPayToScriptHash to
// analyze a very large script.
func BenchmarkIsPayToScriptHash(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPayToScriptHash(script)
	}
}

// BenchmarkIsMultisigScriptLarge benchmarks how long it takes IsMultisigScript
// to analyze a very large script.
func BenchmarkIsMultisigScriptLarge(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		isMultisig, err := IsMultisigScript(script)
		if err != nil {
			b.Fatalf("unexpected err: %v", err)
		}
		if isMultisig {
			b.Fatalf("script should NOT be reported as mutisig script")
		}
	}
}

// BenchmarkIsMultisigScript benchmarks how long it takes IsMultisigScript to
// analyze a 1-of-2 multisig public key script.
func BenchmarkIsMultisigScript(b *testing.B) {
	multisigShortForm := "1 " +
		"DATA_33 " +
		"0x030478aaaa2be30772f1e69e581610f1840b3cf2fe7228ee0281cd599e5746f81e " +
		"DATA_33 " +
		"0x0284f4d078b236a9ff91661f8ffbe012737cd3507566f30fd97d25f2b23539f3cd " +
		"2 CHECKMULTISIG"
	pkScript := mustParseShortForm(multisigShortForm)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		isMultisig, err := IsMultisigScript(pkScript)
		if err != nil {
			b.Fatalf("unexpected err: %v", err)
		}
		if !isMultisig {
			b.Fatalf("script should be reported as a mutisig script")
		}
	}
}

// BenchmarkIsMultisigSigScript benchmarks how long it takes IsMultisigSigScript
// to analyze a very large script.
func BenchmarkIsMultisigSigScriptLarge(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		if IsMultisigSigScript(script) {
			b.Fatalf("script should NOT be reported as mutisig sig script")
		}
	}
}

// BenchmarkIsMultisigSigScript benchmarks how long it takes IsMultisigSigScript
// to analyze both a 1-of-2 multisig public key script (which should be false)
// and a signature script comprised of a pay-to-script-hash 1-of-2 multisig
// redeem script (which should be true).
func BenchmarkIsMultisigSigScript(b *testing.B) {
	multisigShortForm := "1 " +
		"DATA_33 " +
		"0x030478aaaa2be30772f1e69e581610f1840b3cf2fe7228ee0281cd599e5746f81e " +
		"DATA_33 " +
		"0x0284f4d078b236a9ff91661f8ffbe012737cd3507566f30fd97d25f2b23539f3cd " +
		"2 CHECKMULTISIG"
	pkScript := mustParseShortForm(multisigShortForm)

	sigHex := "0x304402205795c3ab6ba11331eeac757bf1fc9c34bef0c7e1a9c8bd5eebb8" +
		"82f3b79c5838022001e0ab7b4c7662e4522dc5fa479e4b4133fa88c6a53d895dc1d5" +
		"2eddc7bbcf2801 "
	sigScript := mustParseShortForm("DATA_71 " + sigHex + "DATA_71 " +
		multisigShortForm)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		if IsMultisigSigScript(pkScript) {
			b.Fatalf("script should NOT be reported as mutisig sig script")
		}
		if !IsMultisigSigScript(sigScript) {
			b.Fatalf("script should be reported as a mutisig sig script")
		}
	}
}

// BenchmarkIsPushOnlyScript benchmarks how long it takes IsPushOnlyScript to
// analyze a very large script.
func BenchmarkIsPushOnlyScript(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPushOnlyScript(script)
	}
}
<commit_msg>txscript: Add benchmark IsPayToWitnessPubkeyHash<commit_after>// Copyright (c) 2018-2019 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"testing"

	"github.com/btcsuite/btcd/wire"
)

var (
	// manyInputsBenchTx is a transaction that contains a lot of inputs which is
	// useful for benchmarking signature hash calculation.
	manyInputsBenchTx wire.MsgTx

	// A mock previous output script to use in the signing benchmark.
	prevOutScript = hexToBytes("a914f5916158e3e2c4551c1796708db8367207ed13bb87")
)

func init() {
	// tx 620f57c92cf05a7f7e7f7d28255d5f7089437bc48e34dcfebf7751d08b7fb8f5
	txHex, err := ioutil.ReadFile("data/many_inputs_tx.hex")
	if err != nil {
		panic(fmt.Sprintf("unable to read benchmark tx file: %v", err))
	}

	txBytes := hexToBytes(string(txHex))
	err = manyInputsBenchTx.Deserialize(bytes.NewReader(txBytes))
	if err != nil {
		panic(err)
	}
}

// BenchmarkCalcSigHash benchmarks how long it takes to calculate the signature
// hashes for all inputs of a transaction with many inputs.
func BenchmarkCalcSigHash(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for j := 0; j < len(manyInputsBenchTx.TxIn); j++ {
			_, err := CalcSignatureHash(prevOutScript, SigHashAll,
				&manyInputsBenchTx, j)
			if err != nil {
				b.Fatalf("failed to calc signature hash: %v", err)
			}
		}
	}
}

// BenchmarkCalcWitnessSigHash benchmarks how long it takes to calculate the
// witness signature hashes for all inputs of a transaction with many inputs.
func BenchmarkCalcWitnessSigHash(b *testing.B) {
	sigHashes := NewTxSigHashes(&manyInputsBenchTx)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		for j := 0; j < len(manyInputsBenchTx.TxIn); j++ {
			_, err := CalcWitnessSigHash(
				prevOutScript, sigHashes, SigHashAll,
				&manyInputsBenchTx, j, 5,
			)
			if err != nil {
				b.Fatalf("failed to calc signature hash: %v", err)
			}
		}
	}
}

// genComplexScript returns a script comprised of half as many opcodes as the
// maximum allowed followed by as many max size data pushes fit without
// exceeding the max allowed script size.
func genComplexScript() ([]byte, error) {
	var scriptLen int
	builder := NewScriptBuilder()
	for i := 0; i < MaxOpsPerScript/2; i++ {
		builder.AddOp(OP_TRUE)
		scriptLen++
	}
	maxData := bytes.Repeat([]byte{0x02}, MaxScriptElementSize)
	for i := 0; i < (MaxScriptSize-scriptLen)/(MaxScriptElementSize+3); i++ {
		builder.AddData(maxData)
	}
	return builder.Script()
}

// BenchmarkScriptParsing benchmarks how long it takes to parse a very large
// script.
func BenchmarkScriptParsing(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	const scriptVersion = 0
	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		tokenizer := MakeScriptTokenizer(scriptVersion, script)
		for tokenizer.Next() {
			_ = tokenizer.Opcode()
			_ = tokenizer.Data()
			_ = tokenizer.ByteIndex()
		}
		if err := tokenizer.Err(); err != nil {
			b.Fatalf("failed to parse script: %v", err)
		}
	}
}

// BenchmarkDisasmString benchmarks how long it takes to disassemble a very
// large script.
func BenchmarkDisasmString(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_, err := DisasmString(script)
		if err != nil {
			b.Fatalf("failed to disasm script: %v", err)
		}
	}
}

// BenchmarkIsPubKeyScript benchmarks how long it takes to analyze a very large
// script to determine if it is a standard pay-to-pubkey script.
func BenchmarkIsPubKeyScript(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPayToPubKey(script)
	}
}

// BenchmarkIsPubKeyHashScript benchmarks how long it takes to analyze a very
// large script to determine if it is a standard pay-to-pubkey-hash script.
func BenchmarkIsPubKeyHashScript(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPayToPubKeyHash(script)
	}
}

// BenchmarkIsPayToScriptHash benchmarks how long it takes IsPayToScriptHash to
// analyze a very large script.
func BenchmarkIsPayToScriptHash(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPayToScriptHash(script)
	}
}

// BenchmarkIsMultisigScriptLarge benchmarks how long it takes IsMultisigScript
// to analyze a very large script.
func BenchmarkIsMultisigScriptLarge(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		isMultisig, err := IsMultisigScript(script)
		if err != nil {
			b.Fatalf("unexpected err: %v", err)
		}
		if isMultisig {
			b.Fatalf("script should NOT be reported as mutisig script")
		}
	}
}

// BenchmarkIsMultisigScript benchmarks how long it takes IsMultisigScript to
// analyze a 1-of-2 multisig public key script.
func BenchmarkIsMultisigScript(b *testing.B) {
	multisigShortForm := "1 " +
		"DATA_33 " +
		"0x030478aaaa2be30772f1e69e581610f1840b3cf2fe7228ee0281cd599e5746f81e " +
		"DATA_33 " +
		"0x0284f4d078b236a9ff91661f8ffbe012737cd3507566f30fd97d25f2b23539f3cd " +
		"2 CHECKMULTISIG"
	pkScript := mustParseShortForm(multisigShortForm)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		isMultisig, err := IsMultisigScript(pkScript)
		if err != nil {
			b.Fatalf("unexpected err: %v", err)
		}
		if !isMultisig {
			b.Fatalf("script should be reported as a mutisig script")
		}
	}
}

// BenchmarkIsMultisigSigScript benchmarks how long it takes IsMultisigSigScript
// to analyze a very large script.
func BenchmarkIsMultisigSigScriptLarge(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		if IsMultisigSigScript(script) {
			b.Fatalf("script should NOT be reported as mutisig sig script")
		}
	}
}

// BenchmarkIsMultisigSigScript benchmarks how long it takes IsMultisigSigScript
// to analyze both a 1-of-2 multisig public key script (which should be false)
// and a signature script comprised of a pay-to-script-hash 1-of-2 multisig
// redeem script (which should be true).
func BenchmarkIsMultisigSigScript(b *testing.B) {
	multisigShortForm := "1 " +
		"DATA_33 " +
		"0x030478aaaa2be30772f1e69e581610f1840b3cf2fe7228ee0281cd599e5746f81e " +
		"DATA_33 " +
		"0x0284f4d078b236a9ff91661f8ffbe012737cd3507566f30fd97d25f2b23539f3cd " +
		"2 CHECKMULTISIG"
	pkScript := mustParseShortForm(multisigShortForm)

	sigHex := "0x304402205795c3ab6ba11331eeac757bf1fc9c34bef0c7e1a9c8bd5eebb8" +
		"82f3b79c5838022001e0ab7b4c7662e4522dc5fa479e4b4133fa88c6a53d895dc1d5" +
		"2eddc7bbcf2801 "
	sigScript := mustParseShortForm("DATA_71 " + sigHex + "DATA_71 " +
		multisigShortForm)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		if IsMultisigSigScript(pkScript) {
			b.Fatalf("script should NOT be reported as mutisig sig script")
		}
		if !IsMultisigSigScript(sigScript) {
			b.Fatalf("script should be reported as a mutisig sig script")
		}
	}
}

// BenchmarkIsPushOnlyScript benchmarks how long it takes IsPushOnlyScript to
// analyze a very large script.
func BenchmarkIsPushOnlyScript(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPushOnlyScript(script)
	}
}

// BenchmarkIsWitnessPubKeyHash benchmarks how long it takes to analyze a very
// large script to determine if it is a standard witness pubkey hash script.
func BenchmarkIsWitnessPubKeyHash(b *testing.B) {
	script, err := genComplexScript()
	if err != nil {
		b.Fatalf("failed to create benchmark script: %v", err)
	}

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		_ = IsPayToWitnessPubKeyHash(script)
	}
}
<|endoftext|>