<commit_before>/*
Copyright 2018 The Skaffold 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 docker

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"

	latest "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha4"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/docker/docker/builder/dockerignore"
	"github.com/docker/docker/pkg/fileutils"
	"github.com/google/go-containerregistry/pkg/v1"
	"github.com/karrick/godirwalk"
	"github.com/moby/buildkit/frontend/dockerfile/command"
	"github.com/moby/buildkit/frontend/dockerfile/parser"
	"github.com/moby/buildkit/frontend/dockerfile/shell"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type from struct {
	image string
	as    string
}

// RetrieveImage is overridden for unit testing
var RetrieveImage = retrieveImage

func ValidateDockerfile(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		logrus.Warnf("opening file %s: %s", path, err.Error())
		return false
	}
	res, err := parser.Parse(f)
	if err != nil || res == nil || len(res.AST.Children) == 0 {
		return false
	}
	// validate each node contains valid dockerfile directive
	for _, child := range res.AST.Children {
		_, ok := command.Commands[child.Value]
		if !ok {
			return false
		}
	}

	return true
}

func expandBuildArgs(nodes []*parser.Node, buildArgs map[string]*string) {
	for i, node := range nodes {
		if node.Value != command.Arg {
			continue
		}

		// build arg's key
		keyValue := strings.Split(node.Next.Value, "=")
		key := keyValue[0]

		// build arg's value
		var value string
		if buildArgs[key] != nil {
			value = *buildArgs[key]
		} else if len(keyValue) > 1 {
			value = keyValue[1]
		}

		for _, node := range nodes[i+1:] {
			// Stop replacements if an arg is redefined with the same key
			if node.Value == command.Arg && strings.Split(node.Next.Value, "=")[0] == key {
				break
			}

			// replace $key with value
			for curr := node; curr != nil; curr = curr.Next {
				curr.Value = util.Expand(curr.Value, key, value)
			}
		}
	}
}

func fromInstructions(nodes []*parser.Node) []from {
	var list []from

	for _, node := range nodes {
		if node.Value == command.From {
			list = append(list, fromInstruction(node))
		}
	}

	return list
}

func fromInstruction(node *parser.Node) from {
	var as string
	if next := node.Next.Next; next != nil && strings.ToLower(next.Value) == "as" && next.Next != nil {
		as = next.Next.Value
	}

	return from{
		image: strings.ToLower(node.Next.Value),
		as:    strings.ToLower(as),
	}
}

func onbuildImages(nodes []*parser.Node) [][]string {
	var images [][]string

	stages := map[string]bool{}
	for _, from := range fromInstructions(nodes) {
		stages[from.as] = true

		if from.image == "scratch" {
			continue
		}

		if _, found := stages[from.image]; found {
			continue
		}

		logrus.Debugf("Checking base image %s for ONBUILD triggers.", from.image)
		img, err := RetrieveImage(from.image)
		if err != nil {
			logrus.Warnf("Error processing base image for ONBUILD triggers: %s. Dependencies may be incomplete.", err)
			continue
		}

		logrus.Debugf("Found ONBUILD triggers %v in image %s", img.Config.OnBuild, from.image)
		images = append(images, img.Config.OnBuild)
	}

	return images
}

func readDockerfile(workspace, absDockerfilePath string, buildArgs map[string]*string) ([]string, error) {
	f, err := os.Open(absDockerfilePath)
	if err != nil {
		return nil, errors.Wrapf(err, "opening dockerfile: %s", absDockerfilePath)
	}
	defer f.Close()

	res, err := parser.Parse(f)
	if err != nil {
		return nil, errors.Wrap(err, "parsing dockerfile")
	}

	expandBuildArgs(res.AST.Children, buildArgs)
	onbuildImages := onbuildImages(res.AST.Children)

	var copied [][]string
	envs := map[string]string{}

	var dispatchInstructions = func(r *parser.Result) {
		for _, value := range r.AST.Children {
			switch value.Value {
			case command.Add, command.Copy:
				files, _ := processCopy(value, envs)
				if len(files) > 0 {
					copied = append(copied, files)
				}
			case command.Env:
				envs[value.Next.Value] = value.Next.Next.Value
			}
		}
	}
	for _, image := range onbuildImages {
		for _, ob := range image {
			obRes, err := parser.Parse(strings.NewReader(ob))
			if err != nil {
				return nil, err
			}
			dispatchInstructions(obRes)
		}
	}

	dispatchInstructions(res)

	expandedPaths := make(map[string]bool)
	for _, files := range copied {
		matchesOne := false

		for _, p := range files {
			path := filepath.Join(workspace, p)
			if _, err := os.Stat(path); err == nil {
				expandedPaths[p] = true
				matchesOne = true
				continue
			}

			files, err := filepath.Glob(path)
			if err != nil {
				return nil, errors.Wrap(err, "invalid glob pattern")
			}
			if files == nil {
				continue
			}

			for _, f := range files {
				rel, err := filepath.Rel(workspace, f)
				if err != nil {
					return nil, fmt.Errorf("getting relative path of %s", f)
				}

				expandedPaths[rel] = true
			}
			matchesOne = true
		}

		if !matchesOne {
			return nil, fmt.Errorf("file pattern %s must match at least one file", files)
		}
	}

	var deps []string
	for dep := range expandedPaths {
		deps = append(deps, dep)
	}
	logrus.Infof("Found dependencies for dockerfile %s", deps)

	return deps, nil
}

// GetDependencies finds the sources dependencies for the given docker artifact.
// All paths are relative to the workspace.
func GetDependencies(workspace string, a *latest.DockerArtifact) ([]string, error) {
	absDockerfilePath, err := NormalizeDockerfilePath(workspace, a.DockerfilePath)
	if err != nil {
		return nil, errors.Wrap(err, "normalizing dockerfile path")
	}

	deps, err := readDockerfile(workspace, absDockerfilePath, a.BuildArgs)
	if err != nil {
		return nil, err
	}

	// Read patterns to ignore
	var excludes []string
	dockerignorePath := filepath.Join(workspace, ".dockerignore")
	if _, err := os.Stat(dockerignorePath); !os.IsNotExist(err) {
		r, err := os.Open(dockerignorePath)
		if err != nil {
			return nil, err
		}
		defer r.Close()

		excludes, err = dockerignore.ReadAll(r)
		if err != nil {
			return nil, err
		}
	}

	pExclude, err := fileutils.NewPatternMatcher(excludes)
	if err != nil {
		return nil, errors.Wrap(err, "invalid exclude patterns")
	}

	// Walk the workspace
	files := make(map[string]bool)
	for _, dep := range deps {
		dep = filepath.Clean(dep)
		absDep := filepath.Join(workspace, dep)

		fi, err := os.Stat(absDep)
		if err != nil {
			return nil, errors.Wrapf(err, "stating file %s", absDep)
		}

		switch mode := fi.Mode(); {
		case mode.IsDir():
			if err := godirwalk.Walk(absDep, &godirwalk.Options{
				Unsorted: true,
				Callback: func(fpath string, info *godirwalk.Dirent) error {
					relPath, err := filepath.Rel(workspace, fpath)
					if err != nil {
						return err
					}

					ignored, err := pExclude.Matches(relPath)
					if err != nil {
						return err
					}

					if info.IsDir() {
						if ignored {
							return filepath.SkipDir
						}
					} else if !ignored {
						files[relPath] = true
					}

					return nil
				},
			}); err != nil {
				return nil, errors.Wrapf(err, "walking folder %s", absDep)
			}
		case mode.IsRegular():
			ignored, err := pExclude.Matches(dep)
			if err != nil {
				return nil, err
			}

			if !ignored {
				files[dep] = true
			}
		}
	}

	// Always add dockerfile even if it's .dockerignored. The daemon will need it anyways.
	if !filepath.IsAbs(a.DockerfilePath) {
		files[a.DockerfilePath] = true
	} else {
		files[absDockerfilePath] = true
	}

	// Ignore .dockerignore
	delete(files, ".dockerignore")

	var dependencies []string
	for file := range files {
		dependencies = append(dependencies, file)
	}
	sort.Strings(dependencies)

	return dependencies, nil
}

var imageCache sync.Map

func retrieveImage(image string) (*v1.ConfigFile, error) {
	cachedCfg, present := imageCache.Load(image)
	if present {
		return cachedCfg.(*v1.ConfigFile), nil
	}

	client, err := NewAPIClient()
	if err != nil {
		return nil, err
	}

	cfg := &v1.ConfigFile{}
	raw, err := retrieveLocalImage(client, image)
	if err == nil {
		if err := json.Unmarshal(raw, cfg); err != nil {
			return nil, err
		}
	} else {
		cfg, err = retrieveRemoteConfig(image)
		if err != nil {
			return nil, errors.Wrap(err, "getting remote config")
		}
	}

	imageCache.Store(image, cfg)

	return cfg, nil
}

func retrieveLocalImage(client APIClient, image string) ([]byte, error) {
	_, raw, err := client.ImageInspectWithRaw(context.Background(), image)
	if err != nil {
		return nil, err
	}

	return raw, nil
}

func retrieveRemoteConfig(identifier string) (*v1.ConfigFile, error) {
	img, err := remoteImage(identifier)
	if err != nil {
		return nil, errors.Wrap(err, "getting image")
	}

	return img.ConfigFile()
}

func processCopy(value *parser.Node, envs map[string]string) ([]string, error) {
	var copied []string

	slex := shell.NewLex('\\')
	for {
		// Skip last node, since it is the destination, and stop if we arrive at a comment
		if value.Next.Next == nil || strings.HasPrefix(value.Next.Next.Value, "#") {
			break
		}
		src, err := processShellWord(slex, value.Next.Value, envs)
		if err != nil {
			return nil, errors.Wrap(err, "processing word")
		}
		// If the --from flag is provided, we are dealing with a multi-stage dockerfile
		// Adding a dependency from a different stage does not imply a source dependency
		if hasMultiStageFlag(value.Flags) {
			return nil, nil
		}
		if !strings.HasPrefix(src, "http://") && !strings.HasPrefix(src, "https://") {
			copied = append(copied, src)
		} else {
			logrus.Debugf("Skipping watch on remote dependency %s", src)
		}

		value = value.Next
	}

	return copied, nil
}

func processShellWord(lex *shell.Lex, word string, envs map[string]string) (string, error) {
	envSlice := []string{}
	for envKey, envVal := range envs {
		envSlice = append(envSlice, fmt.Sprintf("%s=%s", envKey, envVal))
	}
	return lex.ProcessWord(word, envSlice)
}

func hasMultiStageFlag(flags []string) bool {
	for _, f := range flags {
		if strings.HasPrefix(f, "--from=") {
			return true
		}
	}
	return false
}
<commit_msg>Simplify code<commit_after>/*
Copyright 2018 The Skaffold 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 docker

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"

	latest "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha4"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/docker/docker/builder/dockerignore"
	"github.com/docker/docker/pkg/fileutils"
	"github.com/google/go-containerregistry/pkg/v1"
	"github.com/karrick/godirwalk"
	"github.com/moby/buildkit/frontend/dockerfile/command"
	"github.com/moby/buildkit/frontend/dockerfile/parser"
	"github.com/moby/buildkit/frontend/dockerfile/shell"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

type from struct {
	image string
	as    string
}

// RetrieveImage is overridden for unit testing
var RetrieveImage = retrieveImage

func ValidateDockerfile(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		logrus.Warnf("opening file %s: %s", path, err.Error())
		return false
	}
	res, err := parser.Parse(f)
	if err != nil || res == nil || len(res.AST.Children) == 0 {
		return false
	}
	// validate each node contains valid dockerfile directive
	for _, child := range res.AST.Children {
		_, ok := command.Commands[child.Value]
		if !ok {
			return false
		}
	}

	return true
}

func expandBuildArgs(nodes []*parser.Node, buildArgs map[string]*string) {
	for i, node := range nodes {
		if node.Value != command.Arg {
			continue
		}

		// build arg's key
		keyValue := strings.Split(node.Next.Value, "=")
		key := keyValue[0]

		// build arg's value
		var value string
		if buildArgs[key] != nil {
			value = *buildArgs[key]
		} else if len(keyValue) > 1 {
			value = keyValue[1]
		}

		for _, node := range nodes[i+1:] {
			// Stop replacements if an arg is redefined with the same key
			if node.Value == command.Arg && strings.Split(node.Next.Value, "=")[0] == key {
				break
			}

			// replace $key with value
			for curr := node; curr != nil; curr = curr.Next {
				curr.Value = util.Expand(curr.Value, key, value)
			}
		}
	}
}

func fromInstructions(nodes []*parser.Node) []from {
	var list []from

	for _, node := range nodes {
		if node.Value == command.From {
			list = append(list, fromInstruction(node))
		}
	}

	return list
}

func fromInstruction(node *parser.Node) from {
	var as string
	if next := node.Next.Next; next != nil && strings.ToLower(next.Value) == "as" && next.Next != nil {
		as = next.Next.Value
	}

	return from{
		image: strings.ToLower(node.Next.Value),
		as:    strings.ToLower(as),
	}
}

func onbuildInstructions(nodes []*parser.Node) ([]*parser.Node, error) {
	var instructions []string

	stages := map[string]bool{}
	for _, from := range fromInstructions(nodes) {
		stages[from.as] = true

		if from.image == "scratch" {
			continue
		}

		if _, found := stages[from.image]; found {
			continue
		}

		logrus.Debugf("Checking base image %s for ONBUILD triggers.", from.image)
		img, err := RetrieveImage(from.image)
		if err != nil {
			logrus.Warnf("Error processing base image for ONBUILD triggers: %s. Dependencies may be incomplete.", err)
			continue
		}

		logrus.Debugf("Found ONBUILD triggers %v in image %s", img.Config.OnBuild, from.image)
		instructions = append(instructions, img.Config.OnBuild...)
	}

	obRes, err := parser.Parse(strings.NewReader(strings.Join(instructions, "\n")))
	if err != nil {
		return nil, errors.Wrap(err, "parsing ONBUILD instructions")
	}

	return obRes.AST.Children, nil
}

func copiedFiles(nodes []*parser.Node) ([][]string, error) {
	var copied [][]string

	envs := map[string]string{}
	for _, node := range nodes {
		switch node.Value {
		case command.Add, command.Copy:
			files, _ := processCopy(node, envs)
			if len(files) > 0 {
				copied = append(copied, files)
			}
		case command.Env:
			envs[node.Next.Value] = node.Next.Next.Value
		}
	}

	return copied, nil
}

func readDockerfile(workspace, absDockerfilePath string, buildArgs map[string]*string) ([]string, error) {
	f, err := os.Open(absDockerfilePath)
	if err != nil {
		return nil, errors.Wrapf(err, "opening dockerfile: %s", absDockerfilePath)
	}
	defer f.Close()

	res, err := parser.Parse(f)
	if err != nil {
		return nil, errors.Wrap(err, "parsing dockerfile")
	}

	expandBuildArgs(res.AST.Children, buildArgs)

	instructions, err := onbuildInstructions(res.AST.Children)
	if err != nil {
		return nil, errors.Wrap(err, "listing ONBUILD instructions")
	}

	copied, err := copiedFiles(append(instructions, res.AST.Children...))
	if err != nil {
		return nil, errors.Wrap(err, "listing copied files")
	}

	return expandPaths(workspace, copied)
}

func expandPaths(workspace string, copied [][]string) ([]string, error) {
	expandedPaths := make(map[string]bool)
	for _, files := range copied {
		matchesOne := false

		for _, p := range files {
			path := filepath.Join(workspace, p)
			if _, err := os.Stat(path); err == nil {
				expandedPaths[p] = true
				matchesOne = true
				continue
			}

			files, err := filepath.Glob(path)
			if err != nil {
				return nil, errors.Wrap(err, "invalid glob pattern")
			}
			if files == nil {
				continue
			}

			for _, f := range files {
				rel, err := filepath.Rel(workspace, f)
				if err != nil {
					return nil, fmt.Errorf("getting relative path of %s", f)
				}

				expandedPaths[rel] = true
			}
			matchesOne = true
		}

		if !matchesOne {
			return nil, fmt.Errorf("file pattern %s must match at least one file", files)
		}
	}

	var deps []string
	for dep := range expandedPaths {
		deps = append(deps, dep)
	}
	logrus.Infof("Found dependencies for dockerfile %s", deps)

	return deps, nil
}

// GetDependencies finds the sources dependencies for the given docker artifact.
// All paths are relative to the workspace.
func GetDependencies(workspace string, a *latest.DockerArtifact) ([]string, error) {
	absDockerfilePath, err := NormalizeDockerfilePath(workspace, a.DockerfilePath)
	if err != nil {
		return nil, errors.Wrap(err, "normalizing dockerfile path")
	}

	deps, err := readDockerfile(workspace, absDockerfilePath, a.BuildArgs)
	if err != nil {
		return nil, err
	}

	// Read patterns to ignore
	var excludes []string
	dockerignorePath := filepath.Join(workspace, ".dockerignore")
	if _, err := os.Stat(dockerignorePath); !os.IsNotExist(err) {
		r, err := os.Open(dockerignorePath)
		if err != nil {
			return nil, err
		}
		defer r.Close()

		excludes, err = dockerignore.ReadAll(r)
		if err != nil {
			return nil, err
		}
	}

	pExclude, err := fileutils.NewPatternMatcher(excludes)
	if err != nil {
		return nil, errors.Wrap(err, "invalid exclude patterns")
	}

	// Walk the workspace
	files := make(map[string]bool)
	for _, dep := range deps {
		dep = filepath.Clean(dep)
		absDep := filepath.Join(workspace, dep)

		fi, err := os.Stat(absDep)
		if err != nil {
			return nil, errors.Wrapf(err, "stating file %s", absDep)
		}

		switch mode := fi.Mode(); {
		case mode.IsDir():
			if err := godirwalk.Walk(absDep, &godirwalk.Options{
				Unsorted: true,
				Callback: func(fpath string, info *godirwalk.Dirent) error {
					relPath, err := filepath.Rel(workspace, fpath)
					if err != nil {
						return err
					}

					ignored, err := pExclude.Matches(relPath)
					if err != nil {
						return err
					}

					if info.IsDir() {
						if ignored {
							return filepath.SkipDir
						}
					} else if !ignored {
						files[relPath] = true
					}

					return nil
				},
			}); err != nil {
				return nil, errors.Wrapf(err, "walking folder %s", absDep)
			}
		case mode.IsRegular():
			ignored, err := pExclude.Matches(dep)
			if err != nil {
				return nil, err
			}

			if !ignored {
				files[dep] = true
			}
		}
	}

	// Always add dockerfile even if it's .dockerignored. The daemon will need it anyways.
	if !filepath.IsAbs(a.DockerfilePath) {
		files[a.DockerfilePath] = true
	} else {
		files[absDockerfilePath] = true
	}

	// Ignore .dockerignore
	delete(files, ".dockerignore")

	var dependencies []string
	for file := range files {
		dependencies = append(dependencies, file)
	}
	sort.Strings(dependencies)

	return dependencies, nil
}

var imageCache sync.Map

func retrieveImage(image string) (*v1.ConfigFile, error) {
	cachedCfg, present := imageCache.Load(image)
	if present {
		return cachedCfg.(*v1.ConfigFile), nil
	}

	client, err := NewAPIClient()
	if err != nil {
		return nil, err
	}

	cfg := &v1.ConfigFile{}
	raw, err := retrieveLocalImage(client, image)
	if err == nil {
		if err := json.Unmarshal(raw, cfg); err != nil {
			return nil, err
		}
	} else {
		cfg, err = retrieveRemoteConfig(image)
		if err != nil {
			return nil, errors.Wrap(err, "getting remote config")
		}
	}

	imageCache.Store(image, cfg)

	return cfg, nil
}

func retrieveLocalImage(client APIClient, image string) ([]byte, error) {
	_, raw, err := client.ImageInspectWithRaw(context.Background(), image)
	if err != nil {
		return nil, err
	}

	return raw, nil
}

func retrieveRemoteConfig(identifier string) (*v1.ConfigFile, error) {
	img, err := remoteImage(identifier)
	if err != nil {
		return nil, errors.Wrap(err, "getting image")
	}

	return img.ConfigFile()
}

func processCopy(value *parser.Node, envs map[string]string) ([]string, error) {
	var copied []string

	slex := shell.NewLex('\\')
	for {
		// Skip last node, since it is the destination, and stop if we arrive at a comment
		if value.Next.Next == nil || strings.HasPrefix(value.Next.Next.Value, "#") {
			break
		}
		src, err := processShellWord(slex, value.Next.Value, envs)
		if err != nil {
			return nil, errors.Wrap(err, "processing word")
		}
		// If the --from flag is provided, we are dealing with a multi-stage dockerfile
		// Adding a dependency from a different stage does not imply a source dependency
		if hasMultiStageFlag(value.Flags) {
			return nil, nil
		}
		if !strings.HasPrefix(src, "http://") && !strings.HasPrefix(src, "https://") {
			copied = append(copied, src)
		} else {
			logrus.Debugf("Skipping watch on remote dependency %s", src)
		}

		value = value.Next
	}

	return copied, nil
}

func processShellWord(lex *shell.Lex, word string, envs map[string]string) (string, error) {
	envSlice := []string{}
	for envKey, envVal := range envs {
		envSlice = append(envSlice, fmt.Sprintf("%s=%s", envKey, envVal))
	}
	return lex.ProcessWord(word, envSlice)
}

func hasMultiStageFlag(flags []string) bool {
	for _, f := range flags {
		if strings.HasPrefix(f, "--from=") {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package tls

import (
	"crypto/tls"
	"crypto/x509"
	"net"
	"sort"
	"strings"
	"time"

	"github.com/patrickmn/go-cache"
	"github.com/traefik/traefik/v2/pkg/log"
	"github.com/traefik/traefik/v2/pkg/safe"
)

// CertificateStore store for dynamic certificates.
type CertificateStore struct {
	DynamicCerts       *safe.Safe
	DefaultCertificate *tls.Certificate
	CertCache          *cache.Cache
}

// NewCertificateStore create a store for dynamic certificates.
func NewCertificateStore() *CertificateStore {
	return &CertificateStore{
		DynamicCerts: &safe.Safe{},
		CertCache:    cache.New(1*time.Hour, 10*time.Minute),
	}
}

func (c CertificateStore) getDefaultCertificateDomains() []string {
	var allCerts []string

	if c.DefaultCertificate == nil {
		return allCerts
	}

	x509Cert, err := x509.ParseCertificate(c.DefaultCertificate.Certificate[0])
	if err != nil {
		log.WithoutContext().Errorf("Could not parse default certificate: %v", err)
		return allCerts
	}

	if len(x509Cert.Subject.CommonName) > 0 {
		allCerts = append(allCerts, x509Cert.Subject.CommonName)
	}

	allCerts = append(allCerts, x509Cert.DNSNames...)

	for _, ipSan := range x509Cert.IPAddresses {
		allCerts = append(allCerts, ipSan.String())
	}

	return allCerts
}

// GetAllDomains return a slice with all the certificate domain.
func (c CertificateStore) GetAllDomains() []string {
	allDomains := c.getDefaultCertificateDomains()

	// Get dynamic certificates
	if c.DynamicCerts != nil && c.DynamicCerts.Get() != nil {
		for domain := range c.DynamicCerts.Get().(map[string]*tls.Certificate) {
			allDomains = append(allDomains, domain)
		}
	}

	return allDomains
}

// GetBestCertificate returns the best match certificate, and caches the response.
func (c *CertificateStore) GetBestCertificate(clientHello *tls.ClientHelloInfo) *tls.Certificate {
	if c == nil {
		return nil
	}
	domainToCheck := strings.ToLower(strings.TrimSpace(clientHello.ServerName))
	if len(domainToCheck) == 0 {
		// If no ServerName is provided, Check for local IP address matches
		host, _, err := net.SplitHostPort(clientHello.Conn.LocalAddr().String())
		if err != nil {
			log.Debugf("Could not split host/port: %v", err)
		}
		domainToCheck = strings.TrimSpace(host)
	}

	if cert, ok := c.CertCache.Get(domainToCheck); ok {
		return cert.(*tls.Certificate)
	}

	matchedCerts := map[string]*tls.Certificate{}
	if c.DynamicCerts != nil && c.DynamicCerts.Get() != nil {
		for domains, cert := range c.DynamicCerts.Get().(map[string]*tls.Certificate) {
			for _, certDomain := range strings.Split(domains, ",") {
				if MatchDomain(domainToCheck, certDomain) {
					matchedCerts[certDomain] = cert
				}
			}
		}
	}

	if len(matchedCerts) > 0 {
		// sort map by keys
		keys := make([]string, 0, len(matchedCerts))
		for k := range matchedCerts {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		// cache best match
		c.CertCache.SetDefault(domainToCheck, matchedCerts[keys[len(keys)-1]])
		return matchedCerts[keys[len(keys)-1]]
	}

	return nil
}

// ResetCache clears the cache in the store.
func (c CertificateStore) ResetCache() {
	if c.CertCache != nil {
		c.CertCache.Flush()
	}
}

// MatchDomain return true if a domain match the cert domain.
func MatchDomain(domain, certDomain string) bool {
	if domain == certDomain {
		return true
	}

	for len(certDomain) > 0 && certDomain[len(certDomain)-1] == '.' {
		certDomain = certDomain[:len(certDomain)-1]
	}

	labels := strings.Split(domain, ".")
	for i := range labels {
		labels[i] = "*"
		candidate := strings.Join(labels, ".")
		if certDomain == candidate {
			return true
		}
	}
	return false
}
<commit_msg>Refactor certificate domains matching func<commit_after>package tls

import (
	"crypto/tls"
	"crypto/x509"
	"net"
	"sort"
	"strings"
	"time"

	"github.com/patrickmn/go-cache"
	"github.com/traefik/traefik/v2/pkg/log"
	"github.com/traefik/traefik/v2/pkg/safe"
)

// CertificateStore store for dynamic certificates.
type CertificateStore struct {
	DynamicCerts       *safe.Safe
	DefaultCertificate *tls.Certificate
	CertCache          *cache.Cache
}

// NewCertificateStore create a store for dynamic certificates.
func NewCertificateStore() *CertificateStore {
	return &CertificateStore{
		DynamicCerts: &safe.Safe{},
		CertCache:    cache.New(1*time.Hour, 10*time.Minute),
	}
}

func (c CertificateStore) getDefaultCertificateDomains() []string {
	var allCerts []string

	if c.DefaultCertificate == nil {
		return allCerts
	}

	x509Cert, err := x509.ParseCertificate(c.DefaultCertificate.Certificate[0])
	if err != nil {
		log.WithoutContext().Errorf("Could not parse default certificate: %v", err)
		return allCerts
	}

	if len(x509Cert.Subject.CommonName) > 0 {
		allCerts = append(allCerts, x509Cert.Subject.CommonName)
	}

	allCerts = append(allCerts, x509Cert.DNSNames...)

	for _, ipSan := range x509Cert.IPAddresses {
		allCerts = append(allCerts, ipSan.String())
	}

	return allCerts
}

// GetAllDomains return a slice with all the certificate domain.
func (c CertificateStore) GetAllDomains() []string {
	allDomains := c.getDefaultCertificateDomains()

	// Get dynamic certificates
	if c.DynamicCerts != nil && c.DynamicCerts.Get() != nil {
		for domain := range c.DynamicCerts.Get().(map[string]*tls.Certificate) {
			allDomains = append(allDomains, domain)
		}
	}

	return allDomains
}

// GetBestCertificate returns the best match certificate, and caches the response.
func (c *CertificateStore) GetBestCertificate(clientHello *tls.ClientHelloInfo) *tls.Certificate {
	if c == nil {
		return nil
	}
	serverName := strings.ToLower(strings.TrimSpace(clientHello.ServerName))
	if len(serverName) == 0 {
		// If no ServerName is provided, Check for local IP address matches
		host, _, err := net.SplitHostPort(clientHello.Conn.LocalAddr().String())
		if err != nil {
			log.WithoutContext().Debugf("Could not split host/port: %v", err)
		}
		serverName = strings.TrimSpace(host)
	}

	if cert, ok := c.CertCache.Get(serverName); ok {
		return cert.(*tls.Certificate)
	}

	matchedCerts := map[string]*tls.Certificate{}
	if c.DynamicCerts != nil && c.DynamicCerts.Get() != nil {
		for domains, cert := range c.DynamicCerts.Get().(map[string]*tls.Certificate) {
			for _, certDomain := range strings.Split(domains, ",") {
				if matchDomain(serverName, certDomain) {
					matchedCerts[certDomain] = cert
				}
			}
		}
	}

	if len(matchedCerts) > 0 {
		// sort map by keys
		keys := make([]string, 0, len(matchedCerts))
		for k := range matchedCerts {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		// cache best match
		c.CertCache.SetDefault(serverName, matchedCerts[keys[len(keys)-1]])
		return matchedCerts[keys[len(keys)-1]]
	}

	return nil
}

// ResetCache clears the cache in the store.
func (c CertificateStore) ResetCache() {
	if c.CertCache != nil {
		c.CertCache.Flush()
	}
}

// matchDomain returns whether the server name matches the cert domain.
// The server name, from TLS SNI, must not have trailing dots (https://datatracker.ietf.org/doc/html/rfc6066#section-3).
// This is enforced by https://github.com/golang/go/blob/d3d7998756c33f69706488cade1cd2b9b10a4c7f/src/crypto/tls/handshake_messages.go#L423-L427.
func matchDomain(serverName, certDomain string) bool {
	// TODO: assert equality after removing the trailing dots?
	if serverName == certDomain {
		return true
	}

	for len(certDomain) > 0 && certDomain[len(certDomain)-1] == '.' {
		certDomain = certDomain[:len(certDomain)-1]
	}

	labels := strings.Split(serverName, ".")
	for i := range labels {
		labels[i] = "*"
		candidate := strings.Join(labels, ".")
		if certDomain == candidate {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package tools

import (
	"errors"
	"fmt"
	"os"
	"path"
	"strings"
)

// ResolveScript is resolving the target script.
func ResolveScript(dir, name string) (string, error) {
	script := path.Clean(path.Join(dir, fmt.Sprintf("%s.sh", name)))
	if !strings.HasPrefix(script, dir) {
		return "", errors.New("Invalid script path: " + script)
	}
	if _, err := os.Stat(script); os.IsNotExist(err) {
		return "", errors.New("Script not found: " + script)
	}

	return script, nil
}
<commit_msg>fix(): fix error message<commit_after>package tools

import (
	"errors"
	"fmt"
	"os"
	"path"
	"strings"
)

// ResolveScript is resolving the target script.
func ResolveScript(dir, name string) (string, error) {
	script := path.Clean(path.Join(dir, fmt.Sprintf("%s.sh", name)))
	if !strings.HasPrefix(script, dir) {
		return "", errors.New("Invalid script path: " + name)
	}
	if _, err := os.Stat(script); os.IsNotExist(err) {
		return "", errors.New("Script not found: " + script)
	}

	return script, nil
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"net/http"
	"sync"
	"time"

	"github.com/Comcast/webpa-common/concurrent"
	"github.com/Comcast/webpa-common/health"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/logging/golog"
)

var (
	// ErrorNoPrimaryAddress is the error returned when no primary address is specified in a WebPA instance
	ErrorNoPrimaryAddress = errors.New("No primary address configured")
)

// executor is an internal type used to start an HTTP server.  *http.Server implements
// this interface.  It can be mocked for testing.
type executor interface {
	ListenAndServe() error
	ListenAndServeTLS(certificateFile, keyFile string) error
}

// Secure exposes the optional certificate information to be used when starting an HTTP server.
type Secure interface {
	// Certificate returns the certificate information associated with this Secure instance.
	// BOTH the returned file paths must be non-empty if a TLS server is desired.
	Certificate() (certificateFile, keyFile string)
}

// ListenAndServe invokes the appropriate server method based on the secure information.
// If Secure.Certificate() returns both a certificateFile and a keyFile, e.ListenAndServeTLS()
// is called to start the server.  Otherwise, e.ListenAndServe() is used.
func ListenAndServe(logger logging.Logger, s Secure, e executor) {
	certificateFile, keyFile := s.Certificate()
	if len(certificateFile) > 0 && len(keyFile) > 0 {
		go func() {
			logger.Error(
				e.ListenAndServeTLS(certificateFile, keyFile),
			)
		}()
	} else {
		go func() {
			logger.Error(
				e.ListenAndServe(),
			)
		}()
	}
}

// Basic describes a simple HTTP server.  Typically, this struct has its values
// injected via Viper.  See the New function in this package.
type Basic struct {
	Name               string
	Address            string
	CertificateFile    string
	KeyFile            string
	LogConnectionState bool
}

func (b *Basic) Certificate() (certificateFile, keyFile string) {
	return b.CertificateFile, b.KeyFile
}

// New creates an http.Server using this instance's configuration.  The given logger is required,
// but the handler may be nil.  If the handler is nil, http.DefaultServeMux is used, which matches
// the behavior of http.Server.
//
// This method returns nil if the configured address is empty, effectively disabling
// this server from startup.
func (b *Basic) New(logger logging.Logger, handler http.Handler) *http.Server {
	if len(b.Address) == 0 {
		return nil
	}

	server := &http.Server{
		Addr:     b.Address,
		Handler:  handler,
		ErrorLog: NewErrorLog(b.Name, logger),
	}

	if b.LogConnectionState {
		server.ConnState = NewConnectionStateLogger(b.Name, logger)
	}

	return server
}

// Health represents a configurable factory for a Health server.  As with the Basic type,
// if the Address is not specified, health is considered to be disabled.
//
// Due to a limitation of Viper, this struct does not use an embedded Basic
// instance.  Rather, it duplicates the fields so that Viper can inject them.
type Health struct {
	Name               string
	Address            string
	CertificateFile    string
	KeyFile            string
	LogConnectionState bool
	LogInterval        time.Duration
	Options            []string
}

func (h *Health) Certificate() (certificateFile, keyFile string) {
	return h.CertificateFile, h.KeyFile
}

// NewHealth creates a Health instance from this instance's configuration.  If the Address
// field is not supplied, this method returns nil.
func (h *Health) NewHealth(logger logging.Logger) *health.Health {
	if len(h.Address) == 0 {
		return nil
	}

	options := make([]health.Option, 0, len(h.Options))
	for _, value := range h.Options {
		options = append(options, health.Stat(value))
	}

	return health.New(
		h.LogInterval,
		logger,
		options...,
	)
}

// New creates an HTTP server instance for serving health statistics.  If the health parameter
// is nil, then h.NewHealth is used to create a Health instance.  Otherwise, the health parameter
// is returned as is.
//
// If the Address option is not supplied, the health module is considered to be disabled.  In that
// case, this method simply returns the health parameter as the monitor and a nil server instance.
func (h *Health) New(logger logging.Logger, health *health.Health) (*health.Health, *http.Server) {
	if len(h.Address) == 0 {
		// health is disabled
		return nil, nil
	}

	if health == nil {
		if health = h.NewHealth(logger); health == nil {
			// should never hit this case, since NewHealth performs the same
			// Address field check as this method.  but, just to be safe ...
			return nil, nil
		}
	}

	mux := http.NewServeMux()
	mux.Handle("/health", health)

	server := &http.Server{
		Addr:     h.Address,
		Handler:  mux,
		ErrorLog: NewErrorLog(h.Name, logger),
	}

	if h.LogConnectionState {
		server.ConnState = NewConnectionStateLogger(h.Name, logger)
	}

	return health, server
}

// WebPA represents a server component within the WebPA cluster.  It is used for both
// primary servers (e.g. petasos) and supporting, embedded servers such as pprof.
type WebPA struct {
	// Primary is the main server for this application, e.g. petasos.
	Primary Basic

	// Alternate is an alternate server which serves the primary application logic.
	// Used to have the same API served on more than one port and possibly more than
	// one protocol, e.g. HTTP and HTTPS.
	Alternate Basic

	// Health describes the health server for this application.  Note that if the Address
	// is empty, no health server is started.
	Health Health

	// Pprof describes the pprof server for this application.  Note that if the Address
	// is empty, no pprof server is started.
	Pprof Basic

	// Log is the logging configuration for this application.
	Log golog.LoggerFactory
}

// Prepare gets a WebPA server ready for execution.  This method does not return errors, but the returned
// Runnable may return an error.  The supplied logger will usually come from the New function, but the
// WebPA.Log object can be used to create a different logger if desired.
//
// The caller may pass an arbitrary Health instance.  If this parameter is nil, this method will attempt to
// create one using Health.NewHealth.  In either case, if Health.Address is not supplied, no health server
// will be instantiated.
//
// The supplied http.Handler is used for the primary server.  If the alternate server has an address,
// it will also be used for that server.  The health server uses an internally create handler, while the pprof
// server uses http.DefaultServeMux.  The health Monitor created from configuration is returned so that other
// infrastructure can make use of it.
func (w *WebPA) Prepare(logger logging.Logger, health *health.Health, primaryHandler http.Handler) (health.Monitor, concurrent.Runnable) {
	// allow the health instance to be non-nil, in which case it will be used in favor of
	// the WebPA-configured instance.
	healthHandler, healthServer := w.Health.New(logger, health)

	return healthHandler, concurrent.RunnableFunc(func(waitGroup *sync.WaitGroup, shutdown <-chan struct{}) error {
		if healthHandler != nil && healthServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Health.Name, w.Health.Address)
			ListenAndServe(logger, &w.Health, healthServer)
			healthHandler.Run(waitGroup, shutdown)

			// wrap the primary handler in the RequestTracker decorator
			primaryHandler = healthHandler.RequestTracker(primaryHandler)
		}

		if pprofServer := w.Pprof.New(logger, nil); pprofServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Pprof.Name, w.Pprof.Address)
			ListenAndServe(logger, &w.Pprof, pprofServer)
		}

		if primaryServer := w.Primary.New(logger, primaryHandler); primaryServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Primary.Name, w.Primary.Address)
			ListenAndServe(logger, &w.Primary, primaryServer)
		} else {
			return ErrorNoPrimaryAddress
		}

		if alternateServer := w.Alternate.New(logger, primaryHandler); alternateServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Alternate.Name, w.Alternate.Address)
			ListenAndServe(logger, &w.Alternate, alternateServer)
		}

		return nil
	})
}
<commit_msg>Allow extra options to be injected<commit_after>package server

import (
	"errors"
	"net/http"
	"sync"
	"time"

	"github.com/Comcast/webpa-common/concurrent"
	"github.com/Comcast/webpa-common/health"
	"github.com/Comcast/webpa-common/logging"
	"github.com/Comcast/webpa-common/logging/golog"
)

var (
	// ErrorNoPrimaryAddress is the error returned when no primary address is specified in a WebPA instance
	ErrorNoPrimaryAddress = errors.New("No primary address configured")
)

// executor is an internal type used to start an HTTP server.  *http.Server implements
// this interface.  It can be mocked for testing.
type executor interface {
	ListenAndServe() error
	ListenAndServeTLS(certificateFile, keyFile string) error
}

// Secure exposes the optional certificate information to be used when starting an HTTP server.
type Secure interface {
	// Certificate returns the certificate information associated with this Secure instance.
	// BOTH the returned file paths must be non-empty if a TLS server is desired.
	Certificate() (certificateFile, keyFile string)
}

// ListenAndServe invokes the appropriate server method based on the secure information.
// If Secure.Certificate() returns both a certificateFile and a keyFile, e.ListenAndServeTLS()
// is called to start the server.  Otherwise, e.ListenAndServe() is used.
func ListenAndServe(logger logging.Logger, s Secure, e executor) {
	certificateFile, keyFile := s.Certificate()
	if len(certificateFile) > 0 && len(keyFile) > 0 {
		go func() {
			logger.Error(
				e.ListenAndServeTLS(certificateFile, keyFile),
			)
		}()
	} else {
		go func() {
			logger.Error(
				e.ListenAndServe(),
			)
		}()
	}
}

// Basic describes a simple HTTP server.  Typically, this struct has its values
// injected via Viper.  See the New function in this package.
type Basic struct {
	Name               string
	Address            string
	CertificateFile    string
	KeyFile            string
	LogConnectionState bool
}

func (b *Basic) Certificate() (certificateFile, keyFile string) {
	return b.CertificateFile, b.KeyFile
}

// New creates an http.Server using this instance's configuration.  The given logger is required,
// but the handler may be nil.  If the handler is nil, http.DefaultServeMux is used, which matches
// the behavior of http.Server.
//
// This method returns nil if the configured address is empty, effectively disabling
// this server from startup.
func (b *Basic) New(logger logging.Logger, handler http.Handler) *http.Server {
	if len(b.Address) == 0 {
		return nil
	}

	server := &http.Server{
		Addr:     b.Address,
		Handler:  handler,
		ErrorLog: NewErrorLog(b.Name, logger),
	}

	if b.LogConnectionState {
		server.ConnState = NewConnectionStateLogger(b.Name, logger)
	}

	return server
}

// Health represents a configurable factory for a Health server.  As with the Basic type,
// if the Address is not specified, health is considered to be disabled.
//
// Due to a limitation of Viper, this struct does not use an embedded Basic
// instance.  Rather, it duplicates the fields so that Viper can inject them.
type Health struct {
	Name               string
	Address            string
	CertificateFile    string
	KeyFile            string
	LogConnectionState bool
	LogInterval        time.Duration
	Options            []string
}

func (h *Health) Certificate() (certificateFile, keyFile string) {
	return h.CertificateFile, h.KeyFile
}

// NewHealth creates a Health instance from this instance's configuration.  If the Address
// field is not supplied, this method returns nil.
func (h *Health) NewHealth(logger logging.Logger, options ...health.Option) *health.Health {
	if len(h.Address) == 0 {
		return nil
	}

	for _, value := range h.Options {
		options = append(options, health.Stat(value))
	}

	return health.New(
		h.LogInterval,
		logger,
		options...,
	)
}

// New creates an HTTP server instance for serving health statistics.  If the health parameter
// is nil, then h.NewHealth is used to create a Health instance.  Otherwise, the health parameter
// is returned as is.
//
// If the Address option is not supplied, the health module is considered to be disabled.  In that
// case, this method simply returns the health parameter as the monitor and a nil server instance.
func (h *Health) New(logger logging.Logger, health *health.Health) (*health.Health, *http.Server) {
	if len(h.Address) == 0 {
		// health is disabled
		return nil, nil
	}

	if health == nil {
		if health = h.NewHealth(logger); health == nil {
			// should never hit this case, since NewHealth performs the same
			// Address field check as this method.  but, just to be safe ...
			return nil, nil
		}
	}

	mux := http.NewServeMux()
	mux.Handle("/health", health)

	server := &http.Server{
		Addr:     h.Address,
		Handler:  mux,
		ErrorLog: NewErrorLog(h.Name, logger),
	}

	if h.LogConnectionState {
		server.ConnState = NewConnectionStateLogger(h.Name, logger)
	}

	return health, server
}

// WebPA represents a server component within the WebPA cluster.  It is used for both
// primary servers (e.g. petasos) and supporting, embedded servers such as pprof.
type WebPA struct {
	// Primary is the main server for this application, e.g. petasos.
	Primary Basic

	// Alternate is an alternate server which serves the primary application logic.
	// Used to have the same API served on more than one port and possibly more than
	// one protocol, e.g. HTTP and HTTPS.
	Alternate Basic

	// Health describes the health server for this application.  Note that if the Address
	// is empty, no health server is started.
	Health Health

	// Pprof describes the pprof server for this application.  Note that if the Address
	// is empty, no pprof server is started.
	Pprof Basic

	// Log is the logging configuration for this application.
	Log golog.LoggerFactory
}

// Prepare gets a WebPA server ready for execution.  This method does not return errors, but the returned
// Runnable may return an error.  The supplied logger will usually come from the New function, but the
// WebPA.Log object can be used to create a different logger if desired.
//
// The caller may pass an arbitrary Health instance.  If this parameter is nil, this method will attempt to
// create one using Health.NewHealth.  In either case, if Health.Address is not supplied, no health server
// will be instantiated.
//
// The supplied http.Handler is used for the primary server.  If the alternate server has an address,
// it will also be used for that server.  The health server uses an internally create handler, while the pprof
// server uses http.DefaultServeMux.  The health Monitor created from configuration is returned so that other
// infrastructure can make use of it.
func (w *WebPA) Prepare(logger logging.Logger, health *health.Health, primaryHandler http.Handler) (health.Monitor, concurrent.Runnable) {
	// allow the health instance to be non-nil, in which case it will be used in favor of
	// the WebPA-configured instance.
	healthHandler, healthServer := w.Health.New(logger, health)

	return healthHandler, concurrent.RunnableFunc(func(waitGroup *sync.WaitGroup, shutdown <-chan struct{}) error {
		if healthHandler != nil && healthServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Health.Name, w.Health.Address)
			ListenAndServe(logger, &w.Health, healthServer)
			healthHandler.Run(waitGroup, shutdown)

			// wrap the primary handler in the RequestTracker decorator
			primaryHandler = healthHandler.RequestTracker(primaryHandler)
		}

		if pprofServer := w.Pprof.New(logger, nil); pprofServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Pprof.Name, w.Pprof.Address)
			ListenAndServe(logger, &w.Pprof, pprofServer)
		}

		if primaryServer := w.Primary.New(logger, primaryHandler); primaryServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Primary.Name, w.Primary.Address)
			ListenAndServe(logger, &w.Primary, primaryServer)
		} else {
			return ErrorNoPrimaryAddress
		}

		if alternateServer := w.Alternate.New(logger, primaryHandler); alternateServer != nil {
			logger.Info("Starting [%s] on [%s]", w.Alternate.Name, w.Alternate.Address)
			ListenAndServe(logger, &w.Alternate, alternateServer)
		}

		return nil
	})
}
<|endoftext|>


<commit_before>package reverseproxy

import (
	"encoding/json"
	"io"
	"os"
	"fmt"
)

// ----------------------------------------

type ServerBlock struct {
	Hostnames []string
	Content []ServerResource
}

type ServerResource struct {
	Type, Path, Cachestrategy, Cachelimit string
}

// ----------------------------------------

func LoadConfigFromFile(configLocation string) ([]ServerBlock, error) {
	file, err := os.Open(configLocation)

	if err != nil {
		return nil, err
	}

	return LoadConfig(file)
}

func LoadConfig(config io.Reader) ([]ServerBlock, error) {
	sb := make([]ServerBlock, 0)
	d := json.NewDecoder(config)
	decodeErr := d.Decode(sb)

	if decodeErr != nil {
		panic(decodeErr)
	}

	fmt.Println(len(sb))

	return sb, decodeErr
}
<commit_msg>Fixing json parsing<commit_after>package reverseproxy

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

// ----------------------------------------

type ServerBlock struct {
	Hostnames []string
	Content []ServerResource
}

type ServerResource struct {
	Type, Path, Cachestrategy string
	Cachelimit int
}

// ----------------------------------------

func LoadConfigFromFile(configLocation string) ([]ServerBlock, error) {
	file, err := os.Open(configLocation)

	if err != nil {
		return nil, err
	}

	return LoadConfig(file)
}

func LoadConfig(config io.Reader) ([]ServerBlock, error) {
	sb := make([]ServerBlock, 0)
	d := json.NewDecoder(config)
	decodeErr := d.Decode(&sb)

	if decodeErr != nil {
		panic(decodeErr)
	}

	return sb, decodeErr
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 util

import (
	"archive/tar"
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
	"strings"

	"github.com/GoogleCloudPlatform/container-diff/cmd/util/output"
	"github.com/containers/image/docker"
	"github.com/containers/image/manifest"
	"github.com/containers/image/pkg/compression"
	"github.com/containers/image/types"
	"github.com/sirupsen/logrus"
)

type Prepper interface {
	Name() string
	GetConfig() (ConfigSchema, error)
	GetFileSystem() (string, error)
	GetImage() (Image, error)
	GetSource() string
	SetSource(string)
}

type ImageType int

const (
	ImageTypeTar ImageType = iota
	ImageTypeDaemon
	ImageTypeCloud
)

type Image struct {
	Source string
	FSPath string
	Config ConfigSchema
	Type   ImageType
}

func (i *Image) IsTar() bool {
	return i.Type == ImageTypeTar
}

func (i *Image) IsDaemon() bool {
	return i.Type == ImageTypeDaemon
}

func (i *Image) IsCloud() bool {
	return i.Type == ImageTypeCloud
}

func (i *Image) GetRemoteDigest() (string, error) {
	ref, err := docker.ParseReference("//" + i.Source)
	if err != nil {
		return "", err
	}
	return getDigestFromReference(ref, i.Source)
}

func (i *Image) GetName() string {
	return strings.Split(i.Source, ":")[0]
}

type ImageHistoryItem struct {
	CreatedBy string `json:"created_by"`
}

type ConfigObject struct {
	Env          []string            `json:"Env"`
	Entrypoint   []string            `json:"Entrypoint"`
	ExposedPorts map[string]struct{} `json:"ExposedPorts"`
	Cmd          []string            `json:"Cmd"`
	Volumes      map[string]struct{} `json:"Volumes"`
	Workdir      string              `json:"WorkingDir"`
	Labels       map[string]string   `json:"Labels"`
}

type ConfigSchema struct {
	Config  ConfigObject       `json:"config"`
	History []ImageHistoryItem `json:"history"`
}

func getImage(p Prepper) (Image, error) {
	// see if the image name has tag provided, if not add latest as tag
	if !HasTag(p.GetSource()) {
		p.SetSource(p.GetSource() + LatestTag)
	}
	output.PrintToStdErr("Retrieving image %s from source %s\n", p.GetSource(), p.Name())
	imgPath, err := p.GetFileSystem()
	if err != nil {
		return Image{}, err
	}

	config, err := p.GetConfig()
	if err != nil {
		logrus.Error("Error retrieving History: ", err)
	}

	logrus.Infof("Finished prepping image %s", p.GetSource())
	return Image{
		Source: p.GetSource(),
		FSPath: imgPath,
		Config: config,
	}, nil
}

func getImageFromTar(tarPath string) (string, error) {
	logrus.Info("Extracting image tar to obtain image file system")
	tempPath, err := ioutil.TempDir("", ".container-diff")
	if err != nil {
		return "", err
	}
	return tempPath, unpackDockerSave(tarPath, tempPath)
}

func GetFileSystemFromReference(ref types.ImageReference, imgSrc types.ImageSource, path string, whitelist []string) error {
	img, err := ref.NewImage(nil)
	if err != nil {
		return err
	}
	defer img.Close()
	for _, b := range img.LayerInfos() {
		bi, _, err := imgSrc.GetBlob(b)
		if err != nil {
			return err
		}
		defer bi.Close()
		f, reader, err := compression.DetectCompression(bi)
		if err != nil {
			return err
		}
		// Decompress if necessary.
		if f != nil {
			reader, err = f(reader)
			if err != nil {
				return err
			}
		}
		tr := tar.NewReader(reader)
		if err := unpackTar(tr, path, whitelist); err != nil {
			return err
		}
	}
	return nil
}

func getDigestFromReference(ref types.ImageReference, source string) (string, error) {
	img, err := ref.NewImage(nil)
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return "", errors.New("Could not obtain image digest")
	}
	defer img.Close()

	rawManifest, _, err := img.Manifest()
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return "", errors.New("Could not obtain image digest")
	}

	digest, err := manifest.Digest(rawManifest)
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return "", errors.New("Could not obtain image digest")
	}

	return digest.String(), nil
}

func getConfigFromReference(ref types.ImageReference, source string) (ConfigSchema, error) {
	img, err := ref.NewImage(nil)
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return ConfigSchema{}, errors.New("Could not obtain image config")
	}
	defer img.Close()

	configBlob, err := img.ConfigBlob()
	if err != nil {
		logrus.Errorf("Error obtaining config blob for image %s from registry: %s", source, err)
		return ConfigSchema{}, errors.New("Could not obtain image config")
	}

	var config ConfigSchema
	err = json.Unmarshal(configBlob, &config)
	if err != nil {
		logrus.Errorf("Error with config file struct for image %s: %s", source, err)
		return ConfigSchema{}, errors.New("Could not obtain image config")
	}
	return config, nil
}

func CleanupImage(image Image) {
	if image.FSPath != "" {
		logrus.Infof("Removing image filesystem directory %s from system", image.FSPath)
		if err := os.RemoveAll(image.FSPath); err != nil {
			logrus.Error(err.Error())
		}
	}
}
<commit_msg>create default ImageSource if none is provided<commit_after>/*
Copyright 2017 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 util

import (
	"archive/tar"
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
	"strings"

	"github.com/GoogleCloudPlatform/container-diff/cmd/util/output"
	"github.com/containers/image/docker"
	"github.com/containers/image/manifest"
	"github.com/containers/image/pkg/compression"
	"github.com/containers/image/types"
	"github.com/sirupsen/logrus"
)

type Prepper interface {
	Name() string
	GetConfig() (ConfigSchema, error)
	GetFileSystem() (string, error)
	GetImage() (Image, error)
	GetSource() string
	SetSource(string)
}

type ImageType int

const (
	ImageTypeTar ImageType = iota
	ImageTypeDaemon
	ImageTypeCloud
)

type Image struct {
	Source string
	FSPath string
	Config ConfigSchema
	Type   ImageType
}

func (i *Image) IsTar() bool {
	return i.Type == ImageTypeTar
}

func (i *Image) IsDaemon() bool {
	return i.Type == ImageTypeDaemon
}

func (i *Image) IsCloud() bool {
	return i.Type == ImageTypeCloud
}

func (i *Image) GetRemoteDigest() (string, error) {
	ref, err := docker.ParseReference("//" + i.Source)
	if err != nil {
		return "", err
	}
	return getDigestFromReference(ref, i.Source)
}

func (i *Image) GetName() string {
	return strings.Split(i.Source, ":")[0]
}

type ImageHistoryItem struct {
	CreatedBy string `json:"created_by"`
}

type ConfigObject struct {
	Env          []string            `json:"Env"`
	Entrypoint   []string            `json:"Entrypoint"`
	ExposedPorts map[string]struct{} `json:"ExposedPorts"`
	Cmd          []string            `json:"Cmd"`
	Volumes      map[string]struct{} `json:"Volumes"`
	Workdir      string              `json:"WorkingDir"`
	Labels       map[string]string   `json:"Labels"`
}

type ConfigSchema struct {
	Config  ConfigObject       `json:"config"`
	History []ImageHistoryItem `json:"history"`
}

func getImage(p Prepper) (Image, error) {
	// see if the image name has tag provided, if not add latest as tag
	if !HasTag(p.GetSource()) {
		p.SetSource(p.GetSource() + LatestTag)
	}
	output.PrintToStdErr("Retrieving image %s from source %s\n", p.GetSource(), p.Name())
	imgPath, err := p.GetFileSystem()
	if err != nil {
		return Image{}, err
	}

	config, err := p.GetConfig()
	if err != nil {
		logrus.Error("Error retrieving History: ", err)
	}

	logrus.Infof("Finished prepping image %s", p.GetSource())
	return Image{
		Source: p.GetSource(),
		FSPath: imgPath,
		Config: config,
	}, nil
}

func getImageFromTar(tarPath string) (string, error) {
	logrus.Info("Extracting image tar to obtain image file system")
	tempPath, err := ioutil.TempDir("", ".container-diff")
	if err != nil {
		return "", err
	}
	return tempPath, unpackDockerSave(tarPath, tempPath)
}

func GetFileSystemFromReference(ref types.ImageReference, imgSrc types.ImageSource, path string, whitelist []string) error {
	var err error
	if imgSrc == nil {
		imgSrc, err = ref.NewImageSource(nil)
	}
	if err != nil {
		return err
	}
	img, err := ref.NewImage(nil)
	if err != nil {
		return err
	}
	defer img.Close()
	for _, b := range img.LayerInfos() {
		bi, _, err := imgSrc.GetBlob(b)
		if err != nil {
			return err
		}
		defer bi.Close()
		f, reader, err := compression.DetectCompression(bi)
		if err != nil {
			return err
		}
		// Decompress if necessary.
		if f != nil {
			reader, err = f(reader)
			if err != nil {
				return err
			}
		}
		tr := tar.NewReader(reader)
		if err := unpackTar(tr, path, whitelist); err != nil {
			return err
		}
	}
	return nil
}

func getDigestFromReference(ref types.ImageReference, source string) (string, error) {
	img, err := ref.NewImage(nil)
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return "", errors.New("Could not obtain image digest")
	}
	defer img.Close()

	rawManifest, _, err := img.Manifest()
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return "", errors.New("Could not obtain image digest")
	}

	digest, err := manifest.Digest(rawManifest)
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return "", errors.New("Could not obtain image digest")
	}

	return digest.String(), nil
}

func getConfigFromReference(ref types.ImageReference, source string) (ConfigSchema, error) {
	img, err := ref.NewImage(nil)
	if err != nil {
		logrus.Errorf("Error referencing image %s from registry: %s", source, err)
		return ConfigSchema{}, errors.New("Could not obtain image config")
	}
	defer img.Close()

	configBlob, err := img.ConfigBlob()
	if err != nil {
		logrus.Errorf("Error obtaining config blob for image %s from registry: %s", source, err)
		return ConfigSchema{}, errors.New("Could not obtain image config")
	}

	var config ConfigSchema
	err = json.Unmarshal(configBlob, &config)
	if err != nil {
		logrus.Errorf("Error with config file struct for image %s: %s", source, err)
		return ConfigSchema{}, errors.New("Could not obtain image config")
	}
	return config, nil
}

func CleanupImage(image Image) {
	if image.FSPath != "" {
		logrus.Infof("Removing image filesystem directory %s from system", image.FSPath)
		if err := os.RemoveAll(image.FSPath); err != nil {
			logrus.Error(err.Error())
		}
	}
}
<|endoftext|>


<commit_before>// send.go - mixnet client send
// Copyright (C) 2018  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package session

import (
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"time"

	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/core/constants"
	"github.com/katzenpost/core/crypto/rand"
	sConstants "github.com/katzenpost/core/sphinx/constants"
)

const roundTripTimeSlop = time.Duration(88 * time.Second)

// WaitForSent blocks until the message with the corresponding message ID is sent.
func (s *Session) WaitForSent(id MessageID) error {
	s.log.Debug("Waiting for message to be sent.")
	var waitCh chan Event
	var err error

	s.mapLock.Lock()
	msg, ok := s.messageIDMap[*id]
	if !ok {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	}
	waitCh, ok = s.waitSentChans[*id]
	if ok {
		defer delete(s.waitSentChans, *id)
	} else {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	}
	s.mapLock.Unlock()

	if err != nil {
		return err
	}
	if msg.Sent {
		return nil
	}
	select {
	case <-waitCh:
	case <-time.After(1 * time.Minute):
		return fmt.Errorf("[%v] Failure waiting for reply, timeout", id)
	}
	s.log.Debug("Finished waiting. Message was sent.")
	return nil
}

// WaitForReply blocks until a reply is received.
func (s *Session) WaitForReply(id MessageID) ([]byte, error) {
	s.log.Debugf("WaitForReply message ID: %x\n", *id)
	err := s.WaitForSent(id)
	if err != nil {
		return nil, err
	}
	s.mapLock.Lock()
	waitCh, ok := s.waitChans[*id]
	if ok {
		defer delete(s.waitChans, *id)
	} else {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	}
	msg, ok := s.messageIDMap[*id]
	if ok {
		// XXX Consider what will happen because of this deletion
		// when we implement an ARQ based reliability.
		defer delete(s.messageIDMap, *id)
	} else {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	}
	s.log.Debug("reply eta is %v", msg.ReplyETA)
	s.mapLock.Unlock()
	if err != nil {
		return nil, err
	}
	select {
	case event := <-waitCh:
		e, ok := event.(*MessageReplyEvent)
		if !ok {
			s.log.Debug("UNKNOWN EVENT TYPE FOUND IN WAIT CHANNEL FOR THE GIVEN MESSAGE ID.")
		}
		return e.Payload, nil
	case <-time.After(msg.ReplyETA + roundTripTimeSlop):
		return nil, fmt.Errorf("[%v] Failure waiting for reply, timeout reached", id)
	}
	// unreachable
}

func (s *Session) sendNext() error {
	msg, err := s.egressQueue.Peek()
	if err != nil {
		return err
	}
	if msg == nil {
		return errors.New("send next failure, message is nil")
	}
	m, ok := msg.(*Message)
	if !ok {
		return errors.New("send next failure, unknown message type")
	}
	err = s.doSend(m)
	if err != nil {
		return err
	}
	_, err = s.egressQueue.Pop()
	return err
}

func (s *Session) doSend(msg *Message) error {
	surbID := [sConstants.SURBIDLength]byte{}
	_, err := io.ReadFull(rand.Reader, surbID[:])
	if err != nil {
		return err
	}
	idStr := fmt.Sprintf("[%v]", hex.EncodeToString(surbID[:]))
	s.log.Debugf("doSend with SURB ID %x", idStr)
	key := []byte{}
	var eta time.Duration
	if msg.WithSURB {
		key, eta, err = s.minclient.SendCiphertext(msg.Recipient, msg.Provider, &surbID, msg.Payload)
	} else {
		err = s.minclient.SendUnreliableCiphertext(msg.Recipient, msg.Provider, msg.Payload)
	}
	if err != nil {
		return err
	}
	if msg.WithSURB {
		s.log.Debugf("doSend setting ReplyETA to %v", eta)
		msg.Key = key
		msg.SentAt = time.Now()
		msg.Sent = true
		msg.ReplyETA = eta
		s.mapLock.Lock()
		s.surbIDMap[surbID] = msg
		s.mapLock.Unlock()
	}

	eventCh, ok := s.waitSentChans[*msg.ID]
	if ok {
		select {
		case eventCh <- &MessageSentEvent{
			MessageID: msg.ID,
			Err:       nil,
		}:
		case <-time.After(3 * time.Second):
			s.log.Debug("timeout reached when attempting to sent to waitSentChans")
			break
		}
	} else {
		s.log.Debug("no waitSentChans map entry found for that message ID")
	}
	return nil
}

func (s *Session) sendLoopDecoy() error {
	s.log.Info("sending loop decoy")
	const loopService = "loop"
	serviceDesc, err := s.GetService(loopService)
	if err != nil {
		return err
	}
	payload := [constants.UserForwardPayloadLength]byte{}
	id := [cConstants.MessageIDLength]byte{}
	_, err = io.ReadFull(rand.Reader, id[:])
	if err != nil {
		return err
	}
	msg := &Message{
		ID:        &id,
		Recipient: serviceDesc.Name,
		Provider:  serviceDesc.Provider,
		Payload:   payload[:],
		WithSURB:  true,
		IsDecoy:   true,
	}
	defer s.incrementDecoyLoopTally()
	return s.doSend(msg)
}

func (s *Session) sendDropDecoy() error {
	s.log.Info("sending drop decoy")
	const loopService = "loop"
	serviceDesc, err := s.GetService(loopService)
	if err != nil {
		return err
	}
	payload := [constants.UserForwardPayloadLength]byte{}
	id := [cConstants.MessageIDLength]byte{}
	_, err = io.ReadFull(rand.Reader, id[:])
	if err != nil {
		return err
	}
	msg := &Message{
		ID:        &id,
		Recipient: serviceDesc.Name,
		Provider:  serviceDesc.Provider,
		Payload:   payload[:],
		WithSURB:  false,
		IsDecoy:   true,
	}
	return s.doSend(msg)
}

func (s *Session) composeMessage(recipient, provider string, message []byte) (*Message, error) {
	s.log.Debug("SendMessage")
	if len(message) > constants.UserForwardPayloadLength {
		return nil, fmt.Errorf("invalid message size: %v", len(message))
	}
	payload := make([]byte, constants.UserForwardPayloadLength)
	copy(payload, message)
	id := [cConstants.MessageIDLength]byte{}
	_, err := io.ReadFull(rand.Reader, id[:])
	if err != nil {
		return nil, err
	}
	var msg = Message{
		ID:        &id,
		Recipient: recipient,
		Provider:  provider,
		Payload:   payload,
		WithSURB:  true,
	}
	msg.SURBType = cConstants.SurbTypeKaetzchen
	return &msg, nil
}

// SendUnreliableMessage sends message without any automatic retransmissions.
func (s *Session) SendUnreliableMessage(recipient, provider string, message []byte) (*[cConstants.MessageIDLength]byte, error) {
	msg, err := s.composeMessage(recipient, provider, message)
	if err != nil {
		return nil, err
	}

	s.mapLock.Lock()
	s.messageIDMap[*msg.ID] = msg
	s.waitChans[*msg.ID] = make(chan Event)
	s.waitSentChans[*msg.ID] = make(chan Event)
	s.mapLock.Unlock()

	err = s.egressQueue.Push(msg)
	if err != nil {
		return nil, err
	}
	return msg.ID, err
}
<commit_msg>Fix early return for WaitForSent<commit_after>// send.go - mixnet client send
// Copyright (C) 2018  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package session

import (
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"time"

	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/core/constants"
	"github.com/katzenpost/core/crypto/rand"
	sConstants "github.com/katzenpost/core/sphinx/constants"
)

const roundTripTimeSlop = time.Duration(88 * time.Second)

// WaitForSent blocks until the message with the corresponding message ID is sent.
func (s *Session) WaitForSent(id MessageID) error {
	s.log.Debug("Waiting for message to be sent.")
	var waitCh chan Event
	var err error
	s.mapLock.Lock()
	msg, ok := s.messageIDMap[*id]
	if !ok {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	} else {
		if msg.Sent {
			return nil
		}
	}
	waitCh, ok = s.waitSentChans[*id]
	if ok {
		defer delete(s.waitSentChans, *id)
	} else {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	}
	s.mapLock.Unlock()
	if err != nil {
		return err
	}
	select {
	case <-waitCh:
	case <-time.After(1 * time.Minute):
		return fmt.Errorf("[%v] Failure waiting for reply, timeout", id)
	}
	s.log.Debug("Finished waiting. Message was sent.")
	return nil
}

// WaitForReply blocks until a reply is received.
func (s *Session) WaitForReply(id MessageID) ([]byte, error) {
	s.log.Debugf("WaitForReply message ID: %x\n", *id)
	err := s.WaitForSent(id)
	if err != nil {
		return nil, err
	}
	s.mapLock.Lock()
	waitCh, ok := s.waitChans[*id]
	if ok {
		defer delete(s.waitChans, *id)
	} else {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	}
	msg, ok := s.messageIDMap[*id]
	if ok {
		// XXX Consider what will happen because of this deletion
		// when we implement an ARQ based reliability.
		defer delete(s.messageIDMap, *id)
	} else {
		err = fmt.Errorf("[%v] Failure waiting for reply, invalid message ID", id)
	}
	s.log.Debug("reply eta is %v", msg.ReplyETA)
	s.mapLock.Unlock()
	if err != nil {
		return nil, err
	}
	select {
	case event := <-waitCh:
		e, ok := event.(*MessageReplyEvent)
		if !ok {
			s.log.Debug("UNKNOWN EVENT TYPE FOUND IN WAIT CHANNEL FOR THE GIVEN MESSAGE ID.")
		}
		return e.Payload, nil
	case <-time.After(msg.ReplyETA + roundTripTimeSlop):
		return nil, fmt.Errorf("[%v] Failure waiting for reply, timeout reached", id)
	}
	// unreachable
}

func (s *Session) sendNext() error {
	msg, err := s.egressQueue.Peek()
	if err != nil {
		return err
	}
	if msg == nil {
		return errors.New("send next failure, message is nil")
	}
	m, ok := msg.(*Message)
	if !ok {
		return errors.New("send next failure, unknown message type")
	}
	err = s.doSend(m)
	if err != nil {
		return err
	}
	_, err = s.egressQueue.Pop()
	return err
}

func (s *Session) doSend(msg *Message) error {
	surbID := [sConstants.SURBIDLength]byte{}
	_, err := io.ReadFull(rand.Reader, surbID[:])
	if err != nil {
		return err
	}
	idStr := fmt.Sprintf("[%v]", hex.EncodeToString(surbID[:]))
	s.log.Debugf("doSend with SURB ID %x", idStr)
	key := []byte{}
	var eta time.Duration
	if msg.WithSURB {
		key, eta, err = s.minclient.SendCiphertext(msg.Recipient, msg.Provider, &surbID, msg.Payload)
	} else {
		err = s.minclient.SendUnreliableCiphertext(msg.Recipient, msg.Provider, msg.Payload)
	}
	if err != nil {
		return err
	}
	if msg.WithSURB {
		s.log.Debugf("doSend setting ReplyETA to %v", eta)
		msg.Key = key
		msg.SentAt = time.Now()
		msg.Sent = true
		msg.ReplyETA = eta
		s.mapLock.Lock()
		s.surbIDMap[surbID] = msg
		s.mapLock.Unlock()
	}

	eventCh, ok := s.waitSentChans[*msg.ID]
	if ok {
		select {
		case eventCh <- &MessageSentEvent{
			MessageID: msg.ID,
			Err:       nil,
		}:
		case <-time.After(3 * time.Second):
			s.log.Debug("timeout reached when attempting to sent to waitSentChans")
			break
		}
	} else {
		s.log.Debug("no waitSentChans map entry found for that message ID")
	}
	return nil
}

func (s *Session) sendLoopDecoy() error {
	s.log.Info("sending loop decoy")
	const loopService = "loop"
	serviceDesc, err := s.GetService(loopService)
	if err != nil {
		return err
	}
	payload := [constants.UserForwardPayloadLength]byte{}
	id := [cConstants.MessageIDLength]byte{}
	_, err = io.ReadFull(rand.Reader, id[:])
	if err != nil {
		return err
	}
	msg := &Message{
		ID:        &id,
		Recipient: serviceDesc.Name,
		Provider:  serviceDesc.Provider,
		Payload:   payload[:],
		WithSURB:  true,
		IsDecoy:   true,
	}
	defer s.incrementDecoyLoopTally()
	return s.doSend(msg)
}

func (s *Session) sendDropDecoy() error {
	s.log.Info("sending drop decoy")
	const loopService = "loop"
	serviceDesc, err := s.GetService(loopService)
	if err != nil {
		return err
	}
	payload := [constants.UserForwardPayloadLength]byte{}
	id := [cConstants.MessageIDLength]byte{}
	_, err = io.ReadFull(rand.Reader, id[:])
	if err != nil {
		return err
	}
	msg := &Message{
		ID:        &id,
		Recipient: serviceDesc.Name,
		Provider:  serviceDesc.Provider,
		Payload:   payload[:],
		WithSURB:  false,
		IsDecoy:   true,
	}
	return s.doSend(msg)
}

func (s *Session) composeMessage(recipient, provider string, message []byte) (*Message, error) {
	s.log.Debug("SendMessage")
	if len(message) > constants.UserForwardPayloadLength {
		return nil, fmt.Errorf("invalid message size: %v", len(message))
	}
	payload := make([]byte, constants.UserForwardPayloadLength)
	copy(payload, message)
	id := [cConstants.MessageIDLength]byte{}
	_, err := io.ReadFull(rand.Reader, id[:])
	if err != nil {
		return nil, err
	}
	var msg = Message{
		ID:        &id,
		Recipient: recipient,
		Provider:  provider,
		Payload:   payload,
		WithSURB:  true,
	}
	msg.SURBType = cConstants.SurbTypeKaetzchen
	return &msg, nil
}

// SendUnreliableMessage sends message without any automatic retransmissions.
func (s *Session) SendUnreliableMessage(recipient, provider string, message []byte) (*[cConstants.MessageIDLength]byte, error) {
	msg, err := s.composeMessage(recipient, provider, message)
	if err != nil {
		return nil, err
	}

	s.mapLock.Lock()
	s.messageIDMap[*msg.ID] = msg
	s.waitChans[*msg.ID] = make(chan Event)
	s.waitSentChans[*msg.ID] = make(chan Event)
	s.mapLock.Unlock()

	err = s.egressQueue.Push(msg)
	if err != nil {
		return nil, err
	}
	return msg.ID, err
}
<|endoftext|>


<commit_before>package roaring

// to run just these tests: go test -run TestSetUtil*

import (
	"testing"
)

func TestSetUtilDifference(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{0, 1}
	nl := difference(data1, data2, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Difference is broken")
	}
	expectedresult = []uint16{5, 8, 11}
	nl = difference(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Difference is broken")
	}
}

func TestSetUtilUnion(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{0, 1, 2, 3, 4, 5, 8, 9, 11}
	nl := union2by2(data1, data2, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Union is broken")
	}
	nl = union2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Union is broken")
	}
}

func TestSetUtilExclusiveUnion(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{0, 1, 5, 8, 11}
	nl := exclusiveUnion2by2(data1, data2, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Exclusive Union is broken")
	}
	nl = exclusiveUnion2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Exclusive Union is broken")
	}
}

func TestSetUtilIntersection(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{2, 3, 4, 9}
	nl := intersection2by2(data1, data2, result)
	result = result[:nl]
	result = result[:len(expectedresult)]
	if !equal(result, expectedresult) {
		t.Errorf("Intersection is broken")
	}
	nl = intersection2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Intersection is broken")
	}
	data1 = []uint16{4}

	data2 = make([]uint16, 10000)
	for i := range data2 {
		data2[i] = uint16(i)
	}
	result = make([]uint16, 0, len(data1)+len(data2))
	expectedresult = data1
	nl = intersection2by2(data1, data2, result)
	result = result[:nl]
	result = result[:len(expectedresult)]

	if !equal(result, expectedresult) {
		t.Errorf("Long intersection is broken")
	}
	nl = intersection2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Long intersection is broken")
	}

}

func TestSetUtilBinarySearch(t *testing.T) {
	data := make([]uint16, 256)
	for i := range data {
		data[i] = uint16(2 * i)
	}
	for i := 0; i < 2*len(data); i += 1 {
		key := uint16(i)
		loc := binarySearch(data, key)
		if (key & 1) == 0 {
			if loc != int(key)/2 {
				t.Errorf("binary search is broken")
			}
		} else {
			if loc != -int(key)/2-2 {
				t.Errorf("neg binary search is broken")
			}
		}
	}
}
<commit_msg>lint issue<commit_after>package roaring

// to run just these tests: go test -run TestSetUtil*

import (
	"testing"
)

func TestSetUtilDifference(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{0, 1}
	nl := difference(data1, data2, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Difference is broken")
	}
	expectedresult = []uint16{5, 8, 11}
	nl = difference(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Difference is broken")
	}
}

func TestSetUtilUnion(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{0, 1, 2, 3, 4, 5, 8, 9, 11}
	nl := union2by2(data1, data2, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Union is broken")
	}
	nl = union2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Union is broken")
	}
}

func TestSetUtilExclusiveUnion(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{0, 1, 5, 8, 11}
	nl := exclusiveUnion2by2(data1, data2, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Exclusive Union is broken")
	}
	nl = exclusiveUnion2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Exclusive Union is broken")
	}
}

func TestSetUtilIntersection(t *testing.T) {
	data1 := []uint16{0, 1, 2, 3, 4, 9}
	data2 := []uint16{2, 3, 4, 5, 8, 9, 11}
	result := make([]uint16, 0, len(data1)+len(data2))
	expectedresult := []uint16{2, 3, 4, 9}
	nl := intersection2by2(data1, data2, result)
	result = result[:nl]
	result = result[:len(expectedresult)]
	if !equal(result, expectedresult) {
		t.Errorf("Intersection is broken")
	}
	nl = intersection2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Intersection is broken")
	}
	data1 = []uint16{4}

	data2 = make([]uint16, 10000)
	for i := range data2 {
		data2[i] = uint16(i)
	}
	result = make([]uint16, 0, len(data1)+len(data2))
	expectedresult = data1
	nl = intersection2by2(data1, data2, result)
	result = result[:nl]
	result = result[:len(expectedresult)]

	if !equal(result, expectedresult) {
		t.Errorf("Long intersection is broken")
	}
	nl = intersection2by2(data2, data1, result)
	result = result[:nl]
	if !equal(result, expectedresult) {
		t.Errorf("Long intersection is broken")
	}

}

func TestSetUtilBinarySearch(t *testing.T) {
	data := make([]uint16, 256)
	for i := range data {
		data[i] = uint16(2 * i)
	}
	for i := 0; i < 2*len(data); i++ {
		key := uint16(i)
		loc := binarySearch(data, key)
		if (key & 1) == 0 {
			if loc != int(key)/2 {
				t.Errorf("binary search is broken")
			}
		} else {
			if loc != -int(key)/2-2 {
				t.Errorf("neg binary search is broken")
			}
		}
	}
}
<|endoftext|>


<commit_before>package model

import (
	"github.com/jinzhu/gorm"
	"time"
)

type Task struct {
	gorm.Model
	TaskId      *string    `gorm:"unique_index"`
	IterationId *string    `gorm:"not null"`
	Name        *string    `gorm:"not null"`
	Point       *float64   `gorm:"not null"`
	StartDate   JsonTime   `gorm:"-" json:"-"`
	EndDate     JsonTime   `gorm:"-" json:"-"`
	StartTime   *time.Time `gorm:"not null"`
	EndTime     *time.Time `gorm:"not null"`
	Raw         *string    `sql:"json"`
}

func (it *Task) SetTime() {
	it.StartTime = it.StartDate.Time
	it.EndTime = it.EndDate.Time
}
<commit_msg>Update task's date issue.<commit_after>package model

import (
	"github.com/jinzhu/gorm"
	"time"
)

type Task struct {
	gorm.Model
	TaskId      *string    `gorm:"unique_index"`
	IterationId *string    `gorm:"not null"`
	Name        *string    `gorm:"not null"`
	Point       *float64   `gorm:"not null"`
	StartDate   *JsonTime  `gorm:"-"`
	EndDate     *JsonTime  `gorm:"-"`
	StartTime   *time.Time `gorm:"not null" json:"-"`
	EndTime     *time.Time `gorm:"not null" json:"-"`
	Raw         *string    `sql:"json"`
}

func (it *Task) SetDate() {
	it.StartDate = &JsonTime{it.StartTime}
	it.EndDate = &JsonTime{it.EndTime}
}

func (it *Task) SetTime() {
	it.StartTime = it.StartDate.Time
	it.EndTime = it.EndDate.Time
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
)

func main() {
	http.HandleFunc("/hi", hi)
	http.ListenAndServe(":8081", nil)
}

func hi(w http.ResponseWriter, r *http.Request) {
	hostName, _ := os.Hostname()
	fmt.Fprintf(w, "Hostname: %s", hostName)
}
<commit_msg>http server<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"strconv"
)

func main() {
	http.HandleFunc("/hi", hi)
	greet := "Hello World!"
	fmt.Println("greet:", greet)
	func01()
	func02()
	http.HandleFunc("/sum", sum)
	fmt.Println("running on port:8081")
	http.ListenAndServe(":8081", nil)
}

func func01() {
	fmt.Println("func01")
}

func func02() {
	fmt.Println("func02")
}

func sum(w http.ResponseWriter, r *http.Request) {
	result := 0
	if r.Method == "GET" {
		vals := r.URL.Query()
		_num := vals.Get("num")
		if len(_num) != 0 {
			num, _ := strconv.Atoi(_num)
			if num != 0 {
				for i := 0; i <= num; i++ {
					result += i
				}
			}
		}
	}
	fmt.Fprintf(w, "result: %d\n", result)
}
func hi(w http.ResponseWriter, r *http.Request) {
	doHi(w)
}

func doHi(w http.ResponseWriter) {
	hostName, _ := os.Hostname()
	fmt.Fprintf(w, "Hostname: %s\n", hostName)
}
<|endoftext|>


<commit_before>package slt

import (
	"log"
	"regexp"
)

var (
	BHRegString string = `(\d{1,5}\+*\d*\+*\d*)` + // group(1) is the BH id
		`\s+\S+_to_black_hole_at_time\s*=\s*` +
		`(\d+\.*\d*)` + // group(2) is the BH formation time in units of FIXME
		`\s*` +
		`(\S+)` // group(3) is the time unit
		//`\s*\(old mass\s*=\s*(\d+\.*\d*)\)`									// group(4) is the progenitor mass (probably wrong)
	BHReg *regexp.Regexp = regexp.MustCompile(BHRegString)
	BHRes []string

	NSRegString string = `(\d{1,5}\+*\d*\+*\d*)` + // group(1) is the NS id
		`\s+\S+_to_neutron_star_at_time\s*=\s*` +
		`(\d+\.*\d*)` + // group(2) is the NS formation time in units of FIXME
		`\s*` +
		`(\S+)` // group(3) is the time unit
		//`\s*\(old mass\s*=\s*(\d+\.*\d*)\)`									// group(4) is the progenitor mass (probably wrong)
	NSReg *regexp.Regexp = regexp.MustCompile(NSRegString)
	NSRes []string

	WDRegString string = `(\d{1,5}\+*\d*\+*\d*)` + // group(1) is the WD id
		`\s+\S+_to_\S+_dwarf_at_time\s*=\s*` +
		`(\d+\.*\d*)` + // group(2) is the WD formation time in units of FIXME
		`\s*` +
		`(\S+)` // group(3) is the time unit
		//`\s*\(old mass\s*=\s*(\d+\.*\d*)\)`									// group(4) is the progenitor mass (probably wrong)
	WDReg *regexp.Regexp = regexp.MustCompile(WDRegString)
	WDRes []string

	MergerRegString string = `binary_evolution:\s*merger within\s*\(` + // group(1) are the two ids
		`(\d{1,5}\+*\d*\+*\d*,\d{1,5}\+*\d*\+*\d*)` +
		`\)\s*triggered by \d{1,5}\+*\d*\s*at time\s*` +
		`(\d+\.*\d*)` // group(2) is the merger time in units of FIXME
	MergerReg       *regexp.Regexp = regexp.MustCompile(MergerRegString)
	MergerRes       []string

	MergerTimeRegString string = `Collision at time =\s*\d+\.*\d*\s*\((\d+\.*\d*)\s*\[Myr\]\)\s*between`
	MergerTimeReg       *regexp.Regexp = regexp.MustCompile(MergerTimeRegString)
	MergerTimeRes       []string

	CollisionResultString string = `\d+\s*\((\S+);\s*M\s*=\s*(\d+\.*\S*)\s*\[Msun\]`
	CollisionResultReg       *regexp.Regexp = regexp.MustCompile(CollisionResultRegString)
	CollisionResultRes       []string
)

func Search (snapChan chan *DumbSnapshot) () {
	var (
		line string
		snap *DumbSnapshot
		lineChan = make(chan string, 1)
	)

	go SearchCO(lineChan)
	go SearchMerger(lineChan)
	go SearchBinaries(lineChan)

	for snap  = range snapChan {
		for _, line = snap.Lines {
			lineChan <- line
		}
	}

}

func SearchCO () () {

}

func SearchMerger () () {

}

func SearchBinaries () () {

}

<commit_msg>updates<commit_after>package slt

import (
	"log"
	"regexp"
)

var (
	// BH regexp
	BHRegString string = `(\d{1,5}\+*\d*\+*\d*)` + // group(1) is the BH id
		`\s+\S+_to_black_hole_at_time\s*=\s*` +
		`(\d+\.*\d*)` + // group(2) is the BH formation time in units of FIXME
		`\s*` +
		`(\S+)` // group(3) is the time unit
		//`\s*\(old mass\s*=\s*(\d+\.*\d*)\)`									// group(4) is the progenitor mass (probably wrong)
	BHReg *regexp.Regexp = regexp.MustCompile(BHRegString)
	BHRes []string

	// NS regexp
	NSRegString string = `(\d{1,5}\+*\d*\+*\d*)` + // group(1) is the NS id
		`\s+\S+_to_neutron_star_at_time\s*=\s*` +
		`(\d+\.*\d*)` + // group(2) is the NS formation time in units of FIXME
		`\s*` +
		`(\S+)` // group(3) is the time unit
		//`\s*\(old mass\s*=\s*(\d+\.*\d*)\)`									// group(4) is the progenitor mass (probably wrong)
	NSReg *regexp.Regexp = regexp.MustCompile(NSRegString)
	NSRes []string

	// WD regexp
	WDRegString string = `(\d{1,5}\+*\d*\+*\d*)` + // group(1) is the WD id
		`\s+\S+_to_\S+_dwarf_at_time\s*=\s*` +
		`(\d+\.*\d*)` + // group(2) is the WD formation time in units of FIXME
		`\s*` +
		`(\S+)` // group(3) is the time unit
		//`\s*\(old mass\s*=\s*(\d+\.*\d*)\)`									// group(4) is the progenitor mass (probably wrong)
	WDReg *regexp.Regexp = regexp.MustCompile(WDRegString)
	WDRes []string

	// Merger regexp
	MergerRegString string = `binary_evolution:\s*merger within\s*\(` + // group(1) are the two ids
		`(\d{1,5}\+*\d*\+*\d*,\d{1,5}\+*\d*\+*\d*)` +
		`\)\s*triggered by \d{1,5}\+*\d*\s*at time\s*` +
		`(\d+\.*\d*)` // group(2) is the merger time in units of FIXME
	MergerReg *regexp.Regexp = regexp.MustCompile(MergerRegString)
	MergerRes []string

	// Merger time regexp
	MergerTimeRegString string         = `Collision at time =\s*\d+\.*\d*\s*\((\d+\.*\d*)\s*\[Myr\]\)\s*between`
	MergerTimeReg       *regexp.Regexp = regexp.MustCompile(MergerTimeRegString)
	MergerTimeRes       []string

	// Collision check regexp
	CollisionResultRegString string         = `\d+\s*\((\S+);\s*M\s*=\s*(\d+\.*\S*)\s*\[Msun\]`
	CollisionResultReg    *regexp.Regexp = regexp.MustCompile(CollisionResultRegString)
	CollisionResultRes    []string

	// Binary ids check regexp
	BinIdRegString string         = `^\s*(U*)\s*(\(\S+,\S+\)):*\s+a\s=\s(\d+\.*\S*)\s+e\s=\s(\d+\.*\S*)\s+P\s=\s(\d+\.*\S*)`
	BinIdReg    *regexp.Regexp = regexp.MustCompile(CollisionResultRegString)
	BinIdRes    []string

)

func Search(snapChan chan *DumbSnapshot) {
	var (
		lineIn, lineOut string
		snap            *DumbSnapshot
		lineChan        = make(chan string, 1)
	)

	// Read lines and send them to functions with goroutines and channels
	// so if a func needs to read other lines it is possible

	// Read snap lines
	go func() {
		for snap = range snapChan {
			for _, lineIn = range snap.Lines {
				lineChan <- line
			}
		}
	}()

	// Riceive lines and search for CO or mergers or binaries
	go func() {
		for lineOut = range lineChan {
			if SearchMerger(lineOut, lineChan) {
				continue
			} else if SearchCO(lineOut) {
				continue
			} else if SearchBinaries(lineOutline, lineChan) {
				continue
			}
		}
	}()

}

func SearchMerger(line string, lineChan chan string) (bool) {
	if MergerRes = MergerReg.FindStringSubmatch(line); MergerRes == nil {
		return false
	}
	for line = range lineChan {
		if MergerTimeRes = MergerTimeReg.FindStringSubmatch(line); MergerTimeRes != nil {
			// FIXME: fill
		} else if CollisionResultRes = CollisionResultReg.FindStringSubmatch(line); CollisionResultRes != nil {
			// FIXME: fill
		}
	}
	mergerId = strings.Replace(MergerRes[1], ",", "+")
	mergerTime = MergerTimeRes[1]
	collisionResult = CollisionResultRes[1]
	collisionMass = CollisionResultRes[2]
	//FIXME check if collision result is CO in the CO list
	// qui in pratica cerchiamo di capire di che tipo sono i due oggetti coinvolti e
	// 	di conseguenza che tipo di merger e`:
	// 	* BH + BH
	// 	* NS + NS
	// 	* WD +WD
	// 	* BH + NS
	// 	* BH + WD
	// 	* NS + WD
	// 	* BH + star
	// 	* NS + star
	// 	* WD + star
	// ----
	// Send merger to merger list/channel/whatever
	// send result to appropriate destination (star, WD, NS, BH)
}

func SearchCO(line string) (bool) {
	if BHRes = BHReg.FindStringSubmatch(line); BHRes != nil {
		// Send object to appropriate destination
		return true
	} else if NSRes = NSReg.FindStringSubmatch(line); NSRes != nil {
		// Send object to appropriate destination
		return true
	} else if WDRes = WDReg.FindStringSubmatch(line); WDRes != nil {
		// Send object to appropriate destination
		return true
	} else {
		found = false
	}
}

func SearchBinaries(line string, lineChan chan string) () {

	if strings.Contains(line, "Binaries/multiples:") {
		// FIXME hardflag: H
	} else if strings.Contains(line, "ound nn pairs:") {
		// FIXME hardflag: S
	} else {
		// No binary found
		return false
	}

	// If we are here, a binary was found
	// Start a loop to find binary data
	for line = range lineChan {
		if strings.Contains(line, "Total binary energy") || strings.Contains(line, "user_diag:"){
			// End of binary parameters section
			break
		}
		if BinIdRes = BinIdReg.FindStringSubmatch(line); BinIdRes != nil {
// 			container["system_time"] = qui posso usare il timestep dello snapshot
// 			container["phys_time"] = container["system_time"] * float(self.time_unit[0])
// 			#print "Found binary in binaries section ", bin_ids.group(2)
// 			container["ids"] = bin_ids.group(2).translate(None, "()").split(",")
// 			container["hardflag"] = self.hardflag
// 			container["sma"] = float(bin_ids.group(3)) * self.r_unit[0]
// 			container["ecc"] = bin_ids.group(4)
// 			container["period"] = float(bin_ids.group(5)) * self.time_unit[0]
// 			bin_ids = None# reset ids variable
		} else if strings.Contains(line, "masses") {
// 			mass_line = line.split()[1:-3]
// 						for mass in mass_line:
// 							container["masses"].append(float(mass)*self.mass_unit[0])
// 						self.container_list.append(container)
// 						# Reinit container
// 						container = {
// 						"system_time": None,
// 						"phys_time": None,
// 						"ids": "--",
// 						"objects": [],
// 						"masses": [],
// 						"sma": "--",
// 						"period": "--",
// 						"ecc": "--"#,
		}

	}

	return true
}
<|endoftext|>


<commit_before>// Package ipam provides node-local IPAM calculations: POD IP addresses, VPP-host interconnect and node interconnect IP addresses.
//
// The IP assignment is driven by unique node ID (uint32), that is passed to the IPAM module upon its initialization,
// together with IPAM configuration (can be specified as IPAMConfig in contiv-agent-cfg ConfigMap
// in ../../k8s/contiv-vpp.yaml). The contiv-agent on each node in the k8s cluster therefore does its node-local IPAM
// calculation and assignment itself, the cluster IPAM is therefore distributed between all nodes.
//
// The package calculates and assigns the following IP addresses:
// 		- node-local POD network and individual POD IPs (based on PodSubnetCIDR, PodNetworkPrefixLen and node ID)
//		- IP subnet for the VPP-to-host Linux stack interconnect (based on VPPHostSubnetCIDR, VPPHostNetworkPrefixLen and node ID)
//		- IP address of the physical interface used for node interconnect (based on NodeInterconnectCIDR and node ID)
//
// Example:
//
//	    IPAMConfig:
//		  PodSubnetCIDR: "10.1.0.0/16"
//		  PodNetworkPrefixLen: 24
//		  VPPHostSubnetCIDR: "172.30.0.0/16"
//		  VPPHostNetworkPrefixLen: 24
//		  NodeInterconnectCIDR: "192.168.16.0/24"
//
//		Assigned node ID: 5
//
//		Calculated POD IPs: 10.1.5.2 - 10.1.5.254 (/24)
//		Calculated VPP-host interconnect IPs: 172.30.5.1, 172.30.5.2 (/24)
//  	Calculated Node Interconnect IP:  192.168.16.5 (/24)
package ipam
<commit_msg>Update documentation for IPAM to include REST<commit_after>// Package ipam provides node-local IPAM calculations: POD IP addresses, VPP-host interconnect and node interconnect IP addresses.
//
// The IP assignment is driven by unique node ID (uint32), that is passed to the IPAM module upon its initialization,
// together with IPAM configuration (can be specified as IPAMConfig in contiv-agent-cfg ConfigMap
// in ../../k8s/contiv-vpp.yaml). The contiv-agent on each node in the k8s cluster therefore does its node-local IPAM
// calculation and assignment itself, the cluster IPAM is therefore distributed between all nodes.
//
// The package calculates and assigns the following IP addresses:
// 		- node-local POD network and individual POD IPs (based on PodSubnetCIDR, PodNetworkPrefixLen and node ID)
//		- IP subnet for the VPP-to-host Linux stack interconnect (based on VPPHostSubnetCIDR, VPPHostNetworkPrefixLen and node ID)
//		- IP address of the physical interface used for node interconnect (based on NodeInterconnectCIDR and node ID)
//
// Example:
//
//	    IPAMConfig:
//		  PodSubnetCIDR: "10.1.0.0/16"
//		  PodNetworkPrefixLen: 24
//		  VPPHostSubnetCIDR: "172.30.0.0/16"
//		  VPPHostNetworkPrefixLen: 24
//		  NodeInterconnectCIDR: "192.168.16.0/24"
//
//		Assigned node ID: 5
//
//		Calculated POD IPs: 10.1.5.2 - 10.1.5.254 (/24)
//		Calculated VPP-host interconnect IPs: 172.30.5.1, 172.30.5.2 (/24)
//  	Calculated Node Interconnect IP:  192.168.16.5 (/24)
//
// Additionally the package provides REST endpoint for getting some of IPAM informations from node on URL
// GET /contiv/v1/ipam.
//
// Example:
//
//      $ curl localhost:9999/contiv/v1/ipam
//      {
//        "nodeId": 1,
//        "nodeName": "vagrant-arch.vagrantup.com",
//        "nodeIP": "192.168.16.1",
//        "podNetwork": "10.1.1.0/24",
//        "vppHostNetwork": "172.30.1.0/24"
//      }
package ipam
<|endoftext|>