<commit_before>/*
Copyright 2018 Google LLC

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 executor

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/GoogleContainerTools/kaniko/pkg/cache"
	"github.com/GoogleContainerTools/kaniko/pkg/config"
	"github.com/GoogleContainerTools/kaniko/pkg/constants"
	"github.com/GoogleContainerTools/kaniko/pkg/creds"
	"github.com/GoogleContainerTools/kaniko/pkg/timing"
	"github.com/GoogleContainerTools/kaniko/pkg/version"
	"github.com/google/go-containerregistry/pkg/name"
	v1 "github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/empty"
	"github.com/google/go-containerregistry/pkg/v1/layout"
	"github.com/google/go-containerregistry/pkg/v1/mutate"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"github.com/google/go-containerregistry/pkg/v1/tarball"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/afero"
)

type withUserAgent struct {
	t http.RoundTripper
}

const (
	UpstreamClientUaKey = "UPSTREAM_CLIENT_TYPE"
)

func (w *withUserAgent) RoundTrip(r *http.Request) (*http.Response, error) {
	ua := []string{fmt.Sprintf("kaniko/%s", version.Version())}
	if upstream := os.Getenv(UpstreamClientUaKey); upstream != "" {
		ua = append(ua, upstream)
	}
	r.Header.Set("User-Agent", strings.Join(ua, ","))
	return w.t.RoundTrip(r)
}

type CertPool interface {
	value() *x509.CertPool
	append(path string) error
}

type X509CertPool struct {
	inner x509.CertPool
}

func (p *X509CertPool) value() *x509.CertPool {
	return &p.inner
}

func (p *X509CertPool) append(path string) error {
	pem, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	p.inner.AppendCertsFromPEM(pem)
	return nil
}

type systemCertLoader func() CertPool

var defaultX509Handler systemCertLoader = func() CertPool {
	systemCertPool, err := x509.SystemCertPool()
	if err != nil {
		logrus.Warn("Failed to load system cert pool. Loading empty one instead.")
		systemCertPool = x509.NewCertPool()
	}
	return &X509CertPool{
		inner: *systemCertPool,
	}
}

// CheckPushPermissions checks that the configured credentials can be used to
// push to every specified destination.
func CheckPushPermissions(opts *config.KanikoOptions) error {
	if opts.NoPush {
		return nil
	}

	checked := map[string]bool{}
	for _, destination := range opts.Destinations {
		destRef, err := name.NewTag(destination, name.WeakValidation)
		if err != nil {
			return errors.Wrap(err, "getting tag for destination")
		}
		if checked[destRef.Context().RepositoryStr()] {
			continue
		}
		if strings.Contains(destRef.RegistryStr(), "gcr.io") {
			if _, err := os.Stat("/kaniko/.docker/config.json"); os.IsNotExist(err) {
				cmd := exec.Command("docker-credential-gcr", "configure-docker")
				if err := cmd.Run(); err != nil {
					return errors.Wrap(err, "error while configuring docker-credential-gcr helper")
				}
			}

		}
		registryName := destRef.Repository.Registry.Name()
		if opts.Insecure || opts.InsecureRegistries.Contains(registryName) {
			newReg, err := name.NewRegistry(registryName, name.WeakValidation, name.Insecure)
			if err != nil {
				return errors.Wrap(err, "getting new insecure registry")
			}
			destRef.Repository.Registry = newReg
		}
		tr := makeTransport(opts, registryName, defaultX509Handler)
		if err := remote.CheckPushPermission(destRef, creds.GetKeychain(), tr); err != nil {
			return errors.Wrapf(err, "checking push permission for %q", destRef)
		}
		checked[destRef.Context().RepositoryStr()] = true
	}
	return nil
}

func getDigest(image v1.Image) ([]byte, error) {
	digest, err := image.Digest()
	if err != nil {
		return nil, err
	}
	return []byte(digest.String()), nil
}

// DoPush is responsible for pushing image to the destinations specified in opts
func DoPush(image v1.Image, opts *config.KanikoOptions) error {
	t := timing.Start("Total Push Time")
	var digestByteArray []byte
	var builder strings.Builder
	if opts.DigestFile != "" || opts.ImageNameDigestFile != "" {
		var err error
		digestByteArray, err = getDigest(image)
		if err != nil {
			return errors.Wrap(err, "error fetching digest")
		}
	}

	if opts.DigestFile != "" {
		err := ioutil.WriteFile(opts.DigestFile, digestByteArray, 0644)
		if err != nil {
			return errors.Wrap(err, "writing digest to file failed")
		}
	}

	if opts.OCILayoutPath != "" {
		path, err := layout.Write(opts.OCILayoutPath, empty.Index)
		if err != nil {
			return errors.Wrap(err, "writing empty layout")
		}
		if err := path.AppendImage(image); err != nil {
			return errors.Wrap(err, "appending image")
		}
	}

	destRefs := []name.Tag{}
	for _, destination := range opts.Destinations {
		destRef, err := name.NewTag(destination, name.WeakValidation)
		if err != nil {
			return errors.Wrap(err, "getting tag for destination")
		}
		if opts.ImageNameDigestFile != "" {
			imageName := []byte(destRef.Repository.Name() + "@")
			builder.Write(append(imageName, digestByteArray...))
			builder.WriteString("\n")
		}
		destRefs = append(destRefs, destRef)
	}

	if opts.ImageNameDigestFile != "" {
		err := ioutil.WriteFile(opts.ImageNameDigestFile, []byte(builder.String()), 0644)
		if err != nil {
			return errors.Wrap(err, "writing image name with digest to file failed")
		}
	}

	if opts.TarPath != "" {
		tagToImage := map[name.Tag]v1.Image{}
		for _, destRef := range destRefs {
			tagToImage[destRef] = image
		}
		return tarball.MultiWriteToFile(opts.TarPath, tagToImage)
	}

	if opts.NoPush {
		logrus.Info("Skipping push to container registry due to --no-push flag")
		return nil
	}

	// continue pushing unless an error occurs
	for _, destRef := range destRefs {
		registryName := destRef.Repository.Registry.Name()
		if opts.Insecure || opts.InsecureRegistries.Contains(registryName) {
			newReg, err := name.NewRegistry(registryName, name.WeakValidation, name.Insecure)
			if err != nil {
				return errors.Wrap(err, "getting new insecure registry")
			}
			destRef.Repository.Registry = newReg
		}

		pushAuth, err := creds.GetKeychain().Resolve(destRef.Context().Registry)
		if err != nil {
			return errors.Wrap(err, "resolving pushAuth")
		}

		tr := makeTransport(opts, registryName, defaultX509Handler)
		rt := &withUserAgent{t: tr}

		if err := remote.Write(destRef, image, remote.WithAuth(pushAuth), remote.WithTransport(rt)); err != nil {
			return errors.Wrap(err, fmt.Sprintf("failed to push to destination %s", destRef))
		}
	}
	timing.DefaultRun.Stop(t)
	return writeImageOutputs(image, destRefs)
}

var fs = afero.NewOsFs()

func writeImageOutputs(image v1.Image, destRefs []name.Tag) error {
	dir := os.Getenv("BUILDER_OUTPUT")
	if dir == "" {
		return nil
	}
	f, err := fs.Create(filepath.Join(dir, "images"))
	if err != nil {
		return err
	}
	defer f.Close()

	d, err := image.Digest()
	if err != nil {
		return err
	}

	type imageOutput struct {
		Name   string `json:"name"`
		Digest string `json:"digest"`
	}
	for _, r := range destRefs {
		if err := json.NewEncoder(f).Encode(imageOutput{
			Name:   r.String(),
			Digest: d.String(),
		}); err != nil {
			return err
		}
	}
	return nil
}

func makeTransport(opts *config.KanikoOptions, registryName string, loader systemCertLoader) http.RoundTripper {
	// Create a transport to set our user-agent.
	var tr http.RoundTripper = http.DefaultTransport.(*http.Transport).Clone()
	if opts.SkipTLSVerify || opts.SkipTLSVerifyRegistries.Contains(registryName) {
		tr.(*http.Transport).TLSClientConfig = &tls.Config{
			InsecureSkipVerify: true,
		}
	} else if certificatePath := opts.RegistriesCertificates[registryName]; certificatePath != "" {
		systemCertPool := loader()
		if err := systemCertPool.append(certificatePath); err != nil {
			logrus.WithError(err).Warnf("Failed to load certificate %s for %s\n", certificatePath, registryName)
		} else {
			tr.(*http.Transport).TLSClientConfig = &tls.Config{
				RootCAs: systemCertPool.value(),
			}
		}
	}
	return tr
}

// pushLayerToCache pushes layer (tagged with cacheKey) to opts.Cache
// if opts.Cache doesn't exist, infer the cache from the given destination
func pushLayerToCache(opts *config.KanikoOptions, cacheKey string, tarPath string, createdBy string) error {
	layer, err := tarball.LayerFromFile(tarPath)
	if err != nil {
		return err
	}
	cache, err := cache.Destination(opts, cacheKey)
	if err != nil {
		return errors.Wrap(err, "getting cache destination")
	}
	logrus.Infof("Pushing layer %s to cache now", cache)
	empty := empty.Image
	empty, err = mutate.CreatedAt(empty, v1.Time{Time: time.Now()})
	if err != nil {
		return errors.Wrap(err, "setting empty image created time")
	}

	empty, err = mutate.Append(empty,
		mutate.Addendum{
			Layer: layer,
			History: v1.History{
				Author:    constants.Author,
				CreatedBy: createdBy,
			},
		},
	)
	if err != nil {
		return errors.Wrap(err, "appending layer onto empty image")
	}
	cacheOpts := *opts
	cacheOpts.TarPath = ""   // tarPath doesn't make sense for Docker layers
	cacheOpts.NoPush = false // we want to push cached layers
	cacheOpts.Destinations = []string{cache}
	cacheOpts.InsecureRegistries = opts.InsecureRegistries
	cacheOpts.SkipTLSVerifyRegistries = opts.SkipTLSVerifyRegistries
	return DoPush(empty, &cacheOpts)
}
<commit_msg>Add comments<commit_after>/*
Copyright 2018 Google LLC

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 executor

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/GoogleContainerTools/kaniko/pkg/cache"
	"github.com/GoogleContainerTools/kaniko/pkg/config"
	"github.com/GoogleContainerTools/kaniko/pkg/constants"
	"github.com/GoogleContainerTools/kaniko/pkg/creds"
	"github.com/GoogleContainerTools/kaniko/pkg/timing"
	"github.com/GoogleContainerTools/kaniko/pkg/version"
	"github.com/google/go-containerregistry/pkg/name"
	v1 "github.com/google/go-containerregistry/pkg/v1"
	"github.com/google/go-containerregistry/pkg/v1/empty"
	"github.com/google/go-containerregistry/pkg/v1/layout"
	"github.com/google/go-containerregistry/pkg/v1/mutate"
	"github.com/google/go-containerregistry/pkg/v1/remote"
	"github.com/google/go-containerregistry/pkg/v1/tarball"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/afero"
)

type withUserAgent struct {
	t http.RoundTripper
}

const (
	UpstreamClientUaKey = "UPSTREAM_CLIENT_TYPE"
)

func (w *withUserAgent) RoundTrip(r *http.Request) (*http.Response, error) {
	ua := []string{fmt.Sprintf("kaniko/%s", version.Version())}
	if upstream := os.Getenv(UpstreamClientUaKey); upstream != "" {
		ua = append(ua, upstream)
	}
	r.Header.Set("User-Agent", strings.Join(ua, ","))
	return w.t.RoundTrip(r)
}

type CertPool interface {
	value() *x509.CertPool
	append(path string) error
}

type X509CertPool struct {
	inner x509.CertPool
}

func (p *X509CertPool) value() *x509.CertPool {
	return &p.inner
}

func (p *X509CertPool) append(path string) error {
	pem, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	p.inner.AppendCertsFromPEM(pem)
	return nil
}

type systemCertLoader func() CertPool

var defaultX509Handler systemCertLoader = func() CertPool {
	systemCertPool, err := x509.SystemCertPool()
	if err != nil {
		logrus.Warn("Failed to load system cert pool. Loading empty one instead.")
		systemCertPool = x509.NewCertPool()
	}
	return &X509CertPool{
		inner: *systemCertPool,
	}
}

// CheckPushPermissions checks that the configured credentials can be used to
// push to every specified destination.
func CheckPushPermissions(opts *config.KanikoOptions) error {
	if opts.NoPush {
		return nil
	}

	checked := map[string]bool{}
	for _, destination := range opts.Destinations {
		destRef, err := name.NewTag(destination, name.WeakValidation)
		if err != nil {
			return errors.Wrap(err, "getting tag for destination")
		}
		if checked[destRef.Context().RepositoryStr()] {
			continue
		}

		// Historically kaniko was pre-configured by default with gcr credential helper,
		// in here we keep the backwards compatibility by enabling the GCR helper only
		// when gcr.io is in one of the destinations.
		if strings.Contains(destRef.RegistryStr(), "gcr.io") {
			// Checking for existence of docker.config as it's normally required for
			// authenticated registries and prevent overwriting user provided docker conf
			if _, err := os.Stat("/kaniko/.docker/config.json"); os.IsNotExist(err) {
				cmd := exec.Command("docker-credential-gcr", "configure-docker")
				if err := cmd.Run(); err != nil {
					return errors.Wrap(err, "error while configuring docker-credential-gcr helper")
				}
			}
		}
		registryName := destRef.Repository.Registry.Name()
		if opts.Insecure || opts.InsecureRegistries.Contains(registryName) {
			newReg, err := name.NewRegistry(registryName, name.WeakValidation, name.Insecure)
			if err != nil {
				return errors.Wrap(err, "getting new insecure registry")
			}
			destRef.Repository.Registry = newReg
		}
		tr := makeTransport(opts, registryName, defaultX509Handler)
		if err := remote.CheckPushPermission(destRef, creds.GetKeychain(), tr); err != nil {
			return errors.Wrapf(err, "checking push permission for %q", destRef)
		}
		checked[destRef.Context().RepositoryStr()] = true
	}
	return nil
}

func getDigest(image v1.Image) ([]byte, error) {
	digest, err := image.Digest()
	if err != nil {
		return nil, err
	}
	return []byte(digest.String()), nil
}

// DoPush is responsible for pushing image to the destinations specified in opts
func DoPush(image v1.Image, opts *config.KanikoOptions) error {
	t := timing.Start("Total Push Time")
	var digestByteArray []byte
	var builder strings.Builder
	if opts.DigestFile != "" || opts.ImageNameDigestFile != "" {
		var err error
		digestByteArray, err = getDigest(image)
		if err != nil {
			return errors.Wrap(err, "error fetching digest")
		}
	}

	if opts.DigestFile != "" {
		err := ioutil.WriteFile(opts.DigestFile, digestByteArray, 0644)
		if err != nil {
			return errors.Wrap(err, "writing digest to file failed")
		}
	}

	if opts.OCILayoutPath != "" {
		path, err := layout.Write(opts.OCILayoutPath, empty.Index)
		if err != nil {
			return errors.Wrap(err, "writing empty layout")
		}
		if err := path.AppendImage(image); err != nil {
			return errors.Wrap(err, "appending image")
		}
	}

	destRefs := []name.Tag{}
	for _, destination := range opts.Destinations {
		destRef, err := name.NewTag(destination, name.WeakValidation)
		if err != nil {
			return errors.Wrap(err, "getting tag for destination")
		}
		if opts.ImageNameDigestFile != "" {
			imageName := []byte(destRef.Repository.Name() + "@")
			builder.Write(append(imageName, digestByteArray...))
			builder.WriteString("\n")
		}
		destRefs = append(destRefs, destRef)
	}

	if opts.ImageNameDigestFile != "" {
		err := ioutil.WriteFile(opts.ImageNameDigestFile, []byte(builder.String()), 0644)
		if err != nil {
			return errors.Wrap(err, "writing image name with digest to file failed")
		}
	}

	if opts.TarPath != "" {
		tagToImage := map[name.Tag]v1.Image{}
		for _, destRef := range destRefs {
			tagToImage[destRef] = image
		}
		return tarball.MultiWriteToFile(opts.TarPath, tagToImage)
	}

	if opts.NoPush {
		logrus.Info("Skipping push to container registry due to --no-push flag")
		return nil
	}

	// continue pushing unless an error occurs
	for _, destRef := range destRefs {
		registryName := destRef.Repository.Registry.Name()
		if opts.Insecure || opts.InsecureRegistries.Contains(registryName) {
			newReg, err := name.NewRegistry(registryName, name.WeakValidation, name.Insecure)
			if err != nil {
				return errors.Wrap(err, "getting new insecure registry")
			}
			destRef.Repository.Registry = newReg
		}

		pushAuth, err := creds.GetKeychain().Resolve(destRef.Context().Registry)
		if err != nil {
			return errors.Wrap(err, "resolving pushAuth")
		}

		tr := makeTransport(opts, registryName, defaultX509Handler)
		rt := &withUserAgent{t: tr}

		if err := remote.Write(destRef, image, remote.WithAuth(pushAuth), remote.WithTransport(rt)); err != nil {
			return errors.Wrap(err, fmt.Sprintf("failed to push to destination %s", destRef))
		}
	}
	timing.DefaultRun.Stop(t)
	return writeImageOutputs(image, destRefs)
}

var fs = afero.NewOsFs()

func writeImageOutputs(image v1.Image, destRefs []name.Tag) error {
	dir := os.Getenv("BUILDER_OUTPUT")
	if dir == "" {
		return nil
	}
	f, err := fs.Create(filepath.Join(dir, "images"))
	if err != nil {
		return err
	}
	defer f.Close()

	d, err := image.Digest()
	if err != nil {
		return err
	}

	type imageOutput struct {
		Name   string `json:"name"`
		Digest string `json:"digest"`
	}
	for _, r := range destRefs {
		if err := json.NewEncoder(f).Encode(imageOutput{
			Name:   r.String(),
			Digest: d.String(),
		}); err != nil {
			return err
		}
	}
	return nil
}

func makeTransport(opts *config.KanikoOptions, registryName string, loader systemCertLoader) http.RoundTripper {
	// Create a transport to set our user-agent.
	var tr http.RoundTripper = http.DefaultTransport.(*http.Transport).Clone()
	if opts.SkipTLSVerify || opts.SkipTLSVerifyRegistries.Contains(registryName) {
		tr.(*http.Transport).TLSClientConfig = &tls.Config{
			InsecureSkipVerify: true,
		}
	} else if certificatePath := opts.RegistriesCertificates[registryName]; certificatePath != "" {
		systemCertPool := loader()
		if err := systemCertPool.append(certificatePath); err != nil {
			logrus.WithError(err).Warnf("Failed to load certificate %s for %s\n", certificatePath, registryName)
		} else {
			tr.(*http.Transport).TLSClientConfig = &tls.Config{
				RootCAs: systemCertPool.value(),
			}
		}
	}
	return tr
}

// pushLayerToCache pushes layer (tagged with cacheKey) to opts.Cache
// if opts.Cache doesn't exist, infer the cache from the given destination
func pushLayerToCache(opts *config.KanikoOptions, cacheKey string, tarPath string, createdBy string) error {
	layer, err := tarball.LayerFromFile(tarPath)
	if err != nil {
		return err
	}
	cache, err := cache.Destination(opts, cacheKey)
	if err != nil {
		return errors.Wrap(err, "getting cache destination")
	}
	logrus.Infof("Pushing layer %s to cache now", cache)
	empty := empty.Image
	empty, err = mutate.CreatedAt(empty, v1.Time{Time: time.Now()})
	if err != nil {
		return errors.Wrap(err, "setting empty image created time")
	}

	empty, err = mutate.Append(empty,
		mutate.Addendum{
			Layer: layer,
			History: v1.History{
				Author:    constants.Author,
				CreatedBy: createdBy,
			},
		},
	)
	if err != nil {
		return errors.Wrap(err, "appending layer onto empty image")
	}
	cacheOpts := *opts
	cacheOpts.TarPath = ""   // tarPath doesn't make sense for Docker layers
	cacheOpts.NoPush = false // we want to push cached layers
	cacheOpts.Destinations = []string{cache}
	cacheOpts.InsecureRegistries = opts.InsecureRegistries
	cacheOpts.SkipTLSVerifyRegistries = opts.SkipTLSVerifyRegistries
	return DoPush(empty, &cacheOpts)
}
<|endoftext|>


<commit_before>package gcsql

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"

	"github.com/gochan-org/gochan/pkg/gclog"
	"github.com/gochan-org/gochan/pkg/gcutil"
)

var (
	db            *sql.DB
	dbDriver      string
	fatalSQLFlags = gclog.LErrorLog | gclog.LStdLog | gclog.LFatal
	nilTimestamp  string
	sqlReplacer   *strings.Replacer // used during SQL string preparation
)

// ConnectToDB initializes the database connection and exits if there are any errors
func ConnectToDB(host string, dbType string, dbName string, username string, password string, prefix string) {
	var err error
	var connStr string
	sqlReplacer = strings.NewReplacer(
		"DBNAME", dbName,
		"DBPREFIX", prefix,
		"\n", " ")
	gclog.Print(gclog.LStdLog|gclog.LErrorLog, "Initializing server...")

	switch dbType {
	case "mysql":
		connStr = fmt.Sprintf("%s:%s@%s/%s?parseTime=true&collation=utf8mb4_unicode_ci",
			username, password, host, dbName)
		nilTimestamp = "0000-00-00 00:00:00"
	case "postgres":
		connStr = fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable",
			username, password, host, dbName)
		nilTimestamp = "0001-01-01 00:00:00"
	case "sqlite3":
		gclog.Print(gclog.LStdLog, "sqlite3 support is still flaky, consider using mysql or postgres")
		connStr = fmt.Sprintf("file:%s?mode=rwc&_auth&_auth_user=%s&_auth_pass=%s&cache=shared",
			host, username, password)
		nilTimestamp = "0001-01-01 00:00:00+00:00"
	default:
		gclog.Printf(fatalSQLFlags,
			`Invalid DBtype %q in gochan.json, valid values are "mysql", "postgres", and "sqlite3"`, dbType)
	}
	dbDriver = dbType
	if db, err = sql.Open(dbType, connStr); err != nil {
		gclog.Print(fatalSQLFlags, "Failed to connect to the database: ", err.Error())
	}

	//TODO TEMP
	alreadyPopulated, err := DoesDatabaseVersionExist()
	if !alreadyPopulated {

		if err = initDB("initdb_" + dbType + ".sql"); err != nil {
			gclog.Print(fatalSQLFlags, "Failed initializing DB: ", err.Error())
		}

		//TODO fix new install thing once it works with existing database
		// var sqlVersionStr string
		// isNewInstall := false
		// if err = queryRowSQL("SELECT value FROM DBPREFIXinfo WHERE name = 'version'",
		// 	[]interface{}{}, []interface{}{&sqlVersionStr},
		// ); err == sql.ErrNoRows {
		// 	isNewInstall = true
		// } else if err != nil {
		// 	gclog.Print(lErrorLog|lStdLog|lFatal, "Failed initializing DB: ", err.Error())
		// }

		err = CreateDefaultBoardIfNoneExist()
		if err != nil {
			gclog.Print(fatalSQLFlags, "Failed creating default board: ", err.Error())
		}
		err = CreateDefaultAdminIfNoStaff()
		if err != nil {
			gclog.Print(fatalSQLFlags, "Failed creating default admin account: ", err.Error())
		}
		//fix versioning thing
	} else {
		gclog.Print(gclog.LStdLog, "Database already populated")
	}
	//END TEMP
}

func initDB(initFile string) error {
	var err error
	filePath := gcutil.FindResource(initFile,
		"/usr/local/share/gochan/"+initFile,
		"/usr/share/gochan/"+initFile)
	if filePath == "" {
		return fmt.Errorf("SQL database initialization file (%s) missing. Please reinstall gochan", initFile)
	}

	sqlBytes, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}

	sqlStr := regexp.MustCompile("--.*\n?").ReplaceAllString(string(sqlBytes), " ")
	sqlArr := strings.Split(sqlReplacer.Replace(sqlStr), ";")

	for _, statement := range sqlArr {
		if statement != "" && statement != " " {
			if _, err = db.Exec(statement); err != nil {
				return err
			}
		}
	}
	return nil
}
<commit_msg>Fixed empty query catch code<commit_after>package gcsql

import (
	"database/sql"
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"

	"github.com/gochan-org/gochan/pkg/gclog"
	"github.com/gochan-org/gochan/pkg/gcutil"
)

var (
	db            *sql.DB
	dbDriver      string
	fatalSQLFlags = gclog.LErrorLog | gclog.LStdLog | gclog.LFatal
	nilTimestamp  string
	sqlReplacer   *strings.Replacer // used during SQL string preparation
)

// ConnectToDB initializes the database connection and exits if there are any errors
func ConnectToDB(host string, dbType string, dbName string, username string, password string, prefix string) {
	var err error
	var connStr string
	sqlReplacer = strings.NewReplacer(
		"DBNAME", dbName,
		"DBPREFIX", prefix,
		"\n", " ")
	gclog.Print(gclog.LStdLog|gclog.LErrorLog, "Initializing server...")

	switch dbType {
	case "mysql":
		connStr = fmt.Sprintf("%s:%s@%s/%s?parseTime=true&collation=utf8mb4_unicode_ci",
			username, password, host, dbName)
		nilTimestamp = "0000-00-00 00:00:00"
	case "postgres":
		connStr = fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable",
			username, password, host, dbName)
		nilTimestamp = "0001-01-01 00:00:00"
	case "sqlite3":
		gclog.Print(gclog.LStdLog, "sqlite3 support is still flaky, consider using mysql or postgres")
		connStr = fmt.Sprintf("file:%s?mode=rwc&_auth&_auth_user=%s&_auth_pass=%s&cache=shared",
			host, username, password)
		nilTimestamp = "0001-01-01 00:00:00+00:00"
	default:
		gclog.Printf(fatalSQLFlags,
			`Invalid DBtype %q in gochan.json, valid values are "mysql", "postgres", and "sqlite3"`, dbType)
	}
	dbDriver = dbType
	if db, err = sql.Open(dbType, connStr); err != nil {
		gclog.Print(fatalSQLFlags, "Failed to connect to the database: ", err.Error())
	}

	//TODO TEMP
	alreadyPopulated, err := DoesDatabaseVersionExist()
	if !alreadyPopulated {

		if err = initDB("initdb_" + dbType + ".sql"); err != nil {
			gclog.Print(fatalSQLFlags, "Failed initializing DB: ", err.Error())
		}

		//TODO fix new install thing once it works with existing database
		// var sqlVersionStr string
		// isNewInstall := false
		// if err = queryRowSQL("SELECT value FROM DBPREFIXinfo WHERE name = 'version'",
		// 	[]interface{}{}, []interface{}{&sqlVersionStr},
		// ); err == sql.ErrNoRows {
		// 	isNewInstall = true
		// } else if err != nil {
		// 	gclog.Print(lErrorLog|lStdLog|lFatal, "Failed initializing DB: ", err.Error())
		// }

		err = CreateDefaultBoardIfNoneExist()
		if err != nil {
			gclog.Print(fatalSQLFlags, "Failed creating default board: ", err.Error())
		}
		err = CreateDefaultAdminIfNoStaff()
		if err != nil {
			gclog.Print(fatalSQLFlags, "Failed creating default admin account: ", err.Error())
		}
		//fix versioning thing
	} else {
		gclog.Print(gclog.LStdLog, "Database already populated")
	}
	//END TEMP
}

func initDB(initFile string) error {
	var err error
	filePath := gcutil.FindResource(initFile,
		"/usr/local/share/gochan/"+initFile,
		"/usr/share/gochan/"+initFile)
	if filePath == "" {
		return fmt.Errorf("SQL database initialization file (%s) missing. Please reinstall gochan", initFile)
	}

	sqlBytes, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}

	sqlStr := regexp.MustCompile("--.*\n?").ReplaceAllString(string(sqlBytes), " ")
	sqlArr := strings.Split(sqlReplacer.Replace(sqlStr), ";")

	for _, statement := range sqlArr {
		statement = strings.Trim(statement, " \n\r\t")
		if len(statement) > 0 {
			if _, err = db.Exec(statement); err != nil {
				print(len(statement))
				fmt.Printf("%08b", []byte(statement))
				return err
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package model

import (
	"fmt"
	"net"
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/apis/kops/model"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/pkg/featureflag"
	"k8s.io/kops/pkg/model/components"
	"k8s.io/kops/pkg/model/iam"
	nodeidentityaws "k8s.io/kops/pkg/nodeidentity/aws"
	"k8s.io/kops/pkg/nodelabels"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
	"k8s.io/kops/upup/pkg/fi/cloudup/awsup"

	"github.com/blang/semver/v4"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/klog/v2"
)

const (
	clusterAutoscalerNodeTemplateTaint = "k8s.io/cluster-autoscaler/node-template/taint/"
)

// KopsModelContext is the kops model
type KopsModelContext struct {
	iam.IAMModelContext
	InstanceGroups []*kops.InstanceGroup
	Region         string
	SSHPublicKeys  [][]byte
}

// GatherSubnets maps the subnet names in an InstanceGroup to the ClusterSubnetSpec objects (which are stored on the Cluster)
func (m *KopsModelContext) GatherSubnets(ig *kops.InstanceGroup) ([]*kops.ClusterSubnetSpec, error) {
	var subnets []*kops.ClusterSubnetSpec
	var subnetType kops.SubnetType

	for _, subnetName := range ig.Spec.Subnets {
		var matches []*kops.ClusterSubnetSpec
		for i := range m.Cluster.Spec.Subnets {
			clusterSubnet := &m.Cluster.Spec.Subnets[i]
			if clusterSubnet.Name == subnetName {
				matches = append(matches, clusterSubnet)
			}
		}
		if len(matches) == 0 {
			return nil, fmt.Errorf("subnet not found: %q", subnetName)
		}
		if len(matches) > 1 {
			return nil, fmt.Errorf("found multiple subnets with name: %q", subnetName)
		}
		subnets = append(subnets, matches[0])

		// @step: check the instance is not cross subnet types
		switch subnetType {
		case "":
			subnetType = matches[0].Type
		default:
			if matches[0].Type != subnetType {
				return nil, fmt.Errorf("found subnets of different types: %v", strings.Join([]string{string(subnetType), string(matches[0].Type)}, ","))
			}
		}
	}

	return subnets, nil
}

// FindInstanceGroup returns the instance group with the matching Name (or nil if not found)
func (m *KopsModelContext) FindInstanceGroup(name string) *kops.InstanceGroup {
	for _, ig := range m.InstanceGroups {
		if ig.ObjectMeta.Name == name {
			return ig
		}
	}
	return nil
}

// FindSubnet returns the subnet with the matching Name (or nil if not found)
func (m *KopsModelContext) FindSubnet(name string) *kops.ClusterSubnetSpec {
	return model.FindSubnet(m.Cluster, name)
}

// FindZonesForInstanceGroup finds the zones for an InstanceGroup
func (m *KopsModelContext) FindZonesForInstanceGroup(ig *kops.InstanceGroup) ([]string, error) {
	return model.FindZonesForInstanceGroup(m.Cluster, ig)
}

// MasterInstanceGroups returns InstanceGroups with the master role
func (m *KopsModelContext) MasterInstanceGroups() []*kops.InstanceGroup {
	var groups []*kops.InstanceGroup
	for _, ig := range m.InstanceGroups {
		if !ig.IsMaster() {
			continue
		}
		groups = append(groups, ig)
	}
	return groups
}

// NodeInstanceGroups returns InstanceGroups with the node role
func (m *KopsModelContext) NodeInstanceGroups() []*kops.InstanceGroup {
	var groups []*kops.InstanceGroup
	for _, ig := range m.InstanceGroups {
		if ig.Spec.Role != kops.InstanceGroupRoleNode {
			continue
		}
		groups = append(groups, ig)
	}
	return groups
}

// CloudTagsForInstanceGroup computes the tags to apply to instances in the specified InstanceGroup
func (m *KopsModelContext) CloudTagsForInstanceGroup(ig *kops.InstanceGroup) (map[string]string, error) {
	labels := m.CloudTags(m.AutoscalingGroupName(ig), false)

	// Apply any user-specified global labels first so they can be overridden by IG-specific labels
	for k, v := range m.Cluster.Spec.CloudLabels {
		labels[k] = v
	}

	// Apply any user-specified labels
	for k, v := range ig.Spec.CloudLabels {
		labels[k] = v
	}

	// Apply labels for cluster autoscaler node labels
	for k, v := range nodelabels.BuildNodeLabels(m.Cluster, ig) {
		labels[nodeidentityaws.ClusterAutoscalerNodeTemplateLabel+k] = v
	}

	// Apply labels for cluster autoscaler node taints
	for _, v := range ig.Spec.Taints {
		splits := strings.SplitN(v, "=", 2)
		if len(splits) > 1 {
			labels[clusterAutoscalerNodeTemplateTaint+splits[0]] = splits[1]
		}
	}

	// The system tags take priority because the cluster likely breaks without them...

	if ig.Spec.Role == kops.InstanceGroupRoleMaster {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleMaster))] = "1"
	}

	if ig.Spec.Role == kops.InstanceGroupRoleAPIServer {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleAPIServer))] = "1"
	}

	if ig.Spec.Role == kops.InstanceGroupRoleNode {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleNode))] = "1"
	}

	if ig.Spec.Role == kops.InstanceGroupRoleBastion {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleBastion))] = "1"
	}

	labels[nodeidentityaws.CloudTagInstanceGroupName] = ig.Name

	return labels, nil
}

// CloudTags computes the tags to apply to a normal cloud resource with the specified name
func (m *KopsModelContext) CloudTags(name string, shared bool) map[string]string {
	tags := make(map[string]string)

	switch kops.CloudProviderID(m.Cluster.Spec.CloudProvider) {
	case kops.CloudProviderAWS:
		if shared {
			// If the resource is shared, we don't try to set the Name - we presume that is managed externally
			klog.V(4).Infof("Skipping Name tag for shared resource")
		} else {
			if name != "" {
				tags["Name"] = name
			}
		}

		// Kubernetes 1.6 introduced the shared ownership tag; that replaces TagClusterName
		setLegacyTag := true
		// For the moment, we only skip the legacy tag for shared resources
		// (other people may be using it)
		if shared {
			klog.V(4).Infof("Skipping %q tag for shared resource", awsup.TagClusterName)
			setLegacyTag = false
		}
		if setLegacyTag {
			tags[awsup.TagClusterName] = m.Cluster.ObjectMeta.Name
		}

		if shared {
			tags["kubernetes.io/cluster/"+m.Cluster.ObjectMeta.Name] = "shared"
		} else {
			tags["kubernetes.io/cluster/"+m.Cluster.ObjectMeta.Name] = "owned"
			for k, v := range m.Cluster.Spec.CloudLabels {
				tags[k] = v
			}
		}

	}
	return tags
}

// UseKopsControllerForNodeBootstrap checks if nodeup should use kops-controller to bootstrap.
func (m *KopsModelContext) UseKopsControllerForNodeBootstrap() bool {
	return model.UseKopsControllerForNodeBootstrap(m.Cluster)
}

// UseBootstrapTokens checks if bootstrap tokens are enabled
func (m *KopsModelContext) UseBootstrapTokens() bool {
	if m.Cluster.Spec.KubeAPIServer == nil || m.UseKopsControllerForNodeBootstrap() {
		return false
	}

	return fi.BoolValue(m.Cluster.Spec.KubeAPIServer.EnableBootstrapAuthToken)
}

// UsesBastionDns checks if we should use a specific name for the bastion dns
func (m *KopsModelContext) UsesBastionDns() bool {
	if m.Cluster.Spec.Topology.Bastion != nil && m.Cluster.Spec.Topology.Bastion.BastionPublicName != "" {
		return true
	}
	return false
}

// UsesSSHBastion checks if we have a Bastion in the cluster
func (m *KopsModelContext) UsesSSHBastion() bool {
	for _, ig := range m.InstanceGroups {
		if ig.Spec.Role == kops.InstanceGroupRoleBastion {
			return true
		}
	}

	return false
}

// UseLoadBalancerForAPI checks if we are using a load balancer for the kubeapi
func (m *KopsModelContext) UseLoadBalancerForAPI() bool {
	if m.Cluster.Spec.API == nil {
		return false
	}
	return m.Cluster.Spec.API.LoadBalancer != nil
}

// UseLoadBalancerForInternalAPI check if true then we will use the created loadbalancer for internal kubelet
// connections.  The intention here is to make connections to apiserver more
// HA - see https://github.com/kubernetes/kops/issues/4252
func (m *KopsModelContext) UseLoadBalancerForInternalAPI() bool {
	return m.UseLoadBalancerForAPI() &&
		m.Cluster.Spec.API.LoadBalancer.UseForInternalApi
}

// APILoadBalancerClass returns which type of load balancer to use for the api
func (m *KopsModelContext) APILoadBalancerClass() kops.LoadBalancerClass {
	if m.Cluster.Spec.API != nil && m.Cluster.Spec.API.LoadBalancer != nil {
		return m.Cluster.Spec.API.LoadBalancer.Class
	}
	return kops.LoadBalancerClassClassic
}

// UsePrivateDNS checks if we are using private DNS
func (m *KopsModelContext) UsePrivateDNS() bool {
	topology := m.Cluster.Spec.Topology
	if topology != nil && topology.DNS != nil {
		switch topology.DNS.Type {
		case kops.DNSTypePublic:
			return false
		case kops.DNSTypePrivate:
			return true

		default:
			klog.Warningf("Unknown DNS type %q", topology.DNS.Type)
			return false
		}
	}

	return false
}

// UseClassicLoadBalancer checks if we are using Classic LoadBalancer
func (m *KopsModelContext) UseClassicLoadBalancer() bool {
	return m.Cluster.Spec.API.LoadBalancer.Class == kops.LoadBalancerClassClassic
}

// UseNetworkLoadBalancer checks if we are using Network LoadBalancer
func (m *KopsModelContext) UseNetworkLoadBalancer() bool {
	return m.Cluster.Spec.API.LoadBalancer.Class == kops.LoadBalancerClassNetwork
}

// UseEtcdManager checks to see if etcd manager is enabled
func (c *KopsModelContext) UseEtcdManager() bool {
	for _, x := range c.Cluster.Spec.EtcdClusters {
		if x.Provider == kops.EtcdProviderTypeManager {
			return true
		}
	}

	return false
}

// UseEtcdTLS checks to see if etcd tls is enabled
func (m *KopsModelContext) UseEtcdTLS() bool {
	for _, x := range m.Cluster.Spec.EtcdClusters {
		if x.EnableEtcdTLS {
			return true
		}
	}

	return false
}

// UseSSHKey returns true if SSHKeyName from the cluster spec is not set to an empty string (""). Setting SSHKeyName
// to an empty string indicates that an SSH key should not be set on instances.
func (m *KopsModelContext) UseSSHKey() bool {
	sshKeyName := m.Cluster.Spec.SSHKeyName
	return sshKeyName == nil || *sshKeyName != ""
}

// KubernetesVersion parses the semver version of kubernetes, from the cluster spec
func (m *KopsModelContext) KubernetesVersion() semver.Version {
	// TODO: Remove copy-pasting c.f. https://github.com/kubernetes/kops/blob/master/pkg/model/components/context.go#L32

	kubernetesVersion := m.Cluster.Spec.KubernetesVersion

	if kubernetesVersion == "" {
		klog.Fatalf("KubernetesVersion is required")
	}

	sv, err := util.ParseKubernetesVersion(kubernetesVersion)
	if err != nil {
		klog.Fatalf("unable to determine kubernetes version from %q", kubernetesVersion)
	}

	return *sv
}

// IsKubernetesGTE checks if the kubernetes version is at least version, ignoring prereleases / patches
func (m *KopsModelContext) IsKubernetesGTE(version string) bool {
	return util.IsKubernetesGTE(version, m.KubernetesVersion())
}

// IsKubernetesLT checks if the kubernetes version is before the specified version, ignoring prereleases / patches
func (m *KopsModelContext) IsKubernetesLT(version string) bool {
	return !m.IsKubernetesGTE(version)
}

// WellKnownServiceIP returns a service ip with the service cidr
func (m *KopsModelContext) WellKnownServiceIP(id int) (net.IP, error) {
	return components.WellKnownServiceIP(&m.Cluster.Spec, id)
}

// NodePortRange returns the range of ports allocated to NodePorts
func (m *KopsModelContext) NodePortRange() (utilnet.PortRange, error) {
	// defaultServiceNodePortRange is the default port range for NodePort services.
	defaultServiceNodePortRange := utilnet.PortRange{Base: 30000, Size: 2768}

	kubeApiServer := m.Cluster.Spec.KubeAPIServer
	if kubeApiServer != nil && kubeApiServer.ServiceNodePortRange != "" {
		err := defaultServiceNodePortRange.Set(kubeApiServer.ServiceNodePortRange)
		if err != nil {
			return utilnet.PortRange{}, fmt.Errorf("error parsing ServiceNodePortRange %q", kubeApiServer.ServiceNodePortRange)
		}
	}

	return defaultServiceNodePortRange, nil
}

// UseServiceAccountIAM returns true if we are using service-account bound IAM roles.
func (m *KopsModelContext) UseServiceAccountIAM() bool {
	return featureflag.UseServiceAccountIAM.Enabled()
}
<commit_msg>'sv' may have 'nil' or other unexpected value  (#11161)<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package model

import (
	"fmt"
	"net"
	"strings"

	"k8s.io/kops/pkg/apis/kops"
	"k8s.io/kops/pkg/apis/kops/model"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/pkg/featureflag"
	"k8s.io/kops/pkg/model/components"
	"k8s.io/kops/pkg/model/iam"
	nodeidentityaws "k8s.io/kops/pkg/nodeidentity/aws"
	"k8s.io/kops/pkg/nodelabels"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
	"k8s.io/kops/upup/pkg/fi/cloudup/awsup"

	"github.com/blang/semver/v4"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/klog/v2"
)

const (
	clusterAutoscalerNodeTemplateTaint = "k8s.io/cluster-autoscaler/node-template/taint/"
)

// KopsModelContext is the kops model
type KopsModelContext struct {
	iam.IAMModelContext
	InstanceGroups []*kops.InstanceGroup
	Region         string
	SSHPublicKeys  [][]byte
}

// GatherSubnets maps the subnet names in an InstanceGroup to the ClusterSubnetSpec objects (which are stored on the Cluster)
func (m *KopsModelContext) GatherSubnets(ig *kops.InstanceGroup) ([]*kops.ClusterSubnetSpec, error) {
	var subnets []*kops.ClusterSubnetSpec
	var subnetType kops.SubnetType

	for _, subnetName := range ig.Spec.Subnets {
		var matches []*kops.ClusterSubnetSpec
		for i := range m.Cluster.Spec.Subnets {
			clusterSubnet := &m.Cluster.Spec.Subnets[i]
			if clusterSubnet.Name == subnetName {
				matches = append(matches, clusterSubnet)
			}
		}
		if len(matches) == 0 {
			return nil, fmt.Errorf("subnet not found: %q", subnetName)
		}
		if len(matches) > 1 {
			return nil, fmt.Errorf("found multiple subnets with name: %q", subnetName)
		}
		subnets = append(subnets, matches[0])

		// @step: check the instance is not cross subnet types
		switch subnetType {
		case "":
			subnetType = matches[0].Type
		default:
			if matches[0].Type != subnetType {
				return nil, fmt.Errorf("found subnets of different types: %v", strings.Join([]string{string(subnetType), string(matches[0].Type)}, ","))
			}
		}
	}

	return subnets, nil
}

// FindInstanceGroup returns the instance group with the matching Name (or nil if not found)
func (m *KopsModelContext) FindInstanceGroup(name string) *kops.InstanceGroup {
	for _, ig := range m.InstanceGroups {
		if ig.ObjectMeta.Name == name {
			return ig
		}
	}
	return nil
}

// FindSubnet returns the subnet with the matching Name (or nil if not found)
func (m *KopsModelContext) FindSubnet(name string) *kops.ClusterSubnetSpec {
	return model.FindSubnet(m.Cluster, name)
}

// FindZonesForInstanceGroup finds the zones for an InstanceGroup
func (m *KopsModelContext) FindZonesForInstanceGroup(ig *kops.InstanceGroup) ([]string, error) {
	return model.FindZonesForInstanceGroup(m.Cluster, ig)
}

// MasterInstanceGroups returns InstanceGroups with the master role
func (m *KopsModelContext) MasterInstanceGroups() []*kops.InstanceGroup {
	var groups []*kops.InstanceGroup
	for _, ig := range m.InstanceGroups {
		if !ig.IsMaster() {
			continue
		}
		groups = append(groups, ig)
	}
	return groups
}

// NodeInstanceGroups returns InstanceGroups with the node role
func (m *KopsModelContext) NodeInstanceGroups() []*kops.InstanceGroup {
	var groups []*kops.InstanceGroup
	for _, ig := range m.InstanceGroups {
		if ig.Spec.Role != kops.InstanceGroupRoleNode {
			continue
		}
		groups = append(groups, ig)
	}
	return groups
}

// CloudTagsForInstanceGroup computes the tags to apply to instances in the specified InstanceGroup
func (m *KopsModelContext) CloudTagsForInstanceGroup(ig *kops.InstanceGroup) (map[string]string, error) {
	labels := m.CloudTags(m.AutoscalingGroupName(ig), false)

	// Apply any user-specified global labels first so they can be overridden by IG-specific labels
	for k, v := range m.Cluster.Spec.CloudLabels {
		labels[k] = v
	}

	// Apply any user-specified labels
	for k, v := range ig.Spec.CloudLabels {
		labels[k] = v
	}

	// Apply labels for cluster autoscaler node labels
	for k, v := range nodelabels.BuildNodeLabels(m.Cluster, ig) {
		labels[nodeidentityaws.ClusterAutoscalerNodeTemplateLabel+k] = v
	}

	// Apply labels for cluster autoscaler node taints
	for _, v := range ig.Spec.Taints {
		splits := strings.SplitN(v, "=", 2)
		if len(splits) > 1 {
			labels[clusterAutoscalerNodeTemplateTaint+splits[0]] = splits[1]
		}
	}

	// The system tags take priority because the cluster likely breaks without them...

	if ig.Spec.Role == kops.InstanceGroupRoleMaster {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleMaster))] = "1"
	}

	if ig.Spec.Role == kops.InstanceGroupRoleAPIServer {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleAPIServer))] = "1"
	}

	if ig.Spec.Role == kops.InstanceGroupRoleNode {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleNode))] = "1"
	}

	if ig.Spec.Role == kops.InstanceGroupRoleBastion {
		labels[awstasks.CloudTagInstanceGroupRolePrefix+strings.ToLower(string(kops.InstanceGroupRoleBastion))] = "1"
	}

	labels[nodeidentityaws.CloudTagInstanceGroupName] = ig.Name

	return labels, nil
}

// CloudTags computes the tags to apply to a normal cloud resource with the specified name
func (m *KopsModelContext) CloudTags(name string, shared bool) map[string]string {
	tags := make(map[string]string)

	switch kops.CloudProviderID(m.Cluster.Spec.CloudProvider) {
	case kops.CloudProviderAWS:
		if shared {
			// If the resource is shared, we don't try to set the Name - we presume that is managed externally
			klog.V(4).Infof("Skipping Name tag for shared resource")
		} else {
			if name != "" {
				tags["Name"] = name
			}
		}

		// Kubernetes 1.6 introduced the shared ownership tag; that replaces TagClusterName
		setLegacyTag := true
		// For the moment, we only skip the legacy tag for shared resources
		// (other people may be using it)
		if shared {
			klog.V(4).Infof("Skipping %q tag for shared resource", awsup.TagClusterName)
			setLegacyTag = false
		}
		if setLegacyTag {
			tags[awsup.TagClusterName] = m.Cluster.ObjectMeta.Name
		}

		if shared {
			tags["kubernetes.io/cluster/"+m.Cluster.ObjectMeta.Name] = "shared"
		} else {
			tags["kubernetes.io/cluster/"+m.Cluster.ObjectMeta.Name] = "owned"
			for k, v := range m.Cluster.Spec.CloudLabels {
				tags[k] = v
			}
		}

	}
	return tags
}

// UseKopsControllerForNodeBootstrap checks if nodeup should use kops-controller to bootstrap.
func (m *KopsModelContext) UseKopsControllerForNodeBootstrap() bool {
	return model.UseKopsControllerForNodeBootstrap(m.Cluster)
}

// UseBootstrapTokens checks if bootstrap tokens are enabled
func (m *KopsModelContext) UseBootstrapTokens() bool {
	if m.Cluster.Spec.KubeAPIServer == nil || m.UseKopsControllerForNodeBootstrap() {
		return false
	}

	return fi.BoolValue(m.Cluster.Spec.KubeAPIServer.EnableBootstrapAuthToken)
}

// UsesBastionDns checks if we should use a specific name for the bastion dns
func (m *KopsModelContext) UsesBastionDns() bool {
	if m.Cluster.Spec.Topology.Bastion != nil && m.Cluster.Spec.Topology.Bastion.BastionPublicName != "" {
		return true
	}
	return false
}

// UsesSSHBastion checks if we have a Bastion in the cluster
func (m *KopsModelContext) UsesSSHBastion() bool {
	for _, ig := range m.InstanceGroups {
		if ig.Spec.Role == kops.InstanceGroupRoleBastion {
			return true
		}
	}

	return false
}

// UseLoadBalancerForAPI checks if we are using a load balancer for the kubeapi
func (m *KopsModelContext) UseLoadBalancerForAPI() bool {
	if m.Cluster.Spec.API == nil {
		return false
	}
	return m.Cluster.Spec.API.LoadBalancer != nil
}

// UseLoadBalancerForInternalAPI check if true then we will use the created loadbalancer for internal kubelet
// connections.  The intention here is to make connections to apiserver more
// HA - see https://github.com/kubernetes/kops/issues/4252
func (m *KopsModelContext) UseLoadBalancerForInternalAPI() bool {
	return m.UseLoadBalancerForAPI() &&
		m.Cluster.Spec.API.LoadBalancer.UseForInternalApi
}

// APILoadBalancerClass returns which type of load balancer to use for the api
func (m *KopsModelContext) APILoadBalancerClass() kops.LoadBalancerClass {
	if m.Cluster.Spec.API != nil && m.Cluster.Spec.API.LoadBalancer != nil {
		return m.Cluster.Spec.API.LoadBalancer.Class
	}
	return kops.LoadBalancerClassClassic
}

// UsePrivateDNS checks if we are using private DNS
func (m *KopsModelContext) UsePrivateDNS() bool {
	topology := m.Cluster.Spec.Topology
	if topology != nil && topology.DNS != nil {
		switch topology.DNS.Type {
		case kops.DNSTypePublic:
			return false
		case kops.DNSTypePrivate:
			return true

		default:
			klog.Warningf("Unknown DNS type %q", topology.DNS.Type)
			return false
		}
	}

	return false
}

// UseClassicLoadBalancer checks if we are using Classic LoadBalancer
func (m *KopsModelContext) UseClassicLoadBalancer() bool {
	return m.Cluster.Spec.API.LoadBalancer.Class == kops.LoadBalancerClassClassic
}

// UseNetworkLoadBalancer checks if we are using Network LoadBalancer
func (m *KopsModelContext) UseNetworkLoadBalancer() bool {
	return m.Cluster.Spec.API.LoadBalancer.Class == kops.LoadBalancerClassNetwork
}

// UseEtcdManager checks to see if etcd manager is enabled
func (c *KopsModelContext) UseEtcdManager() bool {
	for _, x := range c.Cluster.Spec.EtcdClusters {
		if x.Provider == kops.EtcdProviderTypeManager {
			return true
		}
	}

	return false
}

// UseEtcdTLS checks to see if etcd tls is enabled
func (m *KopsModelContext) UseEtcdTLS() bool {
	for _, x := range m.Cluster.Spec.EtcdClusters {
		if x.EnableEtcdTLS {
			return true
		}
	}

	return false
}

// UseSSHKey returns true if SSHKeyName from the cluster spec is not set to an empty string (""). Setting SSHKeyName
// to an empty string indicates that an SSH key should not be set on instances.
func (m *KopsModelContext) UseSSHKey() bool {
	sshKeyName := m.Cluster.Spec.SSHKeyName
	return sshKeyName == nil || *sshKeyName != ""
}

// KubernetesVersion parses the semver version of kubernetes, from the cluster spec
func (m *KopsModelContext) KubernetesVersion() semver.Version {
	// TODO: Remove copy-pasting c.f. https://github.com/kubernetes/kops/blob/master/pkg/model/components/context.go#L32

	kubernetesVersion := m.Cluster.Spec.KubernetesVersion

	if kubernetesVersion == "" {
		klog.Fatalf("KubernetesVersion is required")
	}

	sv, err := util.ParseKubernetesVersion(kubernetesVersion)
	if err != nil || sv == nil {
		klog.Fatalf("unable to determine kubernetes version from %q: %v", kubernetesVersion, err)
	}
	return *sv
}

// IsKubernetesGTE checks if the kubernetes version is at least version, ignoring prereleases / patches
func (m *KopsModelContext) IsKubernetesGTE(version string) bool {
	return util.IsKubernetesGTE(version, m.KubernetesVersion())
}

// IsKubernetesLT checks if the kubernetes version is before the specified version, ignoring prereleases / patches
func (m *KopsModelContext) IsKubernetesLT(version string) bool {
	return !m.IsKubernetesGTE(version)
}

// WellKnownServiceIP returns a service ip with the service cidr
func (m *KopsModelContext) WellKnownServiceIP(id int) (net.IP, error) {
	return components.WellKnownServiceIP(&m.Cluster.Spec, id)
}

// NodePortRange returns the range of ports allocated to NodePorts
func (m *KopsModelContext) NodePortRange() (utilnet.PortRange, error) {
	// defaultServiceNodePortRange is the default port range for NodePort services.
	defaultServiceNodePortRange := utilnet.PortRange{Base: 30000, Size: 2768}

	kubeApiServer := m.Cluster.Spec.KubeAPIServer
	if kubeApiServer != nil && kubeApiServer.ServiceNodePortRange != "" {
		err := defaultServiceNodePortRange.Set(kubeApiServer.ServiceNodePortRange)
		if err != nil {
			return utilnet.PortRange{}, fmt.Errorf("error parsing ServiceNodePortRange %q", kubeApiServer.ServiceNodePortRange)
		}
	}

	return defaultServiceNodePortRange, nil
}

// UseServiceAccountIAM returns true if we are using service-account bound IAM roles.
func (m *KopsModelContext) UseServiceAccountIAM() bool {
	return featureflag.UseServiceAccountIAM.Enabled()
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 nodejs contains Node.js buildpack library code.
package nodejs

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
	"github.com/buildpack/libbuildpack/layers"
)

const (
	// EnvDevelopment represents a NODE_ENV development value.
	EnvDevelopment = "development"
	// EnvProduction represents a NODE_ENV production value.
	EnvProduction = "production"
)

type packageEnginesJSON struct {
	Node string `json:"node"`
}

type packageScriptsJSON struct {
	Start    string `json:"start"`
	GCPBuild string `json:"gcp-build"`
}

// PackageJSON represents the contents of a package.json file.
type PackageJSON struct {
	Main            string             `json:"main"`
	Version         string             `json:"version"`
	Engines         packageEnginesJSON `json:"engines"`
	Scripts         packageScriptsJSON `json:"scripts"`
	Dependencies    map[string]string  `json:"dependencies"`
	DevDependencies map[string]string  `json:"devDependencies"`
}

// Metadata represents metadata stored for a dependencies layer.
type Metadata struct {
	NodeVersion    string `toml:"node_version"`
	DependencyHash string `toml:"dependency_hash"`
}

// ReadPackageJSON returns deserialized package.json from the given dir. Empty dir uses the current working directory.
func ReadPackageJSON(dir string) (*PackageJSON, error) {
	f := filepath.Join(dir, "package.json")
	rawpjs, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, gcp.InternalErrorf("reading package.json: %v", err)
	}
	var pjs PackageJSON
	if err := json.Unmarshal(rawpjs, &pjs); err != nil {
		return nil, gcp.UserErrorf("unmarshalling package.json: %v", err)
	}
	return &pjs, nil
}

// NodeVersion returns the installed version of Node.js.
func NodeVersion(ctx *gcp.Context) string {
	result := ctx.Exec([]string{"node", "-v"})
	return result.Stdout
}

// NodeEnv returns the value of NODE_ENV or `production`.
func NodeEnv() string {
	nodeEnv := os.Getenv("NODE_ENV")
	if nodeEnv == "" {
		nodeEnv = EnvProduction
	}
	return nodeEnv
}

// CheckCache checks whether cached dependencies exist and match.
func CheckCache(ctx *gcp.Context, l *layers.Layer, env string, files ...string) (bool, *Metadata, error) {
	currentNodeVersion := NodeVersion(ctx)

	components := []interface{}{currentNodeVersion, env}
	for _, f := range files {
		components = append(components, f)
	}
	currentDependencyHash, err := gcp.ComputeSHA256(ctx, components...)
	if err != nil {
		return false, nil, fmt.Errorf("computing dependency hash: %v", err)
	}

	var meta Metadata
	ctx.ReadMetadata(l, &meta)

	// Perform install, skipping if the dependency hash matches existing metadata.
	ctx.Debugf("Current dependency hash: %q", currentDependencyHash)
	ctx.Debugf("  Cache dependency hash: %q", meta.DependencyHash)
	if currentDependencyHash == meta.DependencyHash {
		ctx.Logf("Dependencies cache hit, skipping installation.")
		return true, &meta, nil
	}

	if meta.DependencyHash == "" {
		ctx.Debugf("No metadata found from a previous build, skipping cache.")
	}
	ctx.Logf("Installing application dependencies.")
	// Update the layer metadata.
	meta.DependencyHash = currentDependencyHash
	meta.NodeVersion = currentNodeVersion

	return false, &meta, nil
}
<commit_msg>Correctly hash file contents instead of file names in npm/yarn buildpacks<commit_after>// Copyright 2020 Google LLC
//
// 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 nodejs contains Node.js buildpack library code.
package nodejs

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack"
	"github.com/buildpack/libbuildpack/layers"
)

const (
	// EnvDevelopment represents a NODE_ENV development value.
	EnvDevelopment = "development"
	// EnvProduction represents a NODE_ENV production value.
	EnvProduction = "production"
)

type packageEnginesJSON struct {
	Node string `json:"node"`
}

type packageScriptsJSON struct {
	Start    string `json:"start"`
	GCPBuild string `json:"gcp-build"`
}

// PackageJSON represents the contents of a package.json file.
type PackageJSON struct {
	Main            string             `json:"main"`
	Version         string             `json:"version"`
	Engines         packageEnginesJSON `json:"engines"`
	Scripts         packageScriptsJSON `json:"scripts"`
	Dependencies    map[string]string  `json:"dependencies"`
	DevDependencies map[string]string  `json:"devDependencies"`
}

// Metadata represents metadata stored for a dependencies layer.
type Metadata struct {
	NodeVersion    string `toml:"node_version"`
	DependencyHash string `toml:"dependency_hash"`
}

// ReadPackageJSON returns deserialized package.json from the given dir. Empty dir uses the current working directory.
func ReadPackageJSON(dir string) (*PackageJSON, error) {
	f := filepath.Join(dir, "package.json")
	rawpjs, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, gcp.InternalErrorf("reading package.json: %v", err)
	}
	var pjs PackageJSON
	if err := json.Unmarshal(rawpjs, &pjs); err != nil {
		return nil, gcp.UserErrorf("unmarshalling package.json: %v", err)
	}
	return &pjs, nil
}

// NodeVersion returns the installed version of Node.js.
func NodeVersion(ctx *gcp.Context) string {
	result := ctx.Exec([]string{"node", "-v"})
	return result.Stdout
}

// NodeEnv returns the value of NODE_ENV or `production`.
func NodeEnv() string {
	nodeEnv := os.Getenv("NODE_ENV")
	if nodeEnv == "" {
		nodeEnv = EnvProduction
	}
	return nodeEnv
}

// CheckCache checks whether cached dependencies exist and match.
func CheckCache(ctx *gcp.Context, l *layers.Layer, env string, files ...string) (bool, *Metadata, error) {
	currentNodeVersion := NodeVersion(ctx)

	components := []interface{}{currentNodeVersion, env}
	for _, f := range files {
		components = append(components, gcp.HashFileContents(f))
	}
	currentDependencyHash, err := gcp.ComputeSHA256(ctx, components...)
	if err != nil {
		return false, nil, fmt.Errorf("computing dependency hash: %v", err)
	}

	var meta Metadata
	ctx.ReadMetadata(l, &meta)

	// Perform install, skipping if the dependency hash matches existing metadata.
	ctx.Debugf("Current dependency hash: %q", currentDependencyHash)
	ctx.Debugf("  Cache dependency hash: %q", meta.DependencyHash)
	if currentDependencyHash == meta.DependencyHash {
		ctx.Logf("Dependencies cache hit, skipping installation.")
		return true, &meta, nil
	}

	if meta.DependencyHash == "" {
		ctx.Debugf("No metadata found from a previous build, skipping cache.")
	}
	ctx.Logf("Installing application dependencies.")
	// Update the layer metadata.
	meta.DependencyHash = currentDependencyHash
	meta.NodeVersion = currentNodeVersion

	return false, &meta, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package proxy

import (
	"fmt"
	"io"
	"net"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/golang/glog"
)

// Proxier is a simple proxy for tcp connections between a localhost:lport and services that provide
// the actual implementations.
type Proxier struct {
	loadBalancer LoadBalancer
	serviceMap   map[string]int
}

func NewProxier(loadBalancer LoadBalancer) *Proxier {
	return &Proxier{loadBalancer: loadBalancer, serviceMap: make(map[string]int)}
}

func CopyBytes(in, out *net.TCPConn) {
	glog.Infof("Copying from %v <-> %v <-> %v <-> %v",
		in.RemoteAddr(), in.LocalAddr(), out.LocalAddr(), out.RemoteAddr())
	_, err := io.Copy(in, out)
	if err != nil && err != io.EOF {
		glog.Errorf("I/O error: %v", err)
	}

	in.CloseRead()
	out.CloseWrite()
}

// Create a bidirectional byte shuffler. Copies bytes to/from each connection.
func ProxyConnection(in, out *net.TCPConn) {
	glog.Infof("Creating proxy between %v <-> %v <-> %v <-> %v",
		in.RemoteAddr(), in.LocalAddr(), out.LocalAddr(), out.RemoteAddr())
	go CopyBytes(in, out)
	go CopyBytes(out, in)
}

func (proxier Proxier) AcceptHandler(service string, listener net.Listener) {
	for {
		inConn, err := listener.Accept()
		if err != nil {
			glog.Errorf("Accept failed: %v", err)
			continue
		}
		glog.Infof("Accepted connection from: %v to %v", inConn.RemoteAddr(), inConn.LocalAddr())

		// Figure out where this request should go.
		endpoint, err := proxier.loadBalancer.LoadBalance(service, inConn.RemoteAddr())
		if err != nil {
			glog.Errorf("Couldn't find an endpoint for %s %v", service, err)
			inConn.Close()
			continue
		}

		glog.Infof("Mapped service %s to endpoint %s", service, endpoint)
		outConn, err := net.DialTimeout("tcp", endpoint, time.Duration(5)*time.Second)
		// We basically need to take everything from inConn and send to outConn
		// and anything coming from outConn needs to be sent to inConn.
		if err != nil {
			glog.Errorf("Dial failed: %v", err)
			inConn.Close()
			continue
		}
		go ProxyConnection(inConn.(*net.TCPConn), outConn.(*net.TCPConn))
	}
}

// AddService starts listening for a new service on a given port.
func (proxier Proxier) AddService(service string, port int) error {
	// Make sure we can start listening on the port before saying all's well.
	l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return err
	}
	proxier.addServiceCommon(service, l)
	return nil
}

// addService starts listening for a new service, returning the port it's using.
// For testing on a system with unknown ports used.
func (proxier Proxier) addServiceOnUnusedPort(service string) (string, error) {
	// Make sure we can start listening on the port before saying all's well.
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		return "", err
	}
	proxier.addServiceCommon(service, l)
	_, port, err := net.SplitHostPort(l.Addr().String())
	return port, nil
}

func (proxier Proxier) addServiceCommon(service string, l net.Listener) {
	glog.Infof("Listening for %s on %s", service, l.Addr().String())
	// If that succeeds, start the accepting loop.
	go proxier.AcceptHandler(service, l)
}

func (proxier Proxier) OnUpdate(services []api.Service) {
	glog.Infof("Received update notice: %+v", services)
	for _, service := range services {
		port, exists := proxier.serviceMap[service.ID]
		if !exists || port != service.Port {
			glog.Infof("Adding a new service %s on port %d", service.ID, service.Port)
			err := proxier.AddService(service.ID, service.Port)
			if err == nil {
				proxier.serviceMap[service.ID] = service.Port
			} else {
				glog.Infof("Failed to start listening for %s on %d", service.ID, service.Port)
			}
		}
	}
}
<commit_msg>pkg/proxy: remove unnecessary go routine<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package proxy

import (
	"fmt"
	"io"
	"net"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/golang/glog"
)

// Proxier is a simple proxy for tcp connections between a localhost:lport and services that provide
// the actual implementations.
type Proxier struct {
	loadBalancer LoadBalancer
	serviceMap   map[string]int
}

func NewProxier(loadBalancer LoadBalancer) *Proxier {
	return &Proxier{loadBalancer: loadBalancer, serviceMap: make(map[string]int)}
}

func CopyBytes(in, out *net.TCPConn) {
	glog.Infof("Copying from %v <-> %v <-> %v <-> %v",
		in.RemoteAddr(), in.LocalAddr(), out.LocalAddr(), out.RemoteAddr())
	_, err := io.Copy(in, out)
	if err != nil && err != io.EOF {
		glog.Errorf("I/O error: %v", err)
	}

	in.CloseRead()
	out.CloseWrite()
}

// Create a bidirectional byte shuffler. Copies bytes to/from each connection.
func ProxyConnection(in, out *net.TCPConn) {
	glog.Infof("Creating proxy between %v <-> %v <-> %v <-> %v",
		in.RemoteAddr(), in.LocalAddr(), out.LocalAddr(), out.RemoteAddr())
	go CopyBytes(in, out)
	go CopyBytes(out, in)
}

func (proxier Proxier) AcceptHandler(service string, listener net.Listener) {
	for {
		inConn, err := listener.Accept()
		if err != nil {
			glog.Errorf("Accept failed: %v", err)
			continue
		}
		glog.Infof("Accepted connection from: %v to %v", inConn.RemoteAddr(), inConn.LocalAddr())

		// Figure out where this request should go.
		endpoint, err := proxier.loadBalancer.LoadBalance(service, inConn.RemoteAddr())
		if err != nil {
			glog.Errorf("Couldn't find an endpoint for %s %v", service, err)
			inConn.Close()
			continue
		}

		glog.Infof("Mapped service %s to endpoint %s", service, endpoint)
		outConn, err := net.DialTimeout("tcp", endpoint, time.Duration(5)*time.Second)
		// We basically need to take everything from inConn and send to outConn
		// and anything coming from outConn needs to be sent to inConn.
		if err != nil {
			glog.Errorf("Dial failed: %v", err)
			inConn.Close()
			continue
		}
		ProxyConnection(inConn.(*net.TCPConn), outConn.(*net.TCPConn))
	}
}

// AddService starts listening for a new service on a given port.
func (proxier Proxier) AddService(service string, port int) error {
	// Make sure we can start listening on the port before saying all's well.
	l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		return err
	}
	proxier.addServiceCommon(service, l)
	return nil
}

// addService starts listening for a new service, returning the port it's using.
// For testing on a system with unknown ports used.
func (proxier Proxier) addServiceOnUnusedPort(service string) (string, error) {
	// Make sure we can start listening on the port before saying all's well.
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		return "", err
	}
	proxier.addServiceCommon(service, l)
	_, port, err := net.SplitHostPort(l.Addr().String())
	return port, nil
}

func (proxier Proxier) addServiceCommon(service string, l net.Listener) {
	glog.Infof("Listening for %s on %s", service, l.Addr().String())
	// If that succeeds, start the accepting loop.
	go proxier.AcceptHandler(service, l)
}

func (proxier Proxier) OnUpdate(services []api.Service) {
	glog.Infof("Received update notice: %+v", services)
	for _, service := range services {
		port, exists := proxier.serviceMap[service.ID]
		if !exists || port != service.Port {
			glog.Infof("Adding a new service %s on port %d", service.ID, service.Port)
			err := proxier.AddService(service.ID, service.Port)
			if err == nil {
				proxier.serviceMap[service.ID] = service.Port
			} else {
				glog.Infof("Failed to start listening for %s on %d", service.ID, service.Port)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/olebedev/go-duktape"
)

type ReactRendererDuktape struct {
	count int
	vms   chan *reactRendererDuktapeVM
}

func NewReactRendererDuktape(count int) *ReactRendererDuktape {
	vms := make(chan *reactRendererDuktapeVM, count)
	for i := 0; i < count; i++ {
		vms <- nil
	}

	return &ReactRendererDuktape{
		count: count,
		vms:   vms,
	}
}

func (r *ReactRendererDuktape) Render(code, inputURL, inputJSON string) (string, error) {
	var html string

	if err := r.withVM(code, func(vm *duktape.Context) error {
		if err := vm.PevalString("module.exports"); err != nil {
			return err
		}

		vm.PushString(inputURL)
		vm.PushString(inputJSON)
		if rc := vm.Pcall(2); rc != 0 {
			return fmt.Errorf("ReactRendererDuktape.Render: error rendering app: %s", vm.SafeToString(-1))
		}
		html = vm.SafeToString(-1)
		vm.Pop()

		return nil
	}); err != nil {
		return "", err
	}

	return html, nil
}

type reactRendererDuktapeVM struct {
	vm   *duktape.Context
	code string
}

func (r *ReactRendererDuktape) withVM(code string, fn func(vm *duktape.Context) error) error {
	vm := <-r.vms
	defer func() {
		r.vms <- vm
	}()

	defer func() {
		if e := recover(); e != nil {
			vm = nil
		}
	}()

	if vm != nil && vm.code != code {
		vm.vm.DestroyHeap()
		vm = nil
	}

	if vm == nil {
		c := duktape.New()

		if err := c.PevalString(`console = { log: function() {} }; module = { exports: null };`); err != nil {
			return err
		}

		if err := c.PevalString(code); err != nil {
			return err
		}

		vm = &reactRendererDuktapeVM{code: code, vm: c}
	}

	if err := fn(vm.vm); err != nil {
		vm.vm.DestroyHeap()
		vm = nil
		return err
	}

	return nil
}
<commit_msg>mock more console methods in duktape<commit_after>package main

import (
	"fmt"

	"github.com/olebedev/go-duktape"
)

type ReactRendererDuktape struct {
	count int
	vms   chan *reactRendererDuktapeVM
}

func NewReactRendererDuktape(count int) *ReactRendererDuktape {
	vms := make(chan *reactRendererDuktapeVM, count)
	for i := 0; i < count; i++ {
		vms <- nil
	}

	return &ReactRendererDuktape{
		count: count,
		vms:   vms,
	}
}

func (r *ReactRendererDuktape) Render(code, inputURL, inputJSON string) (string, error) {
	var html string

	if err := r.withVM(code, func(vm *duktape.Context) error {
		if err := vm.PevalString("module.exports"); err != nil {
			return err
		}

		vm.PushString(inputURL)
		vm.PushString(inputJSON)
		if rc := vm.Pcall(2); rc != 0 {
			return fmt.Errorf("ReactRendererDuktape.Render: error rendering app: %s", vm.SafeToString(-1))
		}
		html = vm.SafeToString(-1)
		vm.Pop()

		return nil
	}); err != nil {
		return "", err
	}

	return html, nil
}

type reactRendererDuktapeVM struct {
	vm   *duktape.Context
	code string
}

func (r *ReactRendererDuktape) withVM(code string, fn func(vm *duktape.Context) error) error {
	vm := <-r.vms
	defer func() {
		r.vms <- vm
	}()

	defer func() {
		if e := recover(); e != nil {
			vm = nil
		}
	}()

	if vm != nil && vm.code != code {
		vm.vm.DestroyHeap()
		vm = nil
	}

	if vm == nil {
		c := duktape.New()

		if err := c.PevalString(`
			console = {
				log: function() {},
				warn: function() {},
				error: function() {},
				debug: function() {},
			};

			module = { exports: null };
		`); err != nil {
			return err
		}

		if err := c.PevalString(code); err != nil {
			return err
		}

		vm = &reactRendererDuktapeVM{code: code, vm: c}
	}

	if err := fn(vm.vm); err != nil {
		vm.vm.DestroyHeap()
		vm = nil
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"gopkg.in/yaml.v2"
)

const (
	PortBindingRegexp = `"?\d+:(\d+)"?`
)

var (
	PortBinding = regexp.MustCompile(PortBindingRegexp)
)

type ComposeFile struct {
	filePath string
	Yaml     map[interface{}]interface{}
}

func NewComposeFile(composeFilePath string) (*ComposeFile, error) {
	buf, err := ioutil.ReadFile(composeFilePath)

	if err != nil {
		return nil, err
	}

	m := make(map[interface{}]interface{})
	err = yaml.Unmarshal(buf, &m)

	if err != nil {
		return nil, err
	}

	return &ComposeFile{composeFilePath, m}, nil
}

func (c *ComposeFile) buildArgs(service map[interface{}]interface{}) []interface{} {
	b := service["build"].(map[interface{}]interface{})["arg"]

	if b == nil {
		return []interface{}{}
	}

	return b.([]interface{})
}

func (c *ComposeFile) buildArgsMap(buildArgs []interface{}) map[string]string {
	result := map[string]string{}

	for _, buildArgString := range buildArgs {
		splited := strings.Split(buildArgString.(string), "=")
		key, value := splited[0], strings.Join(splited[1:], "=")
		result[key] = value
	}

	return result
}

func (c *ComposeFile) environment(service map[interface{}]interface{}) []interface{} {
	e := service["environment"]

	if e == nil {
		return []interface{}{}
	}

	return e.([]interface{})
}

func (c *ComposeFile) environmentMap(environment []interface{}) map[string]string {
	result := map[string]string{}

	for _, envString := range environment {
		splited := strings.Split(envString.(string), "=")
		key, value := splited[0], strings.Join(splited[1:], "=")
		result[key] = value
	}

	return result
}

func (c *ComposeFile) isVersion2() bool {
	return c.Yaml["version"] != nil && c.Yaml["version"] == "2"
}

func (c *ComposeFile) service(serviceName string) map[interface{}]interface{} {
	if c.isVersion2() {
		return c.Yaml["services"].(map[interface{}]interface{})[serviceName].(map[interface{}]interface{})
	}

	return c.Yaml[serviceName].(map[interface{}]interface{})
}

func (c *ComposeFile) serviceList() []string {
	var (
		services     map[interface{}]interface{}
		serviceNames []string
	)

	if c.isVersion2() {
		services = c.Yaml["services"].(map[interface{}]interface{})
	} else {
		services = c.Yaml
	}

	for name, _ := range services {
		serviceNames = append(serviceNames, name.(string))
	}

	return serviceNames
}

func (c *ComposeFile) transformBuildToMap(service map[interface{}]interface{}) {
	build := service["build"]

	switch b := build.(type) {
	case map[interface{}]interface{}:
		// build:
		//   context: .
		//   arg:
		//     - FOO=bar

		return

	case string:
		// build: .

		newBuild := map[interface{}]interface{}{
			"context": b,
		}
		service["build"] = newBuild
	}
}

func (c *ComposeFile) InjectBuildArgs(buildArgs map[string]string) {
	var buildArgString string

	if !c.isVersion2() || len(buildArgs) == 0 {
		return
	}

	webService := c.service("web")

	if webService["build"] == nil {
		return
	}

	c.transformBuildToMap(webService)

	b := c.buildArgs(webService)
	buildArgsMap := c.buildArgsMap(b)

	for key, value := range buildArgs {
		buildArgsMap[key] = value
	}

	newBuildArgs := []interface{}{}

	for key, value := range buildArgsMap {
		buildArgString = key + "=" + value
		newBuildArgs = append(newBuildArgs, buildArgString)
	}

	webService["build"].(map[interface{}]interface{})["arg"] = newBuildArgs
}

func (c *ComposeFile) InjectEnvironmentVariables(environmentVariables map[string]string) {
	var envString string

	webService := c.service("web")
	environment := c.environment(webService)
	environmentMap := c.environmentMap(environment)

	for key, value := range environmentVariables {
		environmentMap[key] = value
	}

	newEnvironment := []interface{}{}

	for key, value := range environmentMap {
		envString = key + "=" + value
		newEnvironment = append(newEnvironment, envString)
	}

	webService["environment"] = newEnvironment
}

func (c *ComposeFile) RewritePortBindings() {
	var portString string

	for _, serviceName := range c.serviceList() {
		service := c.service(serviceName)
		newPorts := []interface{}{}

		if service["ports"] == nil {
			continue
		}

		for _, port := range service["ports"].([]interface{}) {
			switch p := port.(type) {
			case int:
				portString = strconv.Itoa(p)
			case string:
				portString = p
			}

			matchResult := PortBinding.FindStringSubmatch(portString)

			if len(matchResult) == 2 {
				newPorts = append(newPorts, matchResult[1])
			} else {
				newPorts = append(newPorts, portString)
			}
		}

		service["ports"] = newPorts
	}
}

func (c *ComposeFile) SaveAs(filePath string) error {
	data, err := yaml.Marshal(c.Yaml)

	if err != nil {
		return err
	}

	if err = ioutil.WriteFile(filePath, data, 0644); err != nil {
		return err
	}

	return nil
}
<commit_msg>Skip if passed environmentVariables is empty<commit_after>package main

import (
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"gopkg.in/yaml.v2"
)

const (
	PortBindingRegexp = `"?\d+:(\d+)"?`
)

var (
	PortBinding = regexp.MustCompile(PortBindingRegexp)
)

type ComposeFile struct {
	filePath string
	Yaml     map[interface{}]interface{}
}

func NewComposeFile(composeFilePath string) (*ComposeFile, error) {
	buf, err := ioutil.ReadFile(composeFilePath)

	if err != nil {
		return nil, err
	}

	m := make(map[interface{}]interface{})
	err = yaml.Unmarshal(buf, &m)

	if err != nil {
		return nil, err
	}

	return &ComposeFile{composeFilePath, m}, nil
}

func (c *ComposeFile) buildArgs(service map[interface{}]interface{}) []interface{} {
	b := service["build"].(map[interface{}]interface{})["arg"]

	if b == nil {
		return []interface{}{}
	}

	return b.([]interface{})
}

func (c *ComposeFile) buildArgsMap(buildArgs []interface{}) map[string]string {
	result := map[string]string{}

	for _, buildArgString := range buildArgs {
		splited := strings.Split(buildArgString.(string), "=")
		key, value := splited[0], strings.Join(splited[1:], "=")
		result[key] = value
	}

	return result
}

func (c *ComposeFile) environment(service map[interface{}]interface{}) []interface{} {
	e := service["environment"]

	if e == nil {
		return []interface{}{}
	}

	return e.([]interface{})
}

func (c *ComposeFile) environmentMap(environment []interface{}) map[string]string {
	result := map[string]string{}

	for _, envString := range environment {
		splited := strings.Split(envString.(string), "=")
		key, value := splited[0], strings.Join(splited[1:], "=")
		result[key] = value
	}

	return result
}

func (c *ComposeFile) isVersion2() bool {
	return c.Yaml["version"] != nil && c.Yaml["version"] == "2"
}

func (c *ComposeFile) service(serviceName string) map[interface{}]interface{} {
	if c.isVersion2() {
		return c.Yaml["services"].(map[interface{}]interface{})[serviceName].(map[interface{}]interface{})
	}

	return c.Yaml[serviceName].(map[interface{}]interface{})
}

func (c *ComposeFile) serviceList() []string {
	var (
		services     map[interface{}]interface{}
		serviceNames []string
	)

	if c.isVersion2() {
		services = c.Yaml["services"].(map[interface{}]interface{})
	} else {
		services = c.Yaml
	}

	for name, _ := range services {
		serviceNames = append(serviceNames, name.(string))
	}

	return serviceNames
}

func (c *ComposeFile) transformBuildToMap(service map[interface{}]interface{}) {
	build := service["build"]

	switch b := build.(type) {
	case map[interface{}]interface{}:
		// build:
		//   context: .
		//   arg:
		//     - FOO=bar

		return

	case string:
		// build: .

		newBuild := map[interface{}]interface{}{
			"context": b,
		}
		service["build"] = newBuild
	}
}

func (c *ComposeFile) InjectBuildArgs(buildArgs map[string]string) {
	var buildArgString string

	if !c.isVersion2() || len(buildArgs) == 0 {
		return
	}

	webService := c.service("web")

	if webService["build"] == nil {
		return
	}

	c.transformBuildToMap(webService)

	b := c.buildArgs(webService)
	buildArgsMap := c.buildArgsMap(b)

	for key, value := range buildArgs {
		buildArgsMap[key] = value
	}

	newBuildArgs := []interface{}{}

	for key, value := range buildArgsMap {
		buildArgString = key + "=" + value
		newBuildArgs = append(newBuildArgs, buildArgString)
	}

	webService["build"].(map[interface{}]interface{})["arg"] = newBuildArgs
}

func (c *ComposeFile) InjectEnvironmentVariables(environmentVariables map[string]string) {
	var envString string

	if len(environmentVariables) == 0 {
		return
	}

	webService := c.service("web")
	environment := c.environment(webService)
	environmentMap := c.environmentMap(environment)

	for key, value := range environmentVariables {
		environmentMap[key] = value
	}

	newEnvironment := []interface{}{}

	for key, value := range environmentMap {
		envString = key + "=" + value
		newEnvironment = append(newEnvironment, envString)
	}

	webService["environment"] = newEnvironment
}

func (c *ComposeFile) RewritePortBindings() {
	var portString string

	for _, serviceName := range c.serviceList() {
		service := c.service(serviceName)
		newPorts := []interface{}{}

		if service["ports"] == nil {
			continue
		}

		for _, port := range service["ports"].([]interface{}) {
			switch p := port.(type) {
			case int:
				portString = strconv.Itoa(p)
			case string:
				portString = p
			}

			matchResult := PortBinding.FindStringSubmatch(portString)

			if len(matchResult) == 2 {
				newPorts = append(newPorts, matchResult[1])
			} else {
				newPorts = append(newPorts, portString)
			}
		}

		service["ports"] = newPorts
	}
}

func (c *ComposeFile) SaveAs(filePath string) error {
	data, err := yaml.Marshal(c.Yaml)

	if err != nil {
		return err
	}

	if err = ioutil.WriteFile(filePath, data, 0644); err != nil {
		return err
	}

	return nil
}
<|endoftext|>