<commit_before>package docker

import (
	"context"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/api/types/strslice"
	"gopkg.in/yaml.v2"
	"log"
	"net/http"
	"regexp"
	"strings"
)

const minMemory = 67108864
const maxMemory = 536870912
const defaultTag = `:latest`
const deploySuffix = `_deploy`

var networkConfig = network.NetworkingConfig{
	EndpointsConfig: map[string]*network.EndpointSettings{
		`traefik`: &network.EndpointSettings{},
	},
}

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

type dockerComposeService struct {
	Image       string
	Command     string
	Environment map[string]string
	Labels      map[string]string
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

func getConfig(service *dockerComposeService, loggedUser *user, appName string) *container.Config {
	environments := make([]string, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = loggedUser.username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if service.Command != `` {
		config.Cmd = strslice.StrSlice([]string{service.Command})
	}

	return &config
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = service.ReadOnly
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit < maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func createAppHandler(w http.ResponseWriter, loggedUser *user, appName []byte, composeFile []byte) {
	if len(appName) == 0 || len(composeFile) == 0 {
		http.Error(w, `An application name and a compose file are required`, http.StatusBadRequest)
		return
	}

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		errorHandler(w, err)
		return
	}

	appNameStr := string(appName)
	log.Print(loggedUser.username + ` deploys ` + appNameStr)

	ownerContainers, err := listContainers(loggedUser, &appNameStr)
	if err != nil {
		errorHandler(w, err)
		return
	}

	ids := make(map[string]string)
	for serviceName, service := range compose.Services {
		image := service.Image
		if !imageTag.MatchString(image) {
			image = image + defaultTag
		}

		log.Print(loggedUser.username + ` starts pulling for ` + image)
		pull, err := docker.ImagePull(context.Background(), image, types.ImagePullOptions{})
		if err != nil {
			errorHandler(w, err)
			return
		}

		readBody(pull)
		log.Print(loggedUser.username + ` ends pulling for ` + image)

		serviceFullName := appNameStr + `_` + serviceName + deploySuffix
		log.Print(loggedUser.username + ` starts ` + serviceFullName)
		id, err := docker.ContainerCreate(context.Background(), getConfig(&service, loggedUser, appNameStr), getHostConfig(&service), &networkConfig, serviceFullName)
		if err != nil {
			errorHandler(w, err)
			return
		}

		startContainer(id.ID)
		ids[id.ID] = serviceFullName
	}

	for _, container := range ownerContainers {
		log.Print(loggedUser.username + ` stops ` + strings.Join(container.Names, `, `))
		stopContainer(container.ID)
		log.Print(loggedUser.username + ` rm ` + strings.Join(container.Names, `, `))
		rmContainer(container.ID)
	}

	for id, name := range ids {
		if err := docker.ContainerRename(context.Background(), id, strings.TrimSuffix(name, deploySuffix)); err != nil {
			errorHandler(w, err)
			return
		}
	}

	jsonHttp.ResponseJSON(w, results{ids})
}
<commit_msg>Splitting into methods<commit_after>package docker

import (
	"context"
	"github.com/ViBiOh/docker-deploy/jsonHttp"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/api/types/strslice"
	"gopkg.in/yaml.v2"
	"log"
	"net/http"
	"regexp"
	"strings"
	"time"
)

const minMemory = 67108864
const maxMemory = 536870912
const defaultTag = `:latest`
const deploySuffix = `_deploy`

var networkConfig = network.NetworkingConfig{
	EndpointsConfig: map[string]*network.EndpointSettings{
		`traefik`: &network.EndpointSettings{},
	},
}

var imageTag = regexp.MustCompile(`^\S*?:\S+$`)

type dockerComposeService struct {
	Image       string
	Command     string
	Environment map[string]string
	Labels      map[string]string
	ReadOnly    bool  `yaml:"read_only"`
	CPUShares   int64 `yaml:"cpu_shares"`
	MemoryLimit int64 `yaml:"mem_limit"`
}

type dockerCompose struct {
	Version  string
	Services map[string]dockerComposeService
}

func getConfig(service *dockerComposeService, loggedUser *user, appName string) *container.Config {
	environments := make([]string, len(service.Environment))
	for key, value := range service.Environment {
		environments = append(environments, key+`=`+value)
	}

	if service.Labels == nil {
		service.Labels = make(map[string]string)
	}

	service.Labels[ownerLabel] = loggedUser.username
	service.Labels[appLabel] = appName

	config := container.Config{
		Image:  service.Image,
		Labels: service.Labels,
		Env:    environments,
	}

	if service.Command != `` {
		config.Cmd = strslice.StrSlice([]string{service.Command})
	}

	return &config
}

func getHostConfig(service *dockerComposeService) *container.HostConfig {
	hostConfig := container.HostConfig{
		LogConfig: container.LogConfig{Type: `json-file`, Config: map[string]string{
			`max-size`: `50m`,
		}},
		RestartPolicy: container.RestartPolicy{Name: `on-failure`, MaximumRetryCount: 5},
		Resources: container.Resources{
			CPUShares: 128,
			Memory:    minMemory,
		},
		SecurityOpt: []string{`no-new-privileges`},
	}

	if service.ReadOnly {
		hostConfig.ReadonlyRootfs = service.ReadOnly
	}

	if service.CPUShares != 0 {
		hostConfig.Resources.CPUShares = service.CPUShares
	}

	if service.MemoryLimit != 0 {
		if service.MemoryLimit < maxMemory {
			hostConfig.Resources.Memory = service.MemoryLimit
		} else {
			hostConfig.Resources.Memory = maxMemory
		}
	}

	return &hostConfig
}

func pullImage(image string, loggedUser *user) error {
	if !imageTag.MatchString(image) {
		image = image + defaultTag
	}

	log.Print(loggedUser.username + ` starts pulling for ` + image)
	pull, err := docker.ImagePull(context.Background(), image, types.ImagePullOptions{})
	if err != nil {
		return err
	}

	readBody(pull)
	log.Print(loggedUser.username + ` ends pulling for ` + image)
	return nil
}

func cleanContainers(containers *[]types.Container, loggedUser *user) {
	for _, container := range *containers {
		log.Print(loggedUser.username + ` stops ` + strings.Join(container.Names, `, `))
		stopContainer(container.ID)
		log.Print(loggedUser.username + ` rm ` + strings.Join(container.Names, `, `))
		rmContainer(container.ID)
	}
}

func renameDeployedContainers(containers *map[string]string) error {
	for id, name := range *containers {
		if err := docker.ContainerRename(context.Background(), id, strings.TrimSuffix(name, deploySuffix)); err != nil {
			return err
		}
	}

	return nil
}

func createAppHandler(w http.ResponseWriter, loggedUser *user, appName []byte, composeFile []byte) {
	if len(appName) == 0 || len(composeFile) == 0 {
		http.Error(w, `An application name and a compose file are required`, http.StatusBadRequest)
		return
	}

	compose := dockerCompose{}
	if err := yaml.Unmarshal(composeFile, &compose); err != nil {
		errorHandler(w, err)
		return
	}

	appNameStr := string(appName)
	log.Print(loggedUser.username + ` deploys ` + appNameStr)

	ownerContainers, err := listContainers(loggedUser, &appNameStr)
	if err != nil {
		errorHandler(w, err)
		return
	}

	deployedServices := make(map[string]string)
	for serviceName, service := range compose.Services {
		if err := pullImage(service.Image, loggedUser); err != nil {
			errorHandler(w, err)
			return
		}

		serviceFullName := appNameStr + `_` + serviceName + deploySuffix
		log.Print(loggedUser.username + ` starts ` + serviceFullName)
		id, err := docker.ContainerCreate(context.Background(), getConfig(&service, loggedUser, appNameStr), getHostConfig(&service), &networkConfig, serviceFullName)
		if err != nil {
			errorHandler(w, err)
			return
		}

		startContainer(id.ID)
		deployedServices[id.ID] = serviceFullName
	}

	log.Print(`Waiting 5 seconds for containers to start...`)
	time.Sleep(5 * time.Second)

	cleanContainers(&ownerContainers, loggedUser)
	if err := renameDeployedContainers(&deployedServices); err != nil {
		errorHandler(w, err)
		return
	}

	jsonHttp.ResponseJSON(w, results{deployedServices})
}
<|endoftext|>


<commit_before>package cell_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"time"

	"code.cloudfoundry.org/archiver/extractor/test_helper"
	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/durationjson"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/inigo/fixtures"
	"code.cloudfoundry.org/inigo/helpers"
	repconfig "code.cloudfoundry.org/rep/cmd/rep/config"
	"code.cloudfoundry.org/tlsconfig"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Evacuation", func() {
	var (
		ifritRuntime ifrit.Process

		cellAID            string
		cellARepAddr       string
		cellARepSecureAddr string

		cellBID            string
		cellBRepAddr       string
		cellBRepSecureAddr string

		cellARepRunner *ginkgomon.Runner
		cellBRepRunner *ginkgomon.Runner

		cellA ifrit.Process
		cellB ifrit.Process

		processGuid    string
		lrp            *models.DesiredLRP
		cellPortsStart uint16

		httpClient *http.Client
	)

	BeforeEach(func() {
		if runtime.GOOS == "windows" {
			Skip(" not yet working on windows")
		}
		processGuid = helpers.GenerateGuid()

		fileServer, fileServerStaticDir := componentMaker.FileServer()

		By("restarting the bbs with smaller convergeRepeatInterval")
		ginkgomon.Interrupt(bbsProcess)
		bbsProcess = ginkgomon.Invoke(componentMaker.BBS(
			overrideConvergenceRepeatInterval,
		))

		ifritRuntime = ginkgomon.Invoke(grouper.NewParallel(os.Kill, grouper.Members{
			{"router", componentMaker.Router()},
			{"file-server", fileServer},
			{"auctioneer", componentMaker.Auctioneer()},
			{"route-emitter", componentMaker.RouteEmitter()},
		}))

		cellAID = "cell-a"
		cellBID = "cell-b"

		var err error
		cellPortsStart, err = componentMaker.PortAllocator().ClaimPorts(4)
		Expect(err).NotTo(HaveOccurred())

		tlscfg, err := tlsconfig.Build(
			tlsconfig.WithInternalServiceDefaults(),
			tlsconfig.WithIdentityFromFile(componentMaker.RepSSLConfig().ServerCert, componentMaker.RepSSLConfig().ServerKey),
		).Client(
			tlsconfig.WithAuthorityFromFile(componentMaker.RepSSLConfig().CACert),
		)
		Expect(err).NotTo(HaveOccurred())

		httpClient = &http.Client{
			Timeout: 5 * time.Second,
			Transport: &http.Transport{
				TLSClientConfig: tlscfg,
			},
		}

		cellARepAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart)
		cellARepSecureAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart+1)
		cellBRepAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart+2)
		cellBRepSecureAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart+3)

		cellARepRunner = componentMaker.RepN(0,
			func(config *repconfig.RepConfig) {
				config.CellID = cellAID
				config.ListenAddr = cellARepAddr
				config.ListenAddrSecurable = cellARepSecureAddr
				config.EvacuationTimeout = durationjson.Duration(30 * time.Second)
			},
		)

		cellBRepRunner = componentMaker.RepN(1,
			func(config *repconfig.RepConfig) {
				config.CellID = cellBID
				config.ListenAddr = cellBRepAddr
				config.ListenAddrSecurable = cellBRepSecureAddr
				config.EvacuationTimeout = durationjson.Duration(30 * time.Second)
			})

		test_helper.CreateZipArchive(
			filepath.Join(fileServerStaticDir, "lrp.zip"),
			fixtures.GoServerApp(),
		)

		lrp = helpers.DefaultLRPCreateRequest(componentMaker.Addresses(), processGuid, "log-guid", 1)
	})

	JustBeforeEach(func() {
		cellA = ginkgomon.Invoke(cellARepRunner)
		cellB = ginkgomon.Invoke(cellBRepRunner)
	})

	AfterEach(func() {
		helpers.StopProcesses(ifritRuntime, cellA, cellB)
	})

	It("handles evacuation", func() {
		By("desiring an LRP")
		err := bbsClient.DesireLRP(lgr, lrp)
		Expect(err).NotTo(HaveOccurred())

		By("running an actual LRP instance")
		Eventually(helpers.LRPStatePoller(lgr, bbsClient, processGuid, nil)).Should(Equal(models.ActualLRPStateRunning))
		Eventually(helpers.ResponseCodeFromHostPoller(componentMaker.Addresses().Router, helpers.DefaultHost)).Should(Equal(http.StatusOK))

		index := int32(0)
		lrps, err := bbsClient.ActualLRPs(lgr, models.ActualLRPFilter{ProcessGuid: processGuid, Index: &index})
		Expect(err).NotTo(HaveOccurred())
		Expect(len(lrps)).To(Equal(1))
		Expect(lrps[0].Presence).NotTo(Equal(models.ActualLRP_Evacuating))

		var evacuatingRepPort uint16
		var evacuatingRepRunner *ginkgomon.Runner

		switch lrps[0].CellId {
		case cellAID:
			evacuatingRepRunner = cellARepRunner
			evacuatingRepPort = cellPortsStart
		case cellBID:
			evacuatingRepRunner = cellBRepRunner
			evacuatingRepPort = cellPortsStart + 2
		default:
			panic("what? who?")
		}

		By("posting the evacuation endpoint")
		// Rep admin endpoint verifies and validate 127.0.0.1 for IP SAN
		resp, err := httpClient.Post(fmt.Sprintf("https://127.0.0.1:%d/evacuate", evacuatingRepPort), "text/html", nil)
		Expect(err).NotTo(HaveOccurred())
		resp.Body.Close()
		Expect(resp.StatusCode).To(Equal(http.StatusAccepted))

		By("staying routable so long as its rep is alive")
		Eventually(func() int {
			Expect(helpers.ResponseCodeFromHostPoller(componentMaker.Addresses().Router, helpers.DefaultHost)()).To(Equal(http.StatusOK))
			return evacuatingRepRunner.ExitCode()
		}).Should(Equal(0))

		By("running immediately after the rep exits and is routable")
		Expect(helpers.LRPStatePoller(lgr, bbsClient, processGuid, nil)()).To(Equal(models.ActualLRPStateRunning))
		Consistently(helpers.ResponseCodeFromHostPoller(componentMaker.Addresses().Router, helpers.DefaultHost)).Should(Equal(http.StatusOK))
	})

	Context("when garden Destroy hangs", func() {
		BeforeEach(func() {
			replaceGrootFSWithHangingVersion()
			cellARepRunner = componentMaker.RepN(0,
				func(config *repconfig.RepConfig) {
					config.CellID = cellAID
					config.ListenAddr = cellARepAddr
					config.ListenAddrSecurable = cellARepSecureAddr
					config.GracefulShutdownInterval = 1 // 1 nanosecond otherwise a 0 is treated as omitted value
				},
			)
		})

		JustBeforeEach(func() {
			// kill cell-b to simplify the test. otherwise, we will have to figure
			// out which cell to evacuate
			ginkgomon.Kill(cellB)
		})

		It("shuts down gracefully after the evacuation timeout", func() {
			time.Sleep(time.Minute)

			err := bbsClient.DesireLRP(lgr, lrp)
			Expect(err).NotTo(HaveOccurred())

			By("running an actual LRP instance")
			Eventually(helpers.LRPStatePoller(lgr, bbsClient, processGuid, nil)).Should(Equal(models.ActualLRPStateRunning))

			By("posting the evacuation endpoint")
			// Rep admin endpoint verifies and validate 127.0.0.1 for IP SAN
			resp, err := httpClient.Post(fmt.Sprintf("https://127.0.0.1:%d/evacuate", cellPortsStart), "text/html", nil)
			Expect(err).NotTo(HaveOccurred())
			resp.Body.Close()
			Expect(resp.StatusCode).To(Equal(http.StatusAccepted))

			factory := componentMaker.RepClientFactory()
			addr := fmt.Sprintf("https://%s.cell.service.cf.internal:%d", cellAID, cellPortsStart)
			secureAddr := fmt.Sprintf("https://%s.cell.service.cf.internal:%d", cellAID, cellPortsStart+1)
			// NewClientFactory <<- tls
			client, err := factory.CreateClient(addr, secureAddr)
			Expect(err).NotTo(HaveOccurred())

			index := int32(0)
			lrps, err := bbsClient.ActualLRPs(lgr, models.ActualLRPFilter{ProcessGuid: lrp.ProcessGuid, Index: &index})
			Expect(err).NotTo(HaveOccurred())
			Expect(len(lrps)).To(Equal(1))

			// the following requests will hang since garden is stuck trying to destroy the containers
			go func() {
				for i := 0; i < 100; i++ {
					err := client.StopLRPInstance(lgr, lrps[0].ActualLRPKey, lrps[0].ActualLRPInstanceKey)
					if err != nil {
						return
					}
					time.Sleep(100 * time.Millisecond)
				}
			}()

			// hanging http requests shouldn't prevent the process from exiting
			Eventually(cellA.Wait(), 10*time.Second).Should(Receive())
		})
	})
})

func replaceGrootFSWithHangingVersion() {
	f, err := ioutil.TempFile(os.TempDir(), "image_plugin")
	Expect(err).NotTo(HaveOccurred())
	Expect(f.Chmod(0755)).To(Succeed())
	path := filepath.Join(os.Getenv("GROOTFS_BINPATH"), "grootfs")
	os.Remove(fmt.Sprintf("/tmp/image_plugin_sleep_%d", GinkgoParallelNode()))
	fmt.Fprintf(f, `#!/usr/bin/env bash
echo $(date +%%s) "$@" >> /tmp/image_plugin_trace
lock_file=/tmp/image_plugin_sleep_%d
# sleep on delete of non healthcheck container and only the first time
if [[ "x$3" == "xdelete" && ! ( "$4" =~ .*healthcheck.* ) && ! -f $lock_file ]]; then
  touch $lock_file
  sleep 10
fi
%s "$@"
`, GinkgoParallelNode(), path)
	Expect(f.Close()).To(Succeed())
	ginkgomon.Interrupt(gardenProcess)
	gardenProcess = ginkgomon.Invoke(componentMaker.Garden(func(config *runner.GdnRunnerConfig) {
		config.ImagePluginBin = f.Name()
		config.PrivilegedImagePluginBin = f.Name()
	}))
}
<commit_msg>Add a CellID filter to ensure we only get 1 LRP<commit_after>package cell_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"time"

	"code.cloudfoundry.org/archiver/extractor/test_helper"
	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/durationjson"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/inigo/fixtures"
	"code.cloudfoundry.org/inigo/helpers"
	repconfig "code.cloudfoundry.org/rep/cmd/rep/config"
	"code.cloudfoundry.org/tlsconfig"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Evacuation", func() {
	var (
		ifritRuntime ifrit.Process

		cellAID            string
		cellARepAddr       string
		cellARepSecureAddr string

		cellBID            string
		cellBRepAddr       string
		cellBRepSecureAddr string

		cellARepRunner *ginkgomon.Runner
		cellBRepRunner *ginkgomon.Runner

		cellA ifrit.Process
		cellB ifrit.Process

		processGuid    string
		lrp            *models.DesiredLRP
		cellPortsStart uint16

		httpClient *http.Client
	)

	BeforeEach(func() {
		if runtime.GOOS == "windows" {
			Skip(" not yet working on windows")
		}
		processGuid = helpers.GenerateGuid()

		fileServer, fileServerStaticDir := componentMaker.FileServer()

		By("restarting the bbs with smaller convergeRepeatInterval")
		ginkgomon.Interrupt(bbsProcess)
		bbsProcess = ginkgomon.Invoke(componentMaker.BBS(
			overrideConvergenceRepeatInterval,
		))

		ifritRuntime = ginkgomon.Invoke(grouper.NewParallel(os.Kill, grouper.Members{
			{"router", componentMaker.Router()},
			{"file-server", fileServer},
			{"auctioneer", componentMaker.Auctioneer()},
			{"route-emitter", componentMaker.RouteEmitter()},
		}))

		cellAID = "cell-a"
		cellBID = "cell-b"

		var err error
		cellPortsStart, err = componentMaker.PortAllocator().ClaimPorts(4)
		Expect(err).NotTo(HaveOccurred())

		tlscfg, err := tlsconfig.Build(
			tlsconfig.WithInternalServiceDefaults(),
			tlsconfig.WithIdentityFromFile(componentMaker.RepSSLConfig().ServerCert, componentMaker.RepSSLConfig().ServerKey),
		).Client(
			tlsconfig.WithAuthorityFromFile(componentMaker.RepSSLConfig().CACert),
		)
		Expect(err).NotTo(HaveOccurred())

		httpClient = &http.Client{
			Timeout: 5 * time.Second,
			Transport: &http.Transport{
				TLSClientConfig: tlscfg,
			},
		}

		cellARepAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart)
		cellARepSecureAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart+1)
		cellBRepAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart+2)
		cellBRepSecureAddr = fmt.Sprintf("0.0.0.0:%d", cellPortsStart+3)

		cellARepRunner = componentMaker.RepN(0,
			func(config *repconfig.RepConfig) {
				config.CellID = cellAID
				config.ListenAddr = cellARepAddr
				config.ListenAddrSecurable = cellARepSecureAddr
				config.EvacuationTimeout = durationjson.Duration(30 * time.Second)
			},
		)

		cellBRepRunner = componentMaker.RepN(1,
			func(config *repconfig.RepConfig) {
				config.CellID = cellBID
				config.ListenAddr = cellBRepAddr
				config.ListenAddrSecurable = cellBRepSecureAddr
				config.EvacuationTimeout = durationjson.Duration(30 * time.Second)
			})

		test_helper.CreateZipArchive(
			filepath.Join(fileServerStaticDir, "lrp.zip"),
			fixtures.GoServerApp(),
		)

		lrp = helpers.DefaultLRPCreateRequest(componentMaker.Addresses(), processGuid, "log-guid", 1)
	})

	JustBeforeEach(func() {
		cellA = ginkgomon.Invoke(cellARepRunner)
		cellB = ginkgomon.Invoke(cellBRepRunner)
	})

	AfterEach(func() {
		helpers.StopProcesses(ifritRuntime, cellA, cellB)
	})

	It("handles evacuation", func() {
		By("desiring an LRP")
		err := bbsClient.DesireLRP(lgr, lrp)
		Expect(err).NotTo(HaveOccurred())

		By("running an actual LRP instance")
		Eventually(helpers.LRPStatePoller(lgr, bbsClient, processGuid, nil)).Should(Equal(models.ActualLRPStateRunning))
		Eventually(helpers.ResponseCodeFromHostPoller(componentMaker.Addresses().Router, helpers.DefaultHost)).Should(Equal(http.StatusOK))

		index := int32(0)
		lrps, err := bbsClient.ActualLRPs(lgr, models.ActualLRPFilter{ProcessGuid: processGuid, Index: &index})
		Expect(err).NotTo(HaveOccurred())
		Expect(len(lrps)).To(Equal(1))
		Expect(lrps[0].Presence).NotTo(Equal(models.ActualLRP_Evacuating))

		var evacuatingRepPort uint16
		var evacuatingRepRunner *ginkgomon.Runner

		switch lrps[0].CellId {
		case cellAID:
			evacuatingRepRunner = cellARepRunner
			evacuatingRepPort = cellPortsStart
		case cellBID:
			evacuatingRepRunner = cellBRepRunner
			evacuatingRepPort = cellPortsStart + 2
		default:
			panic("what? who?")
		}

		By("posting the evacuation endpoint")
		// Rep admin endpoint verifies and validate 127.0.0.1 for IP SAN
		resp, err := httpClient.Post(fmt.Sprintf("https://127.0.0.1:%d/evacuate", evacuatingRepPort), "text/html", nil)
		Expect(err).NotTo(HaveOccurred())
		resp.Body.Close()
		Expect(resp.StatusCode).To(Equal(http.StatusAccepted))

		By("staying routable so long as its rep is alive")
		Eventually(func() int {
			Expect(helpers.ResponseCodeFromHostPoller(componentMaker.Addresses().Router, helpers.DefaultHost)()).To(Equal(http.StatusOK))
			return evacuatingRepRunner.ExitCode()
		}).Should(Equal(0))

		By("running immediately after the rep exits and is routable")
		Expect(helpers.LRPStatePoller(lgr, bbsClient, processGuid, nil)()).To(Equal(models.ActualLRPStateRunning))
		Consistently(helpers.ResponseCodeFromHostPoller(componentMaker.Addresses().Router, helpers.DefaultHost)).Should(Equal(http.StatusOK))
	})

	Context("when garden Destroy hangs", func() {
		BeforeEach(func() {
			replaceGrootFSWithHangingVersion()
			cellARepRunner = componentMaker.RepN(0,
				func(config *repconfig.RepConfig) {
					config.CellID = cellAID
					config.ListenAddr = cellARepAddr
					config.ListenAddrSecurable = cellARepSecureAddr
					config.GracefulShutdownInterval = 1 // 1 nanosecond otherwise a 0 is treated as omitted value
				},
			)
		})

		JustBeforeEach(func() {
			// kill cell-b to simplify the test. otherwise, we will have to figure
			// out which cell to evacuate
			ginkgomon.Kill(cellB)
		})

		It("shuts down gracefully after the evacuation timeout", func() {
			time.Sleep(time.Minute)

			err := bbsClient.DesireLRP(lgr, lrp)
			Expect(err).NotTo(HaveOccurred())

			By("running an actual LRP instance")
			Eventually(helpers.LRPStatePoller(lgr, bbsClient, processGuid, nil)).Should(Equal(models.ActualLRPStateRunning))

			By("posting the evacuation endpoint")
			// Rep admin endpoint verifies and validate 127.0.0.1 for IP SAN
			resp, err := httpClient.Post(fmt.Sprintf("https://127.0.0.1:%d/evacuate", cellPortsStart), "text/html", nil)
			Expect(err).NotTo(HaveOccurred())
			resp.Body.Close()
			Expect(resp.StatusCode).To(Equal(http.StatusAccepted))

			factory := componentMaker.RepClientFactory()
			addr := fmt.Sprintf("https://%s.cell.service.cf.internal:%d", cellAID, cellPortsStart)
			secureAddr := fmt.Sprintf("https://%s.cell.service.cf.internal:%d", cellAID, cellPortsStart+1)
			// NewClientFactory <<- tls
			client, err := factory.CreateClient(addr, secureAddr)
			Expect(err).NotTo(HaveOccurred())

			index := int32(0)
			lrps, err := bbsClient.ActualLRPs(lgr, models.ActualLRPFilter{ProcessGuid: lrp.ProcessGuid, Index: &index, CellID: cellAID})
			Expect(err).NotTo(HaveOccurred())
			Expect(len(lrps)).To(Equal(1))

			// the following requests will hang since garden is stuck trying to destroy the containers
			go func() {
				for i := 0; i < 100; i++ {
					err := client.StopLRPInstance(lgr, lrps[0].ActualLRPKey, lrps[0].ActualLRPInstanceKey)
					if err != nil {
						return
					}
					time.Sleep(100 * time.Millisecond)
				}
			}()

			// hanging http requests shouldn't prevent the process from exiting
			Eventually(cellA.Wait(), 10*time.Second).Should(Receive())
		})
	})
})

func replaceGrootFSWithHangingVersion() {
	f, err := ioutil.TempFile(os.TempDir(), "image_plugin")
	Expect(err).NotTo(HaveOccurred())
	Expect(f.Chmod(0755)).To(Succeed())
	path := filepath.Join(os.Getenv("GROOTFS_BINPATH"), "grootfs")
	os.Remove(fmt.Sprintf("/tmp/image_plugin_sleep_%d", GinkgoParallelNode()))
	fmt.Fprintf(f, `#!/usr/bin/env bash
echo $(date +%%s) "$@" >> /tmp/image_plugin_trace
lock_file=/tmp/image_plugin_sleep_%d
# sleep on delete of non healthcheck container and only the first time
if [[ "x$3" == "xdelete" && ! ( "$4" =~ .*healthcheck.* ) && ! -f $lock_file ]]; then
  touch $lock_file
  sleep 10
fi
%s "$@"
`, GinkgoParallelNode(), path)
	Expect(f.Close()).To(Succeed())
	ginkgomon.Interrupt(gardenProcess)
	gardenProcess = ginkgomon.Invoke(componentMaker.Garden(func(config *runner.GdnRunnerConfig) {
		config.ImagePluginBin = f.Name()
		config.PrivilegedImagePluginBin = f.Name()
	}))
}
<|endoftext|>


<commit_before>/*
Tensile web stress test tool

Mike Hughes 2014
intermernet AT gmail DOT com

LICENSE BSD 3 Clause
*/
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"runtime"
	"sync"
	"time"
)

const version = "0.1"

var (
	url string

	reqs int
	max  int

	wg sync.WaitGroup
)

func init() {
	flag.StringVar(&url, "url", "http://localhost/", "Target URL")
	flag.IntVar(&reqs, "reqs", 1000, "Total requests")
	flag.IntVar(&max, "concurrent", 100, "Maximum concurrent requests")
}

type Response struct {
	*http.Response
	err error
}

// Dispatcher
func dispatcher(reqChan chan *http.Request) {
	defer close(reqChan)
	for i := 0; i < reqs; i++ {
		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			log.Println(err)
		}
		reqChan <- req
	}
}

// Worker Pool
func workerPool(reqChan chan *http.Request, respChan chan Response) {
	defer close(respChan)
	t := &http.Transport{}
	defer t.CloseIdleConnections()
	for i := 0; i < max; i++ {
		wg.Add(1)
		go worker(t, reqChan, respChan)
	}
	wg.Wait()
}

// Worker
func worker(t *http.Transport, reqChan chan *http.Request, respChan chan Response) {
	defer wg.Done()
	for req := range reqChan {
		resp, err := t.RoundTrip(req)
		r := Response{resp, err}
		respChan <- r
	}
}

// Consumer
func consumer(respChan chan Response) (int64, int64) {
	var (
		conns int64
		size  int64
	)
	for r := range respChan {
		if r.err != nil {
			log.Println(r.err)
		} else {
			size += r.ContentLength
			if err := r.Body.Close(); err != nil {
				log.Println(r.err)
			}
		}
		conns++
	}
	return conns, size
}

func main() {
	flag.Parse()
	fmt.Printf("\n\tTensile web stress test tool v%s\n\n", version)
	if reqs < max {
		fmt.Println("NOTICE: Concurrent requests is greater than number of requests.")
		fmt.Println("\tChanging concurrent requests to number of requests\n")
		max = reqs
	}
	runtime.GOMAXPROCS(runtime.NumCPU())
	reqChan := make(chan *http.Request)
	respChan := make(chan Response)
	fmt.Printf("Sending %d requests to %s with %d concurrent workers.\n\n", reqs, url, max)
	start := time.Now()
	go dispatcher(reqChan)
	go workerPool(reqChan, respChan)
	fmt.Println("Waiting for replies...\n")
	conns, size := consumer(respChan)
	took := time.Since(start)
	ns := took.Nanoseconds()
	var av int64
	if conns != 0 {
		av = ns / conns
	}
	average, err := time.ParseDuration(fmt.Sprintf("%d", av) + "ns")
	if err != nil {
		log.Println(err)
	}
	fmt.Printf("Connections:\t%d\nConcurrent:\t%d\nTotal size:\t%d bytes\nTotal time:\t%s\nAverage time:\t%s\n", conns, max, size, took, average)
}
<commit_msg>More logical comparison<commit_after>/*
Tensile web stress test tool

Mike Hughes 2014
intermernet AT gmail DOT com

LICENSE BSD 3 Clause
*/
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"runtime"
	"sync"
	"time"
)

const version = "0.1"

var (
	url string

	reqs int
	max  int

	wg sync.WaitGroup
)

func init() {
	flag.StringVar(&url, "url", "http://localhost/", "Target URL")
	flag.IntVar(&reqs, "reqs", 1000, "Total requests")
	flag.IntVar(&max, "concurrent", 100, "Maximum concurrent requests")
}

type Response struct {
	*http.Response
	err error
}

// Dispatcher
func dispatcher(reqChan chan *http.Request) {
	defer close(reqChan)
	for i := 0; i < reqs; i++ {
		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			log.Println(err)
		}
		reqChan <- req
	}
}

// Worker Pool
func workerPool(reqChan chan *http.Request, respChan chan Response) {
	defer close(respChan)
	t := &http.Transport{}
	defer t.CloseIdleConnections()
	for i := 0; i < max; i++ {
		wg.Add(1)
		go worker(t, reqChan, respChan)
	}
	wg.Wait()
}

// Worker
func worker(t *http.Transport, reqChan chan *http.Request, respChan chan Response) {
	defer wg.Done()
	for req := range reqChan {
		resp, err := t.RoundTrip(req)
		r := Response{resp, err}
		respChan <- r
	}
}

// Consumer
func consumer(respChan chan Response) (int64, int64) {
	var (
		conns int64
		size  int64
	)
	for r := range respChan {
		if r.err != nil {
			log.Println(r.err)
		} else {
			size += r.ContentLength
			if err := r.Body.Close(); err != nil {
				log.Println(r.err)
			}
		}
		conns++
	}
	return conns, size
}

func main() {
	flag.Parse()
	fmt.Printf("\n\tTensile web stress test tool v%s\n\n", version)
	if max > reqs {
		fmt.Println("NOTICE: Concurrent requests is greater than number of requests.")
		fmt.Println("\tChanging concurrent requests to number of requests\n")
		max = reqs
	}
	runtime.GOMAXPROCS(runtime.NumCPU())
	reqChan := make(chan *http.Request)
	respChan := make(chan Response)
	fmt.Printf("Sending %d requests to %s with %d concurrent workers.\n\n", reqs, url, max)
	start := time.Now()
	go dispatcher(reqChan)
	go workerPool(reqChan, respChan)
	fmt.Println("Waiting for replies...\n")
	conns, size := consumer(respChan)
	took := time.Since(start)
	ns := took.Nanoseconds()
	var av int64
	if conns != 0 {
		av = ns / conns
	}
	average, err := time.ParseDuration(fmt.Sprintf("%d", av) + "ns")
	if err != nil {
		log.Println(err)
	}
	fmt.Printf("Connections:\t%d\nConcurrent:\t%d\nTotal size:\t%d bytes\nTotal time:\t%s\nAverage time:\t%s\n", conns, max, size, took, average)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Ebiten 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 shareable_test

import (
	"errors"
	"image/color"
	"os"
	"runtime"
	"testing"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/graphicsutil"
	"github.com/hajimehoshi/ebiten/internal/opengl"
	. "github.com/hajimehoshi/ebiten/internal/shareable"
	"github.com/hajimehoshi/ebiten/internal/testflock"
)

func TestMain(m *testing.M) {
	testflock.Lock()
	defer testflock.Unlock()

	code := 0
	regularTermination := errors.New("regular termination")
	f := func(screen *ebiten.Image) error {
		code = m.Run()
		return regularTermination
	}
	if err := ebiten.Run(f, 320, 240, 1, "Test"); err != nil && err != regularTermination {
		panic(err)
	}
	os.Exit(code)
}

const bigSize = 2049

func TestEnsureNotShared(t *testing.T) {
	// Create img1 and img2 with this size so that the next images are allocated
	// with non-upper-left location.
	img1 := NewImage(bigSize, 100)
	defer img1.Dispose()
	// Ensure img1's region is allocated.
	img1.ReplacePixels(make([]byte, 4*bigSize*100))

	img2 := NewImage(100, bigSize)
	defer img2.Dispose()
	img2.ReplacePixels(make([]byte, 4*100*bigSize))

	const size = 32

	img3 := NewImage(size/2, size/2)
	defer img3.Dispose()
	img3.ReplacePixels(make([]byte, (size/2)*(size/2)*4))

	img4 := NewImage(size, size)
	defer img4.Dispose()

	pix := make([]byte, size*size*4)
	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			pix[4*(i+j*size)] = byte(i + j)
			pix[4*(i+j*size)+1] = byte(i + j)
			pix[4*(i+j*size)+2] = byte(i + j)
			pix[4*(i+j*size)+3] = byte(i + j)
		}
	}
	img4.ReplacePixels(pix)

	const (
		dx0 = size / 4
		dy0 = size / 4
		dx1 = size * 3 / 4
		dy1 = size * 3 / 4
	)
	// img4.ensureNotShared() should be called.
	vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, nil)
	is := graphicsutil.QuadIndices()
	img4.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
	want := false
	if got := img4.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			got := img4.At(i, j)
			var want color.RGBA
			if i < dx0 || dx1 <= i || j < dy0 || dy1 <= j {
				c := byte(i + j)
				want = color.RGBA{c, c, c, c}
			}
			if got != want {
				t.Errorf("img4.At(%d, %d): got: %v, want: %v", i, j, got, want)
			}
		}
	}

	// Check further drawing doesn't cause panic.
	// This bug was fixed by 03dcd948.
	img4.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
}

func TestReshared(t *testing.T) {
	const size = 16

	img0 := NewImage(size, size)
	defer img0.Dispose()
	img0.ReplacePixels(make([]byte, 4*size*size))

	img1 := NewImage(size, size)
	defer img1.Dispose()
	img1.ReplacePixels(make([]byte, 4*size*size))
	want := true
	if got := img1.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	img2 := NewImage(size, size)
	defer img2.Dispose()
	pix := make([]byte, 4*size*size)
	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			pix[4*(i+j*size)] = byte(i + j)
			pix[4*(i+j*size)+1] = byte(i + j)
			pix[4*(i+j*size)+2] = byte(i + j)
			pix[4*(i+j*size)+3] = byte(i + j)
		}
	}
	img2.ReplacePixels(pix)

	img3 := NewVolatileImage(size, size)
	defer img3.Dispose()
	img1.ReplacePixels(make([]byte, 4*size*size))
	want = false
	if got := img3.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	// Use img1 as a render target.
	vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0, nil)
	is := graphicsutil.QuadIndices()
	img1.DrawImage(img2, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
	want = false
	if got := img1.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	// Use img1 as a render source.
	for i := 0; i < MaxCountForShare-1; i++ {
		img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
		want := false
		if got := img1.IsSharedForTesting(); got != want {
			t.Errorf("got: %v, want: %v", got, want)
		}
	}

	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			want := color.RGBA{byte(i + j), byte(i + j), byte(i + j), byte(i + j)}
			got := img1.At(i, j).(color.RGBA)
			if got != want {
				t.Errorf("got: %v, want: %v", got, want)
			}
		}
	}

	img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
	want = true
	if got := img1.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			want := color.RGBA{byte(i + j), byte(i + j), byte(i + j), byte(i + j)}
			got := img1.At(i, j).(color.RGBA)
			if got != want {
				t.Errorf("got: %v, want: %v", got, want)
			}
		}
	}

	// Use img3 as a render source. img3 never uses a shared texture.
	for i := 0; i < MaxCountForShare*2; i++ {
		img0.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
		want := false
		if got := img3.IsSharedForTesting(); got != want {
			t.Errorf("got: %v, want: %v", got, want)
		}
	}

	runtime.GC()
}
<commit_msg>shareable: Bug fix: test failures<commit_after>// Copyright 2018 The Ebiten 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 shareable_test

import (
	"errors"
	"image/color"
	"os"
	"runtime"
	"testing"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/graphicsutil"
	"github.com/hajimehoshi/ebiten/internal/opengl"
	. "github.com/hajimehoshi/ebiten/internal/shareable"
	"github.com/hajimehoshi/ebiten/internal/testflock"
)

func TestMain(m *testing.M) {
	testflock.Lock()
	defer testflock.Unlock()

	code := 0
	regularTermination := errors.New("regular termination")
	f := func(screen *ebiten.Image) error {
		code = m.Run()
		return regularTermination
	}
	if err := ebiten.Run(f, 320, 240, 1, "Test"); err != nil && err != regularTermination {
		panic(err)
	}
	os.Exit(code)
}

const bigSize = 2049

func TestEnsureNotShared(t *testing.T) {
	// Create img1 and img2 with this size so that the next images are allocated
	// with non-upper-left location.
	img1 := NewImage(bigSize, 100)
	defer img1.Dispose()
	// Ensure img1's region is allocated.
	img1.ReplacePixels(make([]byte, 4*bigSize*100))

	img2 := NewImage(100, bigSize)
	defer img2.Dispose()
	img2.ReplacePixels(make([]byte, 4*100*bigSize))

	const size = 32

	img3 := NewImage(size/2, size/2)
	defer img3.Dispose()
	img3.ReplacePixels(make([]byte, (size/2)*(size/2)*4))

	img4 := NewImage(size, size)
	defer img4.Dispose()

	pix := make([]byte, size*size*4)
	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			pix[4*(i+j*size)] = byte(i + j)
			pix[4*(i+j*size)+1] = byte(i + j)
			pix[4*(i+j*size)+2] = byte(i + j)
			pix[4*(i+j*size)+3] = byte(i + j)
		}
	}
	img4.ReplacePixels(pix)

	const (
		dx0 = size / 4
		dy0 = size / 4
		dx1 = size * 3 / 4
		dy1 = size * 3 / 4
	)
	// img4.ensureNotShared() should be called.
	vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, nil)
	is := graphicsutil.QuadIndices()
	img4.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
	want := false
	if got := img4.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			got := img4.At(i, j)
			var want color.RGBA
			if i < dx0 || dx1 <= i || j < dy0 || dy1 <= j {
				c := byte(i + j)
				want = color.RGBA{c, c, c, c}
			}
			if got != want {
				t.Errorf("img4.At(%d, %d): got: %v, want: %v", i, j, got, want)
			}
		}
	}

	// Check further drawing doesn't cause panic.
	// This bug was fixed by 03dcd948.
	img4.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
}

func TestReshared(t *testing.T) {
	const size = 16

	img0 := NewImage(size, size)
	defer img0.Dispose()
	img0.ReplacePixels(make([]byte, 4*size*size))

	img1 := NewImage(size, size)
	defer img1.Dispose()
	img1.ReplacePixels(make([]byte, 4*size*size))
	want := true
	if got := img1.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	img2 := NewImage(size, size)
	defer img2.Dispose()
	pix := make([]byte, 4*size*size)
	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			pix[4*(i+j*size)] = byte(i + j)
			pix[4*(i+j*size)+1] = byte(i + j)
			pix[4*(i+j*size)+2] = byte(i + j)
			pix[4*(i+j*size)+3] = byte(i + j)
		}
	}
	img2.ReplacePixels(pix)

	img3 := NewVolatileImage(size, size)
	defer img3.Dispose()
	img1.ReplacePixels(make([]byte, 4*size*size))
	want = false
	if got := img3.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	// Use img1 as a render target.
	vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0, nil)
	is := graphicsutil.QuadIndices()
	img1.DrawImage(img2, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
	want = false
	if got := img1.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	// Use img1 as a render source.
	for i := 0; i < MaxCountForShare-1; i++ {
		img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
		want := false
		if got := img1.IsSharedForTesting(); got != want {
			t.Errorf("got: %v, want: %v", got, want)
		}
	}

	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			want := color.RGBA{byte(i + j), byte(i + j), byte(i + j), byte(i + j)}
			got := img1.At(i, j)
			if got != want {
				t.Errorf("got: %v, want: %v", got, want)
			}
		}
	}

	img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
	want = true
	if got := img1.IsSharedForTesting(); got != want {
		t.Errorf("got: %v, want: %v", got, want)
	}

	for j := 0; j < size; j++ {
		for i := 0; i < size; i++ {
			want := color.RGBA{byte(i + j), byte(i + j), byte(i + j), byte(i + j)}
			got := img1.At(i, j)
			if got != want {
				t.Errorf("got: %v, want: %v", got, want)
			}
		}
	}

	// Use img3 as a render source. img3 never uses a shared texture.
	for i := 0; i < MaxCountForShare*2; i++ {
		img0.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest)
		want := false
		if got := img3.IsSharedForTesting(); got != want {
			t.Errorf("got: %v, want: %v", got, want)
		}
	}

	runtime.GC()
}
<|endoftext|>


<commit_before>package syscallcompat

import (
	"bytes"
	"syscall"

	"golang.org/x/sys/unix"

	"github.com/rfjakob/gocryptfs/internal/tlog"
)

// PATH_MAX is the maximum allowed path length on Linux.
// It is not defined on Darwin, so we use the Linux value.
const PATH_MAX = 4096

// Readlinkat is a convenience wrapper around unix.Readlinkat() that takes
// care of buffer sizing. Implemented like os.Readlink().
func Readlinkat(dirfd int, path string) (string, error) {
	// Allocate the buffer exponentially like os.Readlink does.
	for bufsz := 128; ; bufsz *= 2 {
		buf := make([]byte, bufsz)
		n, err := unix.Readlinkat(dirfd, path, buf)
		if err != nil {
			return "", err
		}
		if n < bufsz {
			return string(buf[0:n]), nil
		}
	}
}

// Faccessat exists both in Linux and in MacOS 10.10+, but the Linux version
// DOES NOT support any flags. Emulate AT_SYMLINK_NOFOLLOW like glibc does.
func Faccessat(dirfd int, path string, mode uint32) error {
	var st unix.Stat_t
	err := Fstatat(dirfd, path, &st, unix.AT_SYMLINK_NOFOLLOW)
	if err != nil {
		return err
	}
	if st.Mode&syscall.S_IFMT == syscall.S_IFLNK {
		// Pretend that a symlink is always accessible
		return nil
	}
	return unix.Faccessat(dirfd, path, mode, 0)
}

// Openat wraps the Openat syscall.
func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
	if flags&syscall.O_CREAT != 0 {
		// O_CREAT should be used with O_EXCL. O_NOFOLLOW has no effect with O_EXCL.
		if flags&syscall.O_EXCL == 0 {
			tlog.Warn.Printf("Openat: O_CREAT without O_EXCL: flags = %#x", flags)
			flags |= syscall.O_EXCL
		}
	} else {
		// If O_CREAT is not used, we should use O_NOFOLLOW
		if flags&syscall.O_NOFOLLOW == 0 {
			tlog.Warn.Printf("Openat: O_NOFOLLOW missing: flags = %#x", flags)
			flags |= syscall.O_NOFOLLOW
		}
	}
	return unix.Openat(dirfd, path, flags, mode)
}

// Renameat wraps the Renameat syscall.
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
	return unix.Renameat(olddirfd, oldpath, newdirfd, newpath)
}

// Unlinkat syscall.
func Unlinkat(dirfd int, path string, flags int) (err error) {
	return unix.Unlinkat(dirfd, path, flags)
}

// Fchownat syscall.
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
	// Why would we ever want to call this without AT_SYMLINK_NOFOLLOW?
	if flags&unix.AT_SYMLINK_NOFOLLOW == 0 {
		tlog.Warn.Printf("Fchownat: adding missing AT_SYMLINK_NOFOLLOW flag")
		flags |= unix.AT_SYMLINK_NOFOLLOW
	}
	return unix.Fchownat(dirfd, path, uid, gid, flags)
}

// Linkat exists both in Linux and in MacOS 10.10+.
func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
	return unix.Linkat(olddirfd, oldpath, newdirfd, newpath, flags)
}

// Symlinkat syscall.
func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
	return unix.Symlinkat(oldpath, newdirfd, newpath)
}

// Mkdirat syscall.
func Mkdirat(dirfd int, path string, mode uint32) (err error) {
	return unix.Mkdirat(dirfd, path, mode)
}

// Fstatat syscall.
func Fstatat(dirfd int, path string, stat *unix.Stat_t, flags int) (err error) {
	// Why would we ever want to call this without AT_SYMLINK_NOFOLLOW?
	if flags&unix.AT_SYMLINK_NOFOLLOW == 0 {
		tlog.Warn.Printf("Fstatat: adding missing AT_SYMLINK_NOFOLLOW flag")
		flags |= unix.AT_SYMLINK_NOFOLLOW
	}
	return unix.Fstatat(dirfd, path, stat, flags)
}

// Fstatat2 is a more convenient version of Fstatat. It allocates a Stat_t
// for you and also handles the Unix2syscall conversion.
func Fstatat2(dirfd int, path string, flags int) (*syscall.Stat_t, error) {
	var stUnix unix.Stat_t
	err := Fstatat(dirfd, path, &stUnix, flags)
	if err != nil {
		return nil, err
	}
	st := Unix2syscall(stUnix)
	return &st, nil
}

const XATTR_SIZE_MAX = 65536

// Make the buffer 1kB bigger so we can detect overflows
const XATTR_BUFSZ = XATTR_SIZE_MAX + 1024

// Fgetxattr is a wrapper around unix.Fgetxattr that handles the buffer sizing.
func Fgetxattr(fd int, attr string) (val []byte, err error) {
	// If the buffer is too small to fit the value, Linux and MacOS react
	// differently:
	// Linux: returns an ERANGE error and "-1" bytes.
	// MacOS: truncates the value and returns "size" bytes.
	//
	// We choose the simple approach of buffer that is bigger than the limit on
	// Linux, and return an error for everything that is bigger (which can
	// only happen on MacOS).
	//
	// See https://github.com/pkg/xattr for a smarter solution.
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Fgetxattr(fd, attr, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	// Copy only the actually used bytes to a new (smaller) buffer
	// so "buf" never leaves the function and can be allocated on the stack.
	val = make([]byte, sz)
	copy(val, buf)
	return val, nil
}

// Lgetxattr is a wrapper around unix.Lgetxattr that handles the buffer sizing.
func Lgetxattr(path string, attr string) (val []byte, err error) {
	// See the buffer sizing comments in Fgetxattr.
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Lgetxattr(path, attr, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	// Copy only the actually used bytes to a new (smaller) buffer
	// so "buf" never leaves the function and can be allocated on the stack.
	val = make([]byte, sz)
	copy(val, buf)
	return val, nil
}

// Flistxattr is a wrapper for unix.Flistxattr that handles buffer sizing and
// parsing the returned blob to a string slice.
func Flistxattr(fd int) (attrs []string, err error) {
	// See the buffer sizing comments in Fgetxattr.
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Flistxattr(fd, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	attrs = parseListxattrBlob(buf[:sz])
	return attrs, nil
}

// Llistxattr is a wrapper for unix.Llistxattr that handles buffer sizing and
// parsing the returned blob to a string slice.
func Llistxattr(path string) (attrs []string, err error) {
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Llistxattr(path, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	attrs = parseListxattrBlob(buf[:sz])
	return attrs, nil
}

func parseListxattrBlob(buf []byte) (attrs []string) {
	parts := bytes.Split(buf, []byte{0})
	for _, part := range parts {
		if len(part) == 0 {
			// Last part is empty, ignore
			continue
		}
		attrs = append(attrs, string(part))
	}
	return attrs
}
<commit_msg>syscallcompat: Openat: retry on EINTR<commit_after>package syscallcompat

import (
	"bytes"
	"syscall"

	"golang.org/x/sys/unix"

	"github.com/rfjakob/gocryptfs/internal/tlog"
)

// PATH_MAX is the maximum allowed path length on Linux.
// It is not defined on Darwin, so we use the Linux value.
const PATH_MAX = 4096

// Readlinkat is a convenience wrapper around unix.Readlinkat() that takes
// care of buffer sizing. Implemented like os.Readlink().
func Readlinkat(dirfd int, path string) (string, error) {
	// Allocate the buffer exponentially like os.Readlink does.
	for bufsz := 128; ; bufsz *= 2 {
		buf := make([]byte, bufsz)
		n, err := unix.Readlinkat(dirfd, path, buf)
		if err != nil {
			return "", err
		}
		if n < bufsz {
			return string(buf[0:n]), nil
		}
	}
}

// Faccessat exists both in Linux and in MacOS 10.10+, but the Linux version
// DOES NOT support any flags. Emulate AT_SYMLINK_NOFOLLOW like glibc does.
func Faccessat(dirfd int, path string, mode uint32) error {
	var st unix.Stat_t
	err := Fstatat(dirfd, path, &st, unix.AT_SYMLINK_NOFOLLOW)
	if err != nil {
		return err
	}
	if st.Mode&syscall.S_IFMT == syscall.S_IFLNK {
		// Pretend that a symlink is always accessible
		return nil
	}
	return unix.Faccessat(dirfd, path, mode, 0)
}

// Openat wraps the Openat syscall, retrying on EINTR.
func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
	if flags&syscall.O_CREAT != 0 {
		// O_CREAT should be used with O_EXCL. O_NOFOLLOW has no effect with O_EXCL.
		if flags&syscall.O_EXCL == 0 {
			tlog.Warn.Printf("Openat: O_CREAT without O_EXCL: flags = %#x", flags)
			flags |= syscall.O_EXCL
		}
	} else {
		// If O_CREAT is not used, we should use O_NOFOLLOW
		if flags&syscall.O_NOFOLLOW == 0 {
			tlog.Warn.Printf("Openat: O_NOFOLLOW missing: flags = %#x", flags)
			flags |= syscall.O_NOFOLLOW
		}
	}
	// Like ignoringEINTR() in the Go stdlib:
	// https://github.com/golang/go/blob/d2a80f3fb5b44450e0b304ac5a718f99c053d82a/src/os/file_posix.go#L243
	for {
		fd, err = unix.Openat(dirfd, path, flags, mode)
		if err != unix.EINTR {
			return fd, err
		}
	}
}

// Renameat wraps the Renameat syscall.
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
	return unix.Renameat(olddirfd, oldpath, newdirfd, newpath)
}

// Unlinkat syscall.
func Unlinkat(dirfd int, path string, flags int) (err error) {
	return unix.Unlinkat(dirfd, path, flags)
}

// Fchownat syscall.
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
	// Why would we ever want to call this without AT_SYMLINK_NOFOLLOW?
	if flags&unix.AT_SYMLINK_NOFOLLOW == 0 {
		tlog.Warn.Printf("Fchownat: adding missing AT_SYMLINK_NOFOLLOW flag")
		flags |= unix.AT_SYMLINK_NOFOLLOW
	}
	return unix.Fchownat(dirfd, path, uid, gid, flags)
}

// Linkat exists both in Linux and in MacOS 10.10+.
func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
	return unix.Linkat(olddirfd, oldpath, newdirfd, newpath, flags)
}

// Symlinkat syscall.
func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
	return unix.Symlinkat(oldpath, newdirfd, newpath)
}

// Mkdirat syscall.
func Mkdirat(dirfd int, path string, mode uint32) (err error) {
	return unix.Mkdirat(dirfd, path, mode)
}

// Fstatat syscall.
func Fstatat(dirfd int, path string, stat *unix.Stat_t, flags int) (err error) {
	// Why would we ever want to call this without AT_SYMLINK_NOFOLLOW?
	if flags&unix.AT_SYMLINK_NOFOLLOW == 0 {
		tlog.Warn.Printf("Fstatat: adding missing AT_SYMLINK_NOFOLLOW flag")
		flags |= unix.AT_SYMLINK_NOFOLLOW
	}
	return unix.Fstatat(dirfd, path, stat, flags)
}

// Fstatat2 is a more convenient version of Fstatat. It allocates a Stat_t
// for you and also handles the Unix2syscall conversion.
func Fstatat2(dirfd int, path string, flags int) (*syscall.Stat_t, error) {
	var stUnix unix.Stat_t
	err := Fstatat(dirfd, path, &stUnix, flags)
	if err != nil {
		return nil, err
	}
	st := Unix2syscall(stUnix)
	return &st, nil
}

const XATTR_SIZE_MAX = 65536

// Make the buffer 1kB bigger so we can detect overflows
const XATTR_BUFSZ = XATTR_SIZE_MAX + 1024

// Fgetxattr is a wrapper around unix.Fgetxattr that handles the buffer sizing.
func Fgetxattr(fd int, attr string) (val []byte, err error) {
	// If the buffer is too small to fit the value, Linux and MacOS react
	// differently:
	// Linux: returns an ERANGE error and "-1" bytes.
	// MacOS: truncates the value and returns "size" bytes.
	//
	// We choose the simple approach of buffer that is bigger than the limit on
	// Linux, and return an error for everything that is bigger (which can
	// only happen on MacOS).
	//
	// See https://github.com/pkg/xattr for a smarter solution.
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Fgetxattr(fd, attr, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	// Copy only the actually used bytes to a new (smaller) buffer
	// so "buf" never leaves the function and can be allocated on the stack.
	val = make([]byte, sz)
	copy(val, buf)
	return val, nil
}

// Lgetxattr is a wrapper around unix.Lgetxattr that handles the buffer sizing.
func Lgetxattr(path string, attr string) (val []byte, err error) {
	// See the buffer sizing comments in Fgetxattr.
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Lgetxattr(path, attr, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	// Copy only the actually used bytes to a new (smaller) buffer
	// so "buf" never leaves the function and can be allocated on the stack.
	val = make([]byte, sz)
	copy(val, buf)
	return val, nil
}

// Flistxattr is a wrapper for unix.Flistxattr that handles buffer sizing and
// parsing the returned blob to a string slice.
func Flistxattr(fd int) (attrs []string, err error) {
	// See the buffer sizing comments in Fgetxattr.
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Flistxattr(fd, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	attrs = parseListxattrBlob(buf[:sz])
	return attrs, nil
}

// Llistxattr is a wrapper for unix.Llistxattr that handles buffer sizing and
// parsing the returned blob to a string slice.
func Llistxattr(path string) (attrs []string, err error) {
	// TODO: smarter buffer sizing?
	buf := make([]byte, XATTR_BUFSZ)
	sz, err := unix.Llistxattr(path, buf)
	if err == syscall.ERANGE {
		// Do NOT return ERANGE - the user might retry ad inifinitum!
		return nil, syscall.EOVERFLOW
	}
	if err != nil {
		return nil, err
	}
	if sz >= XATTR_SIZE_MAX {
		return nil, syscall.EOVERFLOW
	}
	attrs = parseListxattrBlob(buf[:sz])
	return attrs, nil
}

func parseListxattrBlob(buf []byte) (attrs []string) {
	parts := bytes.Split(buf, []byte{0})
	for _, part := range parts {
		if len(part) == 0 {
			// Last part is empty, ignore
			continue
		}
		attrs = append(attrs, string(part))
	}
	return attrs
}
<|endoftext|>


<commit_before>package notes

import (
	// Stdlib
	"sort"

	// Internal
	"github.com/salsaflow/salsaflow/modules/common"
)

// The following types basically mirror their counterparts from the common package.
// The main difference is that the types are annotated for encoders and also
// we don't use common.Story, but our own type, which makes it possible to serialize
// easily since the struct contains fields, not methods.

type releaseNotes struct {
	Version  string                 `json:"version"  yaml:"version"`
	Sections []*releaseNotesSection `json:"sections" yaml:"sections"`
}

type releaseNotesSection struct {
	StoryType string   `json:"story_type" yaml"story_type"`
	Stories   []*story `json:"stories"    yaml:"stories"`
}

type story struct {
	Id    string `json:"id"    yaml:"id"`
	Title string `json:"title" yaml:"title"`
	URL   string `json:"url"   yaml:"url"`
}

// Implement sort.Interface to sort story sections alphabetically.
type releaseNotesSections []*releaseNotesSection

func (sections releaseNotesSections) Len() int {
	return len(sections)
}

func (sections releaseNotesSections) Less(i, j int) bool {
	return sections[i].StoryType < sections[j].StoryType
}

func (sections releaseNotesSections) Swap(i, j int) {
	sections[i], sections[j] = sections[j], sections[i]
}

// toInternalRepresentation converts the given release notes to an internal
// representation that is easily serializable any typical encoder.
func toInternalRepresentation(notes *common.ReleaseNotes) *releaseNotes {
	// Generate sections.
	var sections []*releaseNotesSection
	for _, section := range notes.Sections {
		var stories []*story
		for _, s := range section.Stories {
			stories = append(stories, &story{
				Id:    s.ReadableId(),
				Title: s.Title(),
				URL:   s.URL(),
			})
		}
		sections = append(sections, &releaseNotesSection{
			StoryType: section.StoryType,
			Stories:   stories,
		})
	}

	// Sort sections alphabetically by story type.
	sort.Sort(releaseNotesSections(sections))

	// Return the new internal representation.
	return &releaseNotes{
		Version:  notes.Version.BaseString(),
		Sections: sections,
	}
}
<commit_msg>releases/notes: Ensure proper story type format<commit_after>package notes

import (
	// Stdlib
	"sort"
	"strings"

	// Internal
	"github.com/salsaflow/salsaflow/modules/common"
)

// The following types basically mirror their counterparts from the common package.
// The main difference is that the types are annotated for encoders and also
// we don't use common.Story, but our own type, which makes it possible to serialize
// easily since the struct contains fields, not methods.

type releaseNotes struct {
	Version  string                 `json:"version"  yaml:"version"`
	Sections []*releaseNotesSection `json:"sections" yaml:"sections"`
}

type releaseNotesSection struct {
	StoryType string   `json:"story_type" yaml"story_type"`
	Stories   []*story `json:"stories"    yaml:"stories"`
}

type story struct {
	Id    string `json:"id"    yaml:"id"`
	Title string `json:"title" yaml:"title"`
	URL   string `json:"url"   yaml:"url"`
}

// Implement sort.Interface to sort story sections alphabetically.
type releaseNotesSections []*releaseNotesSection

func (sections releaseNotesSections) Len() int {
	return len(sections)
}

func (sections releaseNotesSections) Less(i, j int) bool {
	return sections[i].StoryType < sections[j].StoryType
}

func (sections releaseNotesSections) Swap(i, j int) {
	sections[i], sections[j] = sections[j], sections[i]
}

// toInternalRepresentation converts the given release notes to an internal
// representation that is easily serializable any typical encoder.
func toInternalRepresentation(notes *common.ReleaseNotes) *releaseNotes {
	// Generate sections.
	var sections []*releaseNotesSection
	for _, section := range notes.Sections {
		var stories []*story
		for _, s := range section.Stories {
			stories = append(stories, &story{
				Id:    s.ReadableId(),
				Title: s.Title(),
				URL:   s.URL(),
			})
		}
		sections = append(sections, &releaseNotesSection{
			StoryType: strings.Title(section.StoryType),
			Stories:   stories,
		})
	}

	// Sort sections alphabetically by story type.
	sort.Sort(releaseNotesSections(sections))

	// Return the new internal representation.
	return &releaseNotes{
		Version:  notes.Version.BaseString(),
		Sections: sections,
	}
}
<|endoftext|>


<commit_before><commit_msg>Fix scroll evenets getting interpeted ass button1/2 events (for real now)<commit_after><|endoftext|>


<commit_before>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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
 */

package zlib

import (
	"encoding/json"
	"net"
	"time"

	"github.com/zmap/zgrab/ztools/ssh"
	"github.com/zmap/zgrab/ztools/ztls"
)

type Grab struct {
	Host   net.IP    `json:"host"`
	Domain string    `json:"domain"`
	Time   time.Time `json:"timestamp"`
	Data   GrabData  `json:"log"`
	Error  error     `json:"error,omitempty"`
}

type ConnectionEvent struct {
	Data  EventData
	Error error
}

type encodedGrab struct {
	Host   string    `json:"host"`
	Domain string    `json:"domain,omitempty"`
	Time   string    `json:"time"`
	Data   *GrabData `json:"data"`
	Error  *string   `json:"error,omitempty"`
}

type GrabData struct {
	Banner       string                `json:"banner,omitempty"`
	Read         []byte                `json:"read,omitempty"`
	EHLO         *EHLOEvent            `json:"ehlo,omitempty"`
	SMTPHelp     *SMTPHelpEvent        `json:"smtp_help,omitempty"`
	StartTLS     *StartTLSEvent        `json:"starttls,omitempty"`
	TLSHandshake *ztls.ServerHandshake `json:"tls,omitempty"`
	Heartbleed   *ztls.Heartbleed      `json:"heartbleed,omitempty"`
	Modbus       *ModbusEvent          `json:"modbus,omitempty"`
	SSH          *ssh.HandshakeLog     `json:"ssh,omitempty"`
}

func (g *Grab) MarshalJSON() ([]byte, error) {
	time := g.Time.Format(time.RFC3339)
	var errString *string
	if g.Error != nil {
		s := g.Error.Error()
		errString = &s
	}
	obj := encodedGrab{
		Host:   g.Host.String(),
		Domain: g.Domain,
		Time:   time,
		Data:   &g.Data,
		Error:  errString,
	}
	return json.Marshal(obj)
}

func (g *Grab) UnmarshalJSON(b []byte) error {
	eg := new(encodedGrab)
	err := json.Unmarshal(b, eg)
	if err != nil {
		return err
	}
	g.Host = net.ParseIP(eg.Host)
	g.Domain = eg.Domain
	if g.Time, err = time.Parse(time.RFC3339, eg.Time); err != nil {
		return err
	}
	panic("unimplemented")
}

func (g *Grab) status() status {
	if g.Error != nil {
		return status_failure
	}
	return status_success
}
<commit_msg>Rename time to timestamp<commit_after>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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
 */

package zlib

import (
	"encoding/json"
	"net"
	"time"

	"github.com/zmap/zgrab/ztools/ssh"
	"github.com/zmap/zgrab/ztools/ztls"
)

type Grab struct {
	Host   net.IP    `json:"host"`
	Domain string    `json:"domain"`
	Time   time.Time `json:"timestamp"`
	Data   GrabData  `json:"log"`
	Error  error     `json:"error,omitempty"`
}

type ConnectionEvent struct {
	Data  EventData
	Error error
}

type encodedGrab struct {
	Host   string    `json:"host"`
	Domain string    `json:"domain,omitempty"`
	Time   string    `json:"timestamp"`
	Data   *GrabData `json:"data"`
	Error  *string   `json:"error,omitempty"`
}

type GrabData struct {
	Banner       string                `json:"banner,omitempty"`
	Read         []byte                `json:"read,omitempty"`
	EHLO         *EHLOEvent            `json:"ehlo,omitempty"`
	SMTPHelp     *SMTPHelpEvent        `json:"smtp_help,omitempty"`
	StartTLS     *StartTLSEvent        `json:"starttls,omitempty"`
	TLSHandshake *ztls.ServerHandshake `json:"tls,omitempty"`
	Heartbleed   *ztls.Heartbleed      `json:"heartbleed,omitempty"`
	Modbus       *ModbusEvent          `json:"modbus,omitempty"`
	SSH          *ssh.HandshakeLog     `json:"ssh,omitempty"`
}

func (g *Grab) MarshalJSON() ([]byte, error) {
	time := g.Time.Format(time.RFC3339)
	var errString *string
	if g.Error != nil {
		s := g.Error.Error()
		errString = &s
	}
	obj := encodedGrab{
		Host:   g.Host.String(),
		Domain: g.Domain,
		Time:   time,
		Data:   &g.Data,
		Error:  errString,
	}
	return json.Marshal(obj)
}

func (g *Grab) UnmarshalJSON(b []byte) error {
	eg := new(encodedGrab)
	err := json.Unmarshal(b, eg)
	if err != nil {
		return err
	}
	g.Host = net.ParseIP(eg.Host)
	g.Domain = eg.Domain
	if g.Time, err = time.Parse(time.RFC3339, eg.Time); err != nil {
		return err
	}
	panic("unimplemented")
}

func (g *Grab) status() status {
	if g.Error != nil {
		return status_failure
	}
	return status_success
}
<|endoftext|>


<commit_before>package clients

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"time"

	"github.com/jcelliott/lumber"

	"github.com/nanopack/mist/core"
)

type (
	// TCP represents a TCP connection to the mist server
	TCP struct {
		conn     net.Conn          // the connection the mist server
		encoder  *json.Encoder     //
		host     string            //
		messages chan mist.Message // the channel that mist server 'publishes' updates to
		token    string            //
	}
)

// New attempts to connect to a running mist server at the clients specified
// host and port.
func New(host, authtoken string) (*TCP, error) {
	client := &TCP{
		host:     host,
		messages: make(chan mist.Message),
		token:    authtoken,
	}

	return client, client.connect()
}

// connect dials the remote mist server and handles any incoming responses back
// from mist
func (c *TCP) connect() error {

	// attempt to connect to the server
	conn, err := net.Dial("tcp", c.host)
	if err != nil {
		return fmt.Errorf("Failed to dial '%s' - %s", c.host, err)
	}

	// set the connection for the client
	c.conn = conn

	// create a new json encoder for the clients connection
	c.encoder = json.NewEncoder(c.conn)

	// if the client was created with a token, authentication is needed
	if c.token != "" {
		err = c.encoder.Encode(&mist.Message{Command: "auth", Data: c.token})
		if err != nil {
			return fmt.Errorf("Failed to send auth - %s", err)
		}
	}

	// ensure we are authorized/still connected (unauthorized clients get disconnected)
	c.Ping()
	decoder := json.NewDecoder(conn)
	msg := mist.Message{}
	if err := decoder.Decode(&msg); err != nil {
		conn.Close()
		close(c.messages)
		return fmt.Errorf("Ping failed, possibly bad token, or can't read from mist")
	}

	// connection loop (blocking); continually read off the connection. Once something
	// is read, check to see if it's a message the client understands to be one of
	// its commands. If so attempt to execute the command.
	go func() {

		for {
			msg := mist.Message{}

			// decode an array value (Message)
			if err := decoder.Decode(&msg); err != nil {
				switch err {
				case io.EOF:
					lumber.Debug("[mist client] Mist terminated connection")
				case io.ErrUnexpectedEOF:
					lumber.Debug("[mist client] Mist terminated connection unexpedtedly")
				default:
					lumber.Error("[mist client] Failed to get message from mist - %s", err)
				}
				conn.Close()
				close(c.messages)
				return
			}
			c.messages <- msg // read from this using the .Messages() function
			lumber.Trace("[mist client] Received message - %#v", msg)
		}
	}()

	return nil
}

// Ping the server
func (c *TCP) Ping() error {
	return c.encoder.Encode(&mist.Message{Command: "ping"})
}

// Subscribe takes the specified tags and tells the server to subscribe to updates
// on those tags, returning the tags and an error or nil
func (c *TCP) Subscribe(tags []string) error {

	if len(tags) == 0 {
		return fmt.Errorf("Unable to subscribe - missing tags")
	}

	return c.encoder.Encode(&mist.Message{Command: "subscribe", Tags: tags})
}

// Unsubscribe takes the specified tags and tells the server to unsubscribe from
// updates on those tags, returning an error or nil
func (c *TCP) Unsubscribe(tags []string) error {

	if len(tags) == 0 {
		return fmt.Errorf("Unable to unsubscribe - missing tags")
	}

	return c.encoder.Encode(&mist.Message{Command: "unsubscribe", Tags: tags})
}

// Publish sends a message to the mist server to be published to all subscribed
// clients
func (c *TCP) Publish(tags []string, data string) error {

	if len(tags) == 0 {
		return fmt.Errorf("Unable to publish - missing tags")
	}

	if data == "" {
		return fmt.Errorf("Unable to publish - missing data")
	}

	return c.encoder.Encode(&mist.Message{Command: "publish", Tags: tags, Data: data})
}

// PublishAfter sends a message to the mist server to be published to all subscribed
// clients after a specified delay
func (c *TCP) PublishAfter(tags []string, data string, delay time.Duration) error {
	go func() {
		<-time.After(delay)
		c.Publish(tags, data)
	}()
	return nil
}

// List requests a list from the server of the tags this client is subscribed to
func (c *TCP) List() error {
	return c.encoder.Encode(&mist.Message{Command: "list"})
}

// listall related
// List requests a list from the server of the tags this client is subscribed to
func (c *TCP) ListAll() error {
	return c.encoder.Encode(&mist.Message{Command: "listall"})
}

// who related
// Who requests connection/subscriber stats from the server
func (c *TCP) Who() error {
	return c.encoder.Encode(&mist.Message{Command: "who"})
}

// Close closes the client data channel and the connection to the server
func (c *TCP) Close() {
	c.conn.Close()
	// close(c.messages) // we don't close this in case there is a message waiting in the channel
}

// Messages ...
func (c *TCP) Messages() <-chan mist.Message {
	return c.messages
}
<commit_msg>Log ping error, hopefully providing more insight<commit_after>package clients

import (
	"encoding/json"
	"fmt"
	"io"
	"net"
	"time"

	"github.com/jcelliott/lumber"

	"github.com/nanopack/mist/core"
)

type (
	// TCP represents a TCP connection to the mist server
	TCP struct {
		conn     net.Conn          // the connection the mist server
		encoder  *json.Encoder     //
		host     string            //
		messages chan mist.Message // the channel that mist server 'publishes' updates to
		token    string            //
	}
)

// New attempts to connect to a running mist server at the clients specified
// host and port.
func New(host, authtoken string) (*TCP, error) {
	client := &TCP{
		host:     host,
		messages: make(chan mist.Message),
		token:    authtoken,
	}

	return client, client.connect()
}

// connect dials the remote mist server and handles any incoming responses back
// from mist
func (c *TCP) connect() error {

	// attempt to connect to the server
	conn, err := net.Dial("tcp", c.host)
	if err != nil {
		return fmt.Errorf("Failed to dial '%s' - %s", c.host, err)
	}

	// set the connection for the client
	c.conn = conn

	// create a new json encoder for the clients connection
	c.encoder = json.NewEncoder(c.conn)

	// if the client was created with a token, authentication is needed
	if c.token != "" {
		err = c.encoder.Encode(&mist.Message{Command: "auth", Data: c.token})
		if err != nil {
			return fmt.Errorf("Failed to send auth - %s", err)
		}
	}

	// ensure we are authorized/still connected (unauthorized clients get disconnected)
	c.Ping()
	decoder := json.NewDecoder(conn)
	msg := mist.Message{}
	if err := decoder.Decode(&msg); err != nil {
		conn.Close()
		close(c.messages)
		return fmt.Errorf("Ping failed, possibly bad token, or can't read from mist - %s", err)
	}

	// connection loop (blocking); continually read off the connection. Once something
	// is read, check to see if it's a message the client understands to be one of
	// its commands. If so attempt to execute the command.
	go func() {

		for {
			msg := mist.Message{}

			// decode an array value (Message)
			if err := decoder.Decode(&msg); err != nil {
				switch err {
				case io.EOF:
					lumber.Debug("[mist client] Mist terminated connection")
				case io.ErrUnexpectedEOF:
					lumber.Debug("[mist client] Mist terminated connection unexpedtedly")
				default:
					lumber.Error("[mist client] Failed to get message from mist - %s", err)
				}
				conn.Close()
				close(c.messages)
				return
			}
			c.messages <- msg // read from this using the .Messages() function
			lumber.Trace("[mist client] Received message - %#v", msg)
		}
	}()

	return nil
}

// Ping the server
func (c *TCP) Ping() error {
	return c.encoder.Encode(&mist.Message{Command: "ping"})
}

// Subscribe takes the specified tags and tells the server to subscribe to updates
// on those tags, returning the tags and an error or nil
func (c *TCP) Subscribe(tags []string) error {

	if len(tags) == 0 {
		return fmt.Errorf("Unable to subscribe - missing tags")
	}

	return c.encoder.Encode(&mist.Message{Command: "subscribe", Tags: tags})
}

// Unsubscribe takes the specified tags and tells the server to unsubscribe from
// updates on those tags, returning an error or nil
func (c *TCP) Unsubscribe(tags []string) error {

	if len(tags) == 0 {
		return fmt.Errorf("Unable to unsubscribe - missing tags")
	}

	return c.encoder.Encode(&mist.Message{Command: "unsubscribe", Tags: tags})
}

// Publish sends a message to the mist server to be published to all subscribed
// clients
func (c *TCP) Publish(tags []string, data string) error {

	if len(tags) == 0 {
		return fmt.Errorf("Unable to publish - missing tags")
	}

	if data == "" {
		return fmt.Errorf("Unable to publish - missing data")
	}

	return c.encoder.Encode(&mist.Message{Command: "publish", Tags: tags, Data: data})
}

// PublishAfter sends a message to the mist server to be published to all subscribed
// clients after a specified delay
func (c *TCP) PublishAfter(tags []string, data string, delay time.Duration) error {
	go func() {
		<-time.After(delay)
		c.Publish(tags, data)
	}()
	return nil
}

// List requests a list from the server of the tags this client is subscribed to
func (c *TCP) List() error {
	return c.encoder.Encode(&mist.Message{Command: "list"})
}

// listall related
// List requests a list from the server of the tags this client is subscribed to
func (c *TCP) ListAll() error {
	return c.encoder.Encode(&mist.Message{Command: "listall"})
}

// who related
// Who requests connection/subscriber stats from the server
func (c *TCP) Who() error {
	return c.encoder.Encode(&mist.Message{Command: "who"})
}

// Close closes the client data channel and the connection to the server
func (c *TCP) Close() {
	c.conn.Close()
	// close(c.messages) // we don't close this in case there is a message waiting in the channel
}

// Messages ...
func (c *TCP) Messages() <-chan mist.Message {
	return c.messages
}
<|endoftext|>


<commit_before>// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux

package clipboard

import (
	"os/exec"
)

var (
	pasteCmd = exec.Command("xsel", "--output", "--clipboard")
	copyCmd  = exec.Command("xsel", "--input", "--clipboard")
)

func readAll() (string, error) {
	out, err := pasteCmd.Output()
	if err != nil {
		return "", err
	}
	return string(out), nil
}

func writeAll(text string) error {
	in, err := copyCmd.StdinPipe()
	if err != nil {
		return err
	}

	if err := copyCmd.Start(); err != nil {
		return err
	}
	if _, err := in.Write([]byte(text)); err != nil {
		return err
	}
	if err := in.Close(); err != nil {
		return err
	}
	return copyCmd.Wait()
}
<commit_msg>Fixed readAll and writeAll for linux to allow multiple calls by creating a new command for each run. Added check for xsel binary in PATH, and added support to use xclip if xsel is not found.<commit_after>// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux

package clipboard

import (
	"os/exec"
)

var (
	pasteCmdArgs 	[]string
	copyCmdArgs		[]string

	xselPaste = []string{"xsel", "--output", "--clipboard"}
	xselCopy = []string{"xsel", "--input", "--clipboard"}

	xclipPaste = []string{"xclip", "-out", "-secondary", "clipboard"}
	xclipCopy = []string{"xclip", "-in", "-secondary", "clipboard"}
)

func init() {
	_, err := exec.LookPath("xsel")
	if err != nil {
		_, err = exec.LookPath("xclip")
		if err != nil {
			println("No clipboard utilities available. Please install xset or xclip.")
			return
		}
		pasteCmdArgs = xclipPaste
		copyCmdArgs = xclipCopy
	}
	pasteCmdArgs = xselPaste
	copyCmdArgs = xselCopy
}

func getPasteCommand() *exec.Cmd {
	return exec.Command(pasteCmdArgs[0], pasteCmdArgs[1:]...)
}

func getCopyCommand() *exec.Cmd {
	return exec.Command(copyCmdArgs[0], copyCmdArgs[1:]...)
}

func readAll() (string, error) {
	pasteCmd := getPasteCommand()
	out, err := pasteCmd.Output()
	if err != nil {
		return "", err
	}
	return string(out), nil
}

func writeAll(text string) error {
	copyCmd := getCopyCommand()
	in, err := copyCmd.StdinPipe()
	if err != nil {
		return err
	}

	if err := copyCmd.Start(); err != nil {
		return err
	}
	if _, err := in.Write([]byte(text)); err != nil {
		return err
	}
	if err := in.Close(); err != nil {
		return err
	}
	return copyCmd.Wait()
}
<|endoftext|>


<commit_before>// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux

package clipboard

import (
	"os/exec"
)

var (
	pasteCmd = exec.Command("xsel --output --clipboard")
	copyCmd  = exec.Command("xsel --input --clipboard")
)

func readAll() string {
	out, err := pasteCmd.Output()
	if err != nil {
		panic(err)
	}
	return string(out)
}

func writeAll(str string) {
	in, err := copyCmd.StdinPipe()
	if err != nil {
		panic(err)
	}

	copyCmd.Start()
	in.Write([]byte(str))
	in.Close()
	copyCmd.Wait()
}
<commit_msg>Add error<commit_after>// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux

package clipboard

import (
	"os/exec"
)

var (
	pasteCmd = exec.Command("xsel --output --clipboard")
	copyCmd  = exec.Command("xsel --input --clipboard")
)

func readAll() (string, error) {
	out, err := pasteCmd.Output()
	if err != nil {
		return "", err
	}
	return string(out), nil
}

func writeAll(text string) error {
	in, err := copyCmd.StdinPipe()
	if err != nil {
		return err
	}

	if err := copyCmd.Start(); err != nil {
		return err
	}
	if _, err := in.Write([]byte(text)); err != nil {
		return err
	}
	if err := in.Close(); err != nil {
		return err
	}
	return copyCmd.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"database/sql"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"syscall"

	_ "github.com/go-sql-driver/mysql"

	"github.com/gorilla/mux"

	"github.com/domestic-apps/domestic-api/chores"
	"github.com/domestic-apps/domestic-api/tasks"

	"gopkg.in/robfig/cron.v2"

	"golang.org/x/crypto/bcrypt"
	"golang.org/x/crypto/ssh/terminal"
)

type secrets struct {
	Uname string `json:"username"`
	Pwd   string `json:"password"`
	Cert  string `json:"cert"`
	Key   string `json:"key"`
}

func main() {
	if len(os.Args) > 1 && os.Args[1] == "add-user" {
		addUser()
	} else {
		runServer()
	}
}

func addUser() {
	username, password := credentials()
	passHash, err := bcrypt.GenerateFromPassword(password, 6)
	fmt.Print("Enter Password Again: ")
	bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
	fmt.Println()
	if err != nil {
		log.Fatal("Could not get the password, oh no!")
	}
	err = bcrypt.CompareHashAndPassword(passHash, bytePassword)
	if err != nil {
		log.Fatal("Passwords did not match, or some other thing went wrong")
	}
	fmt.Println("This would be the part where we add username and passHash to the database: " + username)
}

// credentials gets username and password credentials from the command line.
// This was totally stolen from https://play.golang.org/p/l-9IP1mrhA
func credentials() (string, []byte) {
	reader := bufio.NewReader(os.Stdin)

	fmt.Print("Enter Username: ")
	username, _ := reader.ReadString('\n')

	fmt.Print("Enter Password: ")
	bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
	fmt.Println()
	if err != nil {
		log.Fatal("Could not get the password, oh no!")
	}

	return strings.TrimSpace(username), bytePassword
}

func runServer() {
	// get mysql username and password from configuration
	file, err := ioutil.ReadFile("./secrets.json")
	if err != nil {
		log.Fatal("File error: %v\n", err)
	}

	var s secrets
	json.Unmarshal(file, &s)
	timezone := "America/Los_Angeles"

	// Set up Database
	db, err := sql.Open("mysql",
		s.Uname+":"+s.Pwd+"@tcp(localhost:3306)/domestic?parseTime=true")
	if err != nil {
		log.Fatal(err)
	}
	if err = db.Ping(); err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Prepare statements in application handlers.
	choresHandler := chores.InitializeHandler(db)
	tasksHandler := tasks.InitializeHandler(db, timezone)
	r := mux.NewRouter()
	r.HandleFunc("/chores/", choresHandler.HandleCreate).Methods("POST").Schemes("https")
	r.HandleFunc("/chores/", choresHandler.HandleReadList).Methods("GET").Schemes("https")
	r.HandleFunc("/chores/", choresHandler.HandleUpdate).Methods("PUT").Schemes("https")
	r.HandleFunc("/chores/", choresHandler.HandleDelete).Methods("DELETE").Schemes("https")
	r.HandleFunc("/tasks/", tasksHandler.Handle)
	c := cron.New()
	c.AddFunc("TZ="+timezone+" 0 0 7,19 * * *", tasksHandler.Cron) // 7am and 7pm every day
	c.Start()
	log.Fatal(http.ListenAndServeTLS(":443", s.Cert, s.Key, r))
}
<commit_msg>maybe like this?<commit_after>package main

import (
	"bufio"
	"database/sql"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"syscall"

	_ "github.com/go-sql-driver/mysql"

	"github.com/gorilla/mux"

	"github.com/domestic-apps/domestic-api/chores"
	"github.com/domestic-apps/domestic-api/tasks"

	"gopkg.in/robfig/cron.v2"

	"golang.org/x/crypto/bcrypt"
	"golang.org/x/crypto/ssh/terminal"
)

type secrets struct {
	Uname string `json:"username"`
	Pwd   string `json:"password"`
	Cert  string `json:"cert"`
	Key   string `json:"key"`
}

func main() {
	if len(os.Args) > 1 && os.Args[1] == "add-user" {
		addUser()
	} else {
		runServer()
	}
}

func addUser() {
	username, password := credentials()
	passHash, err := bcrypt.GenerateFromPassword(password, 6)
	fmt.Print("Enter Password Again: ")
	bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
	fmt.Println()
	if err != nil {
		log.Fatal("Could not get the password, oh no!")
	}
	err = bcrypt.CompareHashAndPassword(passHash, bytePassword)
	if err != nil {
		log.Fatal("Passwords did not match, or some other thing went wrong")
	}
	fmt.Println("This would be the part where we add username and passHash to the database: " + username)
}

// credentials gets username and password credentials from the command line.
// This was totally stolen from https://play.golang.org/p/l-9IP1mrhA
func credentials() (string, []byte) {
	reader := bufio.NewReader(os.Stdin)

	fmt.Print("Enter Username: ")
	username, _ := reader.ReadString('\n')

	fmt.Print("Enter Password: ")
	bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
	fmt.Println()
	if err != nil {
		log.Fatal("Could not get the password, oh no!")
	}

	return strings.TrimSpace(username), bytePassword
}

func runServer() {
	// get mysql username and password from configuration
	file, err := ioutil.ReadFile("./secrets.json")
	if err != nil {
		log.Fatal("File error: %v\n", err)
	}

	var s secrets
	json.Unmarshal(file, &s)
	timezone := "America/Los_Angeles"

	// Set up Database
	db, err := sql.Open("mysql",
		s.Uname+":"+s.Pwd+"@tcp(localhost:3306)/domestic?parseTime=true")
	if err != nil {
		log.Fatal(err)
	}
	if err = db.Ping(); err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Prepare statements in application handlers.
	choresHandler := chores.InitializeHandler(db)
	tasksHandler := tasks.InitializeHandler(db, timezone)
	r := mux.NewRouter()
	r.HandleFunc("/chores/", choresHandler.HandleCreate).Methods("POST").Schemes("https")
	r.HandleFunc("/chores/", choresHandler.HandleReadList).Methods("GET").Schemes("https")
	r.HandleFunc("/chores/", choresHandler.HandleUpdate).Methods("PUT").Schemes("https")
	r.HandleFunc("/chores/", choresHandler.HandleDelete).Methods("DELETE").Schemes("https")
	r.HandleFunc("/tasks/", tasksHandler.Handle)
	c := cron.New()
	c.AddFunc("TZ="+timezone+" 0 0 7,19 * * *", tasksHandler.Cron) // 7am and 7pm every day
	c.Start()
	http.Handle("/", r)
	log.Fatal(http.ListenAndServeTLS(":443", s.Cert, s.Key, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/cmd"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/app"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/credential"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/info"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/space"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/options"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/terminal"
	"github.com/cloudfoundry/cli/plugin"
	"golang.org/x/crypto/ssh"
)

type SSHPlugin struct {
	OutputWriter io.Writer
}

func (p *SSHPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "Diego-SSH",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 1,
			Build: 2,
		},
		Commands: []plugin.Command{
			{
				Name:     "ssh",
				HelpText: "ssh to an application container instance",
				UsageDetails: plugin.Usage{
					Usage: options.SSHUsage(),
				},
			},
			{
				Name:     "enable-ssh",
				HelpText: "enable ssh for the application",
				UsageDetails: plugin.Usage{
					Usage: cmd.EnableSSHUsage,
				},
			},
			{
				Name:     "disable-ssh",
				HelpText: "disable ssh for the application",
				UsageDetails: plugin.Usage{
					Usage: cmd.DisableSSHUsage,
				},
			},
			{
				Name:     "ssh-enabled",
				HelpText: "reports whether SSH is enabled on an application container instance",
				UsageDetails: plugin.Usage{
					Usage: cmd.SSHEnabledUsage,
				},
			},
			{
				Name:     "allow-space-ssh",
				HelpText: "allow SSH access for the space",
				UsageDetails: plugin.Usage{
					Usage: cmd.AllowSSHUsage,
				},
			},
			{
				Name:     "disallow-space-ssh",
				HelpText: "disallow SSH access for the space",
				UsageDetails: plugin.Usage{
					Usage: cmd.DisallowSSHUsage,
				},
			},
			{
				Name:     "space-ssh-allowed",
				HelpText: "reports whether SSH is allowed in a space",
				UsageDetails: plugin.Usage{
					Usage: cmd.SSHAllowedUsage,
				},
			},
			{
				Name:     "get-ssh-code",
				HelpText: "get a one time password for ssh clients",
				UsageDetails: plugin.Usage{
					Usage: cmd.GetSSHCodeUsage,
				},
			},
		},
	}
}

func (p *SSHPlugin) Run(cli plugin.CliConnection, args []string) {
	p.OutputWriter = os.Stdout
	appFactory := app.NewAppFactory(cli, models.Curl)
	infoFactory := info.NewInfoFactory(cli)
	credFactory := credential.NewCredentialFactory(cli, infoFactory)
	spaceFactory := space.NewSpaceFactory(cli, models.Curl)

	switch args[0] {
	case "CLI-MESSAGE-UNINSTALL":
		return
	case "enable-ssh":
		err := cmd.EnableSSH(args, appFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "disable-ssh":
		err := cmd.DisableSSH(args, appFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "ssh-enabled":
		err := cmd.SSHEnabled(args, appFactory, p.OutputWriter)
		if err != nil {
			p.Fatal(err)
		}
	case "allow-space-ssh":
		err := cmd.AllowSSH(args, spaceFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "disallow-space-ssh":
		err := cmd.DisallowSSH(args, spaceFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "space-ssh-allowed":
		err := cmd.SSHAllowed(args, spaceFactory, p.OutputWriter)
		if err != nil {
			p.Fatal(err)
		}
	case "get-ssh-code":
		err := cmd.GetSSHCode(args, credFactory, p.OutputWriter)
		if err != nil {
			p.Fatal(err)
		}
	case "ssh":
		opts := options.NewSSHOptions()
		err := opts.Parse(args)
		if err != nil {
			p.Fail(err.Error())
			fmt.Fprintf(p.OutputWriter, options.SSHUsage())
			return
		}

		secureShell := cmd.NewSecureShell(
			cmd.DefaultSecureDialer(),
			terminal.DefaultHelper(),
			cmd.DefaultListenerFactory(),
			30*time.Second,
			appFactory,
			infoFactory,
			credFactory,
		)

		err = secureShell.Connect(opts)
		if err != nil {
			p.Fail(err.Error())
			return
		}
		defer secureShell.Close()

		err = secureShell.LocalPortForward()
		if err != nil {
			return
		}

		if opts.SkipRemoteExecution {
			err = secureShell.Wait()
		} else {
			err = secureShell.InteractiveSession()
		}

		if err == nil {
			return
		}

		if exitError, ok := err.(*ssh.ExitError); ok {
			exitStatus := exitError.ExitStatus()
			if sig := exitError.Signal(); sig != "" {
				fmt.Printf("Process terminated by signal: %s. Exited with %d.\n", sig, exitStatus)
			}
			os.Exit(exitStatus)
		} else {
			p.Fail(err.Error())
		}

	default:
		p.Fail("Invalid command")
	}
}

func (p *SSHPlugin) Fatal(err error) {
	p.Fail(err.Error())
	os.Exit(1)
}

func (p *SSHPlugin) Fail(message string) {
	fmt.Fprintf(p.OutputWriter, "FAILED\n\n%s\n", message)
}
<commit_msg>Update plugin version<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"time"

	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/cmd"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/app"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/credential"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/info"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/space"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/options"
	"github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/terminal"
	"github.com/cloudfoundry/cli/plugin"
	"golang.org/x/crypto/ssh"
)

type SSHPlugin struct {
	OutputWriter io.Writer
}

func (p *SSHPlugin) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "Diego-SSH",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 2,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "ssh",
				HelpText: "ssh to an application container instance",
				UsageDetails: plugin.Usage{
					Usage: options.SSHUsage(),
				},
			},
			{
				Name:     "enable-ssh",
				HelpText: "enable ssh for the application",
				UsageDetails: plugin.Usage{
					Usage: cmd.EnableSSHUsage,
				},
			},
			{
				Name:     "disable-ssh",
				HelpText: "disable ssh for the application",
				UsageDetails: plugin.Usage{
					Usage: cmd.DisableSSHUsage,
				},
			},
			{
				Name:     "ssh-enabled",
				HelpText: "reports whether SSH is enabled on an application container instance",
				UsageDetails: plugin.Usage{
					Usage: cmd.SSHEnabledUsage,
				},
			},
			{
				Name:     "allow-space-ssh",
				HelpText: "allow SSH access for the space",
				UsageDetails: plugin.Usage{
					Usage: cmd.AllowSSHUsage,
				},
			},
			{
				Name:     "disallow-space-ssh",
				HelpText: "disallow SSH access for the space",
				UsageDetails: plugin.Usage{
					Usage: cmd.DisallowSSHUsage,
				},
			},
			{
				Name:     "space-ssh-allowed",
				HelpText: "reports whether SSH is allowed in a space",
				UsageDetails: plugin.Usage{
					Usage: cmd.SSHAllowedUsage,
				},
			},
			{
				Name:     "get-ssh-code",
				HelpText: "get a one time password for ssh clients",
				UsageDetails: plugin.Usage{
					Usage: cmd.GetSSHCodeUsage,
				},
			},
		},
	}
}

func (p *SSHPlugin) Run(cli plugin.CliConnection, args []string) {
	p.OutputWriter = os.Stdout
	appFactory := app.NewAppFactory(cli, models.Curl)
	infoFactory := info.NewInfoFactory(cli)
	credFactory := credential.NewCredentialFactory(cli, infoFactory)
	spaceFactory := space.NewSpaceFactory(cli, models.Curl)

	switch args[0] {
	case "CLI-MESSAGE-UNINSTALL":
		return
	case "enable-ssh":
		err := cmd.EnableSSH(args, appFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "disable-ssh":
		err := cmd.DisableSSH(args, appFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "ssh-enabled":
		err := cmd.SSHEnabled(args, appFactory, p.OutputWriter)
		if err != nil {
			p.Fatal(err)
		}
	case "allow-space-ssh":
		err := cmd.AllowSSH(args, spaceFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "disallow-space-ssh":
		err := cmd.DisallowSSH(args, spaceFactory)
		if err != nil {
			p.Fatal(err)
		}
	case "space-ssh-allowed":
		err := cmd.SSHAllowed(args, spaceFactory, p.OutputWriter)
		if err != nil {
			p.Fatal(err)
		}
	case "get-ssh-code":
		err := cmd.GetSSHCode(args, credFactory, p.OutputWriter)
		if err != nil {
			p.Fatal(err)
		}
	case "ssh":
		opts := options.NewSSHOptions()
		err := opts.Parse(args)
		if err != nil {
			p.Fail(err.Error())
			fmt.Fprintf(p.OutputWriter, options.SSHUsage())
			return
		}

		secureShell := cmd.NewSecureShell(
			cmd.DefaultSecureDialer(),
			terminal.DefaultHelper(),
			cmd.DefaultListenerFactory(),
			30*time.Second,
			appFactory,
			infoFactory,
			credFactory,
		)

		err = secureShell.Connect(opts)
		if err != nil {
			p.Fail(err.Error())
			return
		}
		defer secureShell.Close()

		err = secureShell.LocalPortForward()
		if err != nil {
			return
		}

		if opts.SkipRemoteExecution {
			err = secureShell.Wait()
		} else {
			err = secureShell.InteractiveSession()
		}

		if err == nil {
			return
		}

		if exitError, ok := err.(*ssh.ExitError); ok {
			exitStatus := exitError.ExitStatus()
			if sig := exitError.Signal(); sig != "" {
				fmt.Printf("Process terminated by signal: %s. Exited with %d.\n", sig, exitStatus)
			}
			os.Exit(exitStatus)
		} else {
			p.Fail(err.Error())
		}

	default:
		p.Fail("Invalid command")
	}
}

func (p *SSHPlugin) Fatal(err error) {
	p.Fail(err.Error())
	os.Exit(1)
}

func (p *SSHPlugin) Fail(message string) {
	fmt.Fprintf(p.OutputWriter, "FAILED\n\n%s\n", message)
}
<|endoftext|>