<commit_before>/*
 * This file is part of the kubevirt project
 *
 * 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.
 *
 * Copyright 2022 Red Hat, Inc.
 *
 */

package network

import (
	"fmt"
	"time"

	expect "github.com/google/goexpect"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	k8sv1 "k8s.io/api/core/v1"

	v1 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/kubecli"

	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/console"
	"kubevirt.io/kubevirt/tests/flags"
	"kubevirt.io/kubevirt/tests/libnet"
	"kubevirt.io/kubevirt/tests/libvmi"
	"kubevirt.io/kubevirt/tests/util"
)

var _ = SIGDescribe("[Serial] Passt", func() {
	var err error
	var virtClient kubecli.KubevirtClient

	BeforeEach(func() {
		virtClient, err = kubecli.GetKubevirtClient()
		util.PanicOnError(err)
	})

	Context("VirtualMachineInstance with passt binding mechanism", func() {

		It("should report the IP to the status", func() {
			vmi := libvmi.NewAlpineWithTestTooling(
				withPasstInterfaceWithPort(),
				libvmi.WithNetwork(v1.DefaultPodNetwork()),
			)

			vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmi)
			Expect(err).ToNot(HaveOccurred())
			vmi = tests.WaitUntilVMIReady(vmi, console.LoginToAlpine)

			Expect(vmi.Status.Interfaces).To(HaveLen(1))
			Expect(vmi.Status.Interfaces[0].IPs).NotTo(BeEmpty())
			Expect(vmi.Status.Interfaces[0].IP).NotTo(BeEmpty())
		})

		Context("should allow regular network connection", func() {
			Context("should have client server connectivity", func() {
				var clientVMI *v1.VirtualMachineInstance
				var serverVMI *v1.VirtualMachineInstance

				startServerVMI := func(ports []v1.Port) {
					serverVMI = libvmi.NewAlpineWithTestTooling(
						libvmi.WithInterface(libvmi.InterfaceDeviceWithPasstBinding(ports...)),
						libvmi.WithNetwork(v1.DefaultPodNetwork()),
						withPasstExtendedResourceMemory(ports...),
					)

					serverVMI, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(serverVMI)
					Expect(err).ToNot(HaveOccurred())
					serverVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(serverVMI)
					Expect(console.LoginToAlpine(serverVMI)).To(Succeed())
				}

				Context("TCP", func() {
					checkConnectionToServer := func(serverIP string, port int, expectSuccess bool) []expect.Batcher {
						expectResult := console.ShellFail
						if expectSuccess {
							expectResult = console.ShellSuccess
						}

						clientCommand := fmt.Sprintf("echo test | nc %s %d -i 1 -w 1 1> /dev/null\n", serverIP, port)

						return []expect.Batcher{
							&expect.BSnd{S: "\n"},
							&expect.BExp{R: console.PromptExpression},
							&expect.BSnd{S: clientCommand},
							&expect.BExp{R: console.PromptExpression},
							&expect.BSnd{S: tests.EchoLastReturnValue},
							&expect.BExp{R: expectResult},
						}
					}

					verifyClientServerConnectivity := func(clientVMI *v1.VirtualMachineInstance, serverVMI *v1.VirtualMachineInstance, tcpPort int, ipFamily k8sv1.IPFamily) error {
						serverIP := libnet.GetVmiPrimaryIPByFamily(serverVMI, ipFamily)
						err := libnet.PingFromVMConsole(clientVMI, serverIP)
						if err != nil {
							return err
						}

						By("Connecting from the client VM")
						err = console.SafeExpectBatch(clientVMI, checkConnectionToServer(serverIP, tcpPort, true), 30)
						if err != nil {
							return err
						}

						return nil
					}

					startClientVMI := func() {
						clientVMI = libvmi.NewAlpineWithTestTooling(
							withPasstInterfaceWithPort(),
							libvmi.WithNetwork(v1.DefaultPodNetwork()),
						)

						clientVMI, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(clientVMI)
						Expect(err).ToNot(HaveOccurred())
						clientVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(clientVMI)
						Expect(console.LoginToAlpine(clientVMI)).To(Succeed())
					}
					DescribeTable("Client server connectivity", func(ports []v1.Port, tcpPort int, ipFamily k8sv1.IPFamily) {
						libnet.SkipWhenClusterNotSupportIPFamily(virtClient, ipFamily)

						By("starting a client VMI")
						startClientVMI()

						By("starting a server VMI")
						startServerVMI(ports)

						By("starting a TCP server")
						tests.StartTCPServer(serverVMI, tcpPort, console.LoginToAlpine)

						Expect(verifyClientServerConnectivity(clientVMI, serverVMI, tcpPort, k8sv1.IPv4Protocol)).To(Succeed())

						if len(ports) != 0 {
							By("starting a TCP server on a port not specified on the VM spec")
							vmPort := int(ports[0].Port)
							serverIP := libnet.GetVmiPrimaryIPByFamily(serverVMI, ipFamily)

							tests.StartTCPServer(serverVMI, vmPort+1, console.LoginToAlpine)

							By("Connecting from the client VM to a port not specified on the VM spec")
							Expect(console.SafeExpectBatch(clientVMI, checkConnectionToServer(serverIP, tcpPort+1, true), 30)).To(Not(Succeed()))
						}
					},
						Entry("with a specific port number [IPv4]", []v1.Port{{Name: "http", Port: 8080, Protocol: "TCP"}}, 8080, k8sv1.IPv4Protocol),
						Entry("without a specific port number [IPv4]", []v1.Port{}, 8080, k8sv1.IPv4Protocol),
						Entry("with a specific port number [IPv6]", []v1.Port{{Name: "http", Port: 8080, Protocol: "TCP"}}, 8080, k8sv1.IPv6Protocol),
						Entry("without a specific port number [IPv6]", []v1.Port{}, 8080, k8sv1.IPv6Protocol),
					)
				})

				Context("UDP", func() {
					startAndVerifyUDPClient := func(vmi *v1.VirtualMachineInstance, serverIP string, serverPort int, ipFamily k8sv1.IPFamily) error {
						var inetSuffix string
						if ipFamily == k8sv1.IPv6Protocol {
							inetSuffix = "6"
						}

						createClientScript := fmt.Sprintf(`cat >udp_client.py <<EOL
import socket
try:
  client = socket.socket(socket.AF_INET%s, socket.SOCK_DGRAM);
  client.sendto("Hello Server".encode(), ("%s",%d));
  client.settimeout(5);
  response = client.recv(1024);
  print(response.decode("utf-8"));

except socket.timeout:
    client.close();
EOL`, inetSuffix, serverIP, serverPort)
						runClient := "python3 udp_client.py"
						return console.ExpectBatch(vmi, []expect.Batcher{
							&expect.BSnd{S: fmt.Sprintf("%s\n", createClientScript)},
							&expect.BExp{R: console.PromptExpression},
							&expect.BSnd{S: fmt.Sprintf("%s\n", runClient)},
							&expect.BExp{R: console.RetValue("Hello Client")},
							&expect.BSnd{S: tests.EchoLastReturnValue},
							&expect.BExp{R: console.ShellSuccess},
						}, 60*time.Second)
					}
					DescribeTable("Client server connectivity", func(ipFamily k8sv1.IPFamily) {
						libnet.SkipWhenClusterNotSupportIPFamily(virtClient, ipFamily)

						const SERVER_PORT = 1700

						By("Starting server VMI")
						startServerVMI([]v1.Port{{Port: SERVER_PORT, Protocol: "UDP"}})
						serverVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(serverVMI)
						Expect(console.LoginToAlpine(serverVMI)).To(Succeed())

						By("Starting a UDP server")
						tests.StartPythonUDPServer(serverVMI, SERVER_PORT, ipFamily)

						By("Starting client VMI")
						clientVMI = libvmi.NewAlpineWithTestTooling(
							libvmi.WithInterface(libvmi.InterfaceDeviceWithPasstBinding()),
							libvmi.WithNetwork(v1.DefaultPodNetwork()),
							withPasstExtendedResourceMemory(),
						)
						clientVMI, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(clientVMI)
						Expect(err).ToNot(HaveOccurred())
						clientVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(clientVMI)
						Expect(console.LoginToAlpine(clientVMI)).To(Succeed())
						console.LoginToAlpine(clientVMI)

						By("Starting and verifying UDP client")
						// Due to a passt bug, at least one UDPv6 message has to be sent from a machine before it can receive UDPv6 messages
						// Tracking bug - https://bugs.passt.top/show_bug.cgi?id=16
						if ipFamily == k8sv1.IPv6Protocol {
							clientIP := libnet.GetVmiPrimaryIPByFamily(clientVMI, ipFamily)
							Expect(libnet.PingFromVMConsole(serverVMI, clientIP)).To(Succeed())
						}
						serverIP := libnet.GetVmiPrimaryIPByFamily(serverVMI, ipFamily)
						Expect(startAndVerifyUDPClient(clientVMI, serverIP, SERVER_PORT, ipFamily)).To(Succeed())
					},
						Entry("[IPv4]", k8sv1.IPv4Protocol),
						Entry("[IPv6]", k8sv1.IPv6Protocol),
					)
				})
			})

			It("[outside_connectivity]should be able to reach the outside world [IPv4]", func() {
				libnet.SkipWhenClusterNotSupportIpv4(virtClient)
				ipv4Address := "8.8.8.8"
				if flags.IPV4ConnectivityCheckAddress != "" {
					ipv4Address = flags.IPV4ConnectivityCheckAddress
				}
				dns := "google.com"
				if flags.ConnectivityCheckDNS != "" {
					dns = flags.ConnectivityCheckDNS
				}

				vmi := libvmi.NewAlpineWithTestTooling(
					withPasstInterfaceWithPort(),
					libvmi.WithNetwork(v1.DefaultPodNetwork()),
				)
				vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmi)
				Expect(err).ToNot(HaveOccurred())
				vmi = tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
				Expect(console.LoginToAlpine(vmi)).To(Succeed())

				By("Checking ping (IPv4)")
				Expect(libnet.PingFromVMConsole(vmi, ipv4Address, "-c 5", "-w 15")).To(Succeed())
				Expect(libnet.PingFromVMConsole(vmi, dns, "-c 5", "-w 15")).To(Succeed())
			})

			It("[outside_connectivity]should be able to reach the outside world [IPv6]", func() {
				libnet.SkipWhenClusterNotSupportIpv6(virtClient)
				// Cluster nodes subnet (docker network gateway)
				// Docker network subnet cidr definition:
				// https://github.com/kubevirt/project-infra/blob/master/github/ci/shared-deployments/files/docker-daemon-mirror.conf#L5
				ipv6Address := "2001:db8:1::1"
				if flags.IPV6ConnectivityCheckAddress != "" {
					ipv6Address = flags.IPV6ConnectivityCheckAddress
				}

				vmi := libvmi.NewAlpineWithTestTooling(
					withPasstInterfaceWithPort(),
					libvmi.WithNetwork(v1.DefaultPodNetwork()),
				)
				Expect(err).ToNot(HaveOccurred())
				vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmi)
				Expect(err).ToNot(HaveOccurred())
				vmi = tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
				Expect(console.LoginToAlpine(vmi)).To(Succeed())

				By("Checking ping (IPv6) from VM to cluster nodes gateway")
				Expect(libnet.PingFromVMConsole(vmi, ipv6Address)).To(Succeed())
			})
		})
	})
})

func withPasstExtendedResourceMemory(ports ...v1.Port) libvmi.Option {
	if len(ports) == 0 {
		return libvmi.WithResourceMemory("2048M")
	}
	return func(vmi *v1.VirtualMachineInstance) {
	}
}

func withPasstInterfaceWithPort() libvmi.Option {
	return libvmi.WithInterface(libvmi.InterfaceDeviceWithPasstBinding([]v1.Port{{Port: 1234, Protocol: "TCP"}}...))
}
<commit_msg>passt, tests: Enable DHCP<commit_after>/*
 * This file is part of the kubevirt project
 *
 * 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.
 *
 * Copyright 2022 Red Hat, Inc.
 *
 */

package network

import (
	"fmt"
	"time"

	expect "github.com/google/goexpect"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	k8sv1 "k8s.io/api/core/v1"

	v1 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/kubecli"

	"kubevirt.io/kubevirt/tests"
	"kubevirt.io/kubevirt/tests/console"
	"kubevirt.io/kubevirt/tests/flags"
	"kubevirt.io/kubevirt/tests/libnet"
	"kubevirt.io/kubevirt/tests/libvmi"
	"kubevirt.io/kubevirt/tests/util"
)

var _ = SIGDescribe("[Serial] Passt", func() {
	var err error
	var virtClient kubecli.KubevirtClient
	var networkData string

	BeforeEach(func() {
		virtClient, err = kubecli.GetKubevirtClient()
		util.PanicOnError(err)

		networkData, err = libnet.NewNetworkData(
			libnet.WithEthernet("eth0",
				libnet.WithDHCP6Enabled(),
			),
		)
	})

	Context("VirtualMachineInstance with passt binding mechanism", func() {

		It("should report the IP to the status", func() {
			vmi := libvmi.NewAlpineWithTestTooling(
				withPasstInterfaceWithPort(),
				libvmi.WithNetwork(v1.DefaultPodNetwork()),
				libvmi.WithCloudInitNoCloudNetworkData(networkData, false),
			)

			vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmi)
			Expect(err).ToNot(HaveOccurred())
			vmi = tests.WaitUntilVMIReady(vmi, console.LoginToAlpine)

			Expect(vmi.Status.Interfaces).To(HaveLen(1))
			Expect(vmi.Status.Interfaces[0].IPs).NotTo(BeEmpty())
			Expect(vmi.Status.Interfaces[0].IP).NotTo(BeEmpty())
		})

		Context("should allow regular network connection", func() {
			Context("should have client server connectivity", func() {
				var clientVMI *v1.VirtualMachineInstance
				var serverVMI *v1.VirtualMachineInstance

				startServerVMI := func(ports []v1.Port) {
					serverVMI = libvmi.NewAlpineWithTestTooling(
						libvmi.WithInterface(libvmi.InterfaceDeviceWithPasstBinding(ports...)),
						libvmi.WithNetwork(v1.DefaultPodNetwork()),
						withPasstExtendedResourceMemory(ports...),
						libvmi.WithCloudInitNoCloudNetworkData(networkData, false),
					)

					serverVMI, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(serverVMI)
					Expect(err).ToNot(HaveOccurred())
					serverVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(serverVMI)
					Expect(console.LoginToAlpine(serverVMI)).To(Succeed())
				}

				Context("TCP", func() {
					checkConnectionToServer := func(serverIP string, port int, expectSuccess bool) []expect.Batcher {
						expectResult := console.ShellFail
						if expectSuccess {
							expectResult = console.ShellSuccess
						}

						clientCommand := fmt.Sprintf("echo test | nc %s %d -i 1 -w 1 1> /dev/null\n", serverIP, port)

						return []expect.Batcher{
							&expect.BSnd{S: "\n"},
							&expect.BExp{R: console.PromptExpression},
							&expect.BSnd{S: clientCommand},
							&expect.BExp{R: console.PromptExpression},
							&expect.BSnd{S: tests.EchoLastReturnValue},
							&expect.BExp{R: expectResult},
						}
					}

					verifyClientServerConnectivity := func(clientVMI *v1.VirtualMachineInstance, serverVMI *v1.VirtualMachineInstance, tcpPort int, ipFamily k8sv1.IPFamily) error {
						serverIP := libnet.GetVmiPrimaryIPByFamily(serverVMI, ipFamily)
						err := libnet.PingFromVMConsole(clientVMI, serverIP)
						if err != nil {
							return err
						}

						By("Connecting from the client VM")
						err = console.SafeExpectBatch(clientVMI, checkConnectionToServer(serverIP, tcpPort, true), 30)
						if err != nil {
							return err
						}

						return nil
					}

					startClientVMI := func() {
						clientVMI = libvmi.NewAlpineWithTestTooling(
							withPasstInterfaceWithPort(),
							libvmi.WithNetwork(v1.DefaultPodNetwork()),
							libvmi.WithCloudInitNoCloudNetworkData(networkData, false),
						)

						clientVMI, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(clientVMI)
						Expect(err).ToNot(HaveOccurred())
						clientVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(clientVMI)
						Expect(console.LoginToAlpine(clientVMI)).To(Succeed())
					}
					DescribeTable("Client server connectivity", func(ports []v1.Port, tcpPort int, ipFamily k8sv1.IPFamily) {
						libnet.SkipWhenClusterNotSupportIPFamily(virtClient, ipFamily)

						By("starting a client VMI")
						startClientVMI()

						By("starting a server VMI")
						startServerVMI(ports)

						By("starting a TCP server")
						tests.StartTCPServer(serverVMI, tcpPort, console.LoginToAlpine)

						Expect(verifyClientServerConnectivity(clientVMI, serverVMI, tcpPort, ipFamily)).To(Succeed())

						if len(ports) != 0 {
							By("starting a TCP server on a port not specified on the VM spec")
							vmPort := int(ports[0].Port)
							serverIP := libnet.GetVmiPrimaryIPByFamily(serverVMI, ipFamily)

							tests.StartTCPServer(serverVMI, vmPort+1, console.LoginToAlpine)

							By("Connecting from the client VM to a port not specified on the VM spec")
							Expect(console.SafeExpectBatch(clientVMI, checkConnectionToServer(serverIP, tcpPort+1, true), 30)).To(Not(Succeed()))
						}
					},
						Entry("with a specific port number [IPv4]", []v1.Port{{Name: "http", Port: 8080, Protocol: "TCP"}}, 8080, k8sv1.IPv4Protocol),
						Entry("without a specific port number [IPv4]", []v1.Port{}, 8080, k8sv1.IPv4Protocol),
						Entry("with a specific port number [IPv6]", []v1.Port{{Name: "http", Port: 8080, Protocol: "TCP"}}, 8080, k8sv1.IPv6Protocol),
						Entry("without a specific port number [IPv6]", []v1.Port{}, 8080, k8sv1.IPv6Protocol),
					)
				})

				Context("UDP", func() {
					startAndVerifyUDPClient := func(vmi *v1.VirtualMachineInstance, serverIP string, serverPort int, ipFamily k8sv1.IPFamily) error {
						var inetSuffix string
						if ipFamily == k8sv1.IPv6Protocol {
							inetSuffix = "6"
						}

						createClientScript := fmt.Sprintf(`cat >udp_client.py <<EOL
import socket
try:
  client = socket.socket(socket.AF_INET%s, socket.SOCK_DGRAM);
  client.sendto("Hello Server".encode(), ("%s",%d));
  client.settimeout(5);
  response = client.recv(1024);
  print(response.decode("utf-8"));

except socket.timeout:
    client.close();
EOL`, inetSuffix, serverIP, serverPort)
						runClient := "python3 udp_client.py"
						return console.ExpectBatch(vmi, []expect.Batcher{
							&expect.BSnd{S: fmt.Sprintf("%s\n", createClientScript)},
							&expect.BExp{R: console.PromptExpression},
							&expect.BSnd{S: fmt.Sprintf("%s\n", runClient)},
							&expect.BExp{R: console.RetValue("Hello Client")},
							&expect.BSnd{S: tests.EchoLastReturnValue},
							&expect.BExp{R: console.ShellSuccess},
						}, 60*time.Second)
					}
					DescribeTable("Client server connectivity", func(ipFamily k8sv1.IPFamily) {
						libnet.SkipWhenClusterNotSupportIPFamily(virtClient, ipFamily)

						const SERVER_PORT = 1700

						By("Starting server VMI")
						startServerVMI([]v1.Port{{Port: SERVER_PORT, Protocol: "UDP"}})
						serverVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(serverVMI)
						Expect(console.LoginToAlpine(serverVMI)).To(Succeed())

						By("Starting a UDP server")
						tests.StartPythonUDPServer(serverVMI, SERVER_PORT, ipFamily)

						By("Starting client VMI")
						clientVMI = libvmi.NewAlpineWithTestTooling(
							libvmi.WithInterface(libvmi.InterfaceDeviceWithPasstBinding()),
							libvmi.WithNetwork(v1.DefaultPodNetwork()),
							withPasstExtendedResourceMemory(),
							libvmi.WithCloudInitNoCloudNetworkData(networkData, false),
						)
						clientVMI, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(clientVMI)
						Expect(err).ToNot(HaveOccurred())
						clientVMI = tests.WaitForSuccessfulVMIStartIgnoreWarnings(clientVMI)
						Expect(console.LoginToAlpine(clientVMI)).To(Succeed())
						console.LoginToAlpine(clientVMI)

						By("Starting and verifying UDP client")
						// Due to a passt bug, at least one UDPv6 message has to be sent from a machine before it can receive UDPv6 messages
						// Tracking bug - https://bugs.passt.top/show_bug.cgi?id=16
						if ipFamily == k8sv1.IPv6Protocol {
							clientIP := libnet.GetVmiPrimaryIPByFamily(clientVMI, ipFamily)
							Expect(libnet.PingFromVMConsole(serverVMI, clientIP)).To(Succeed())
						}
						serverIP := libnet.GetVmiPrimaryIPByFamily(serverVMI, ipFamily)
						Expect(startAndVerifyUDPClient(clientVMI, serverIP, SERVER_PORT, ipFamily)).To(Succeed())
					},
						Entry("[IPv4]", k8sv1.IPv4Protocol),
						Entry("[IPv6]", k8sv1.IPv6Protocol),
					)
				})
			})

			It("[outside_connectivity]should be able to reach the outside world [IPv4]", func() {
				libnet.SkipWhenClusterNotSupportIpv4(virtClient)
				ipv4Address := "8.8.8.8"
				if flags.IPV4ConnectivityCheckAddress != "" {
					ipv4Address = flags.IPV4ConnectivityCheckAddress
				}
				dns := "google.com"
				if flags.ConnectivityCheckDNS != "" {
					dns = flags.ConnectivityCheckDNS
				}

				vmi := libvmi.NewAlpineWithTestTooling(
					withPasstInterfaceWithPort(),
					libvmi.WithNetwork(v1.DefaultPodNetwork()),
					libvmi.WithCloudInitNoCloudNetworkData(networkData, false),
				)
				vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmi)
				Expect(err).ToNot(HaveOccurred())
				vmi = tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
				Expect(console.LoginToAlpine(vmi)).To(Succeed())

				By("Checking ping (IPv4)")
				Expect(libnet.PingFromVMConsole(vmi, ipv4Address, "-c 5", "-w 15")).To(Succeed())
				Expect(libnet.PingFromVMConsole(vmi, dns, "-c 5", "-w 15")).To(Succeed())
			})

			It("[outside_connectivity]should be able to reach the outside world [IPv6]", func() {
				libnet.SkipWhenClusterNotSupportIpv6(virtClient)
				// Cluster nodes subnet (docker network gateway)
				// Docker network subnet cidr definition:
				// https://github.com/kubevirt/project-infra/blob/master/github/ci/shared-deployments/files/docker-daemon-mirror.conf#L5
				ipv6Address := "2001:db8:1::1"
				if flags.IPV6ConnectivityCheckAddress != "" {
					ipv6Address = flags.IPV6ConnectivityCheckAddress
				}

				vmi := libvmi.NewAlpineWithTestTooling(
					withPasstInterfaceWithPort(),
					libvmi.WithNetwork(v1.DefaultPodNetwork()),
					libvmi.WithCloudInitNoCloudNetworkData(networkData, false),
				)
				Expect(err).ToNot(HaveOccurred())
				vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmi)
				Expect(err).ToNot(HaveOccurred())
				vmi = tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
				Expect(console.LoginToAlpine(vmi)).To(Succeed())

				By("Checking ping (IPv6) from VM to cluster nodes gateway")
				Expect(libnet.PingFromVMConsole(vmi, ipv6Address)).To(Succeed())
			})
		})
	})
})

func withPasstExtendedResourceMemory(ports ...v1.Port) libvmi.Option {
	if len(ports) == 0 {
		return libvmi.WithResourceMemory("2048M")
	}
	return func(vmi *v1.VirtualMachineInstance) {
	}
}

func withPasstInterfaceWithPort() libvmi.Option {
	return libvmi.WithInterface(libvmi.InterfaceDeviceWithPasstBinding([]v1.Port{{Port: 1234, Protocol: "TCP"}}...))
}
<|endoftext|>


<commit_before>package check

import (
	"math/rand"
	"time"

	kafka "github.com/Shopify/sarama"
	log "github.com/Sirupsen/logrus"
)

// sends one message to the broker partition, wait for it to appear on the consumer.
func (check *HealthCheck) checkBrokerHealth(metadata *kafka.MetadataResponse) BrokerStatus {
	status := unhealthy
	payload := randomBytes(check.config.MessageLength, check.randSrc)
	message := &kafka.Message{Value: []byte(payload)}

	request := &kafka.ProduceRequest{}
	request.AddMessage(check.config.topicName, check.partitionID, message)
	if _, err := check.broker.broker.Produce(request); err != nil {
		log.Println("producer failure - broker unhealthy:", err)
	} else {
		log.Debug("Waiting for message from broker")
		status = check.waitForMessage(check.config.topicName, check.partitionID, message)
		log.Debug("Got message from broker")
	}

	brokerStatus := BrokerStatus{Status: status}
	if status == healthy {
		request := &kafka.ProduceRequest{}
		request.AddMessage(check.config.replicationTopicName, check.replicationPartitionID, message)
		check.broker.broker.Produce(request)
		check.brokerInSync(&brokerStatus, metadata)
		check.brokerReplicates(&brokerStatus, metadata)
	}

	return brokerStatus
}

// waits for a message with the payload of the given message to appear on the consumer side.
func (check *HealthCheck) waitForMessage(topic string, partition int32, message *kafka.Message) string {
	deadline := time.Now().Add(check.config.CheckTimeout)
	partitionConsumer, err := check.consumer.ConsumePartition(topic, partition, kafka.OffsetOldest)
	if err == nil {
		defer func() {
			if err := partitionConsumer.Close(); err != nil {
				log.Fatalln(err)
			}
		}()
	}
	for time.Now().Before(deadline) {
		if err != nil {
			if err != kafka.ErrRequestTimedOut {
				log.Println("consumer failure - broker unhealthy:", err)
				return unhealthy
			}
			if time.Now().Before(deadline) {
				time.Sleep(check.config.DataWaitInterval)
			}
			continue
		}
		receivedMessage := <-partitionConsumer.Messages()
		if string(receivedMessage.Value) == string(message.Value) {
			return healthy
		}
	}
	return unhealthy
}

// checks whether the broker is in all ISRs of all partitions it replicates.
func (check *HealthCheck) brokerInSync(brokerStatus *BrokerStatus, metadata *kafka.MetadataResponse) {
	brokerID := int32(check.config.brokerID)

	inSync := true
	for _, topic := range metadata.Topics {
		for _, partition := range topic.Partitions {
			if contains(partition.Replicas, brokerID) && !contains(partition.Isr, brokerID) {
				inSync = false
				status := ReplicationStatus{Topic: topic.Name, Partition: partition.ID}
				brokerStatus.OutOfSync = append(brokerStatus.OutOfSync, status)
			}
		}
	}

	if inSync {
		brokerStatus.Status = insync
	}
}

var replicationFailureCount uint

func (check *HealthCheck) brokerReplicates(brokerStatus *BrokerStatus, metadata *kafka.MetadataResponse) {
	brokerID := int32(check.config.brokerID)

	topic, ok := findTopic(check.config.replicationTopicName, metadata)
	if !ok {
		return
	}

	for _, p := range topic.Partitions {
		if p.ID != check.replicationPartitionID {
			continue
		}

		if !contains(p.Isr, brokerID) {
			replicationFailureCount++
			if replicationFailureCount > check.config.replicationFailureThreshold {
				brokerStatus.Status = unhealthy
			}
		} else {
			replicationFailureCount = 0
		}

		brokerStatus.ReplicationFailures = replicationFailureCount
	}
}

// creates a random message payload.
//
// based on the solution http://stackoverflow.com/a/31832326
// provided by http://stackoverflow.com/users/1705598/icza
func randomBytes(n int, src rand.Source) []byte {
	b := make([]byte, n)
	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}

	return b
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)
<commit_msg>Fix replication topic message sending<commit_after>package check

import (
	"math/rand"
	"time"

	kafka "github.com/Shopify/sarama"
	log "github.com/Sirupsen/logrus"
)

// sends one message to the broker partition, wait for it to appear on the consumer.
func (check *HealthCheck) checkBrokerHealth(metadata *kafka.MetadataResponse) BrokerStatus {
	status := unhealthy
	payload := randomBytes(check.config.MessageLength, check.randSrc)
	message := &kafka.Message{Value: []byte(payload)}

	request := &kafka.ProduceRequest{}
	request.AddMessage(check.config.topicName, check.partitionID, message)
	if _, err := check.broker.broker.Produce(request); err != nil {
		log.Info("producer failure - broker unhealthy:", check.config.topicName, err)
	} else {
		log.Debug("Waiting for message from broker")
		status = check.waitForMessage(check.config.topicName, check.partitionID, message)
		log.Debug("Got message from broker")
	}

	brokerStatus := BrokerStatus{Status: status}
	if status == healthy {
		_, _, err := check.producer.SendMessage(&kafka.ProducerMessage{Topic: check.config.replicationTopicName, Value: kafka.ByteEncoder(payload)})
		if err != nil {
			log.Error("producer failure - failed to send message to replicationTopic: ", err)
		}
		check.brokerInSync(&brokerStatus, metadata)
		check.brokerReplicates(&brokerStatus, metadata)
	}

	return brokerStatus
}

// waits for a message with the payload of the given message to appear on the consumer side.
func (check *HealthCheck) waitForMessage(topic string, partition int32, message *kafka.Message) string {
	deadline := time.Now().Add(check.config.CheckTimeout)
	partitionConsumer, err := check.consumer.ConsumePartition(topic, partition, kafka.OffsetOldest)
	if err == nil {
		defer func() {
			if err := partitionConsumer.Close(); err != nil {
				log.Fatalln(err)
			}
		}()
	}
	for time.Now().Before(deadline) {
		if err != nil {
			if err != kafka.ErrRequestTimedOut {
				log.Println("consumer failure - broker unhealthy:", err)
				return unhealthy
			}
			if time.Now().Before(deadline) {
				time.Sleep(check.config.DataWaitInterval)
			}
			continue
		}
		receivedMessage := <-partitionConsumer.Messages()
		if string(receivedMessage.Value) == string(message.Value) {
			return healthy
		}
	}
	return unhealthy
}

// checks whether the broker is in all ISRs of all partitions it replicates.
func (check *HealthCheck) brokerInSync(brokerStatus *BrokerStatus, metadata *kafka.MetadataResponse) {
	brokerID := int32(check.config.brokerID)

	inSync := true
	for _, topic := range metadata.Topics {
		for _, partition := range topic.Partitions {
			if contains(partition.Replicas, brokerID) && !contains(partition.Isr, brokerID) {
				inSync = false
				status := ReplicationStatus{Topic: topic.Name, Partition: partition.ID}
				brokerStatus.OutOfSync = append(brokerStatus.OutOfSync, status)
			}
		}
	}

	if inSync {
		brokerStatus.Status = insync
	}
}

var replicationFailureCount uint

func (check *HealthCheck) brokerReplicates(brokerStatus *BrokerStatus, metadata *kafka.MetadataResponse) {
	brokerID := int32(check.config.brokerID)

	topic, ok := findTopic(check.config.replicationTopicName, metadata)
	if !ok {
		return
	}

	for _, p := range topic.Partitions {
		if p.ID != check.replicationPartitionID {
			continue
		}

		if !contains(p.Isr, brokerID) {
			replicationFailureCount++
			if replicationFailureCount > check.config.replicationFailureThreshold {
				brokerStatus.Status = unhealthy
			}
		} else {
			replicationFailureCount = 0
		}

		brokerStatus.ReplicationFailures = replicationFailureCount
	}
}

// creates a random message payload.
//
// based on the solution http://stackoverflow.com/a/31832326
// provided by http://stackoverflow.com/users/1705598/icza
func randomBytes(n int, src rand.Source) []byte {
	b := make([]byte, n)
	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), letterIdxMax
		}
		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i--
		}
		cache >>= letterIdxBits
		remain--
	}

	return b
}

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
const (
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)
<|endoftext|>


<commit_before>package flyrpc

import (
	"log"
	"time"
)

type Context struct {
	Protocol Protocol
	Debug    bool
	Tag      string
	ClientId int
	Session  interface{}
	Packet   *Packet
	Router   Router
	// private
	serializer Serializer
	nextSeq    TSeq
	replyChans map[TSeq]chan *Packet
	timeout    time.Duration
	// close handler
	closeHandler func(*Context)
}

func NewContext(protocol Protocol, router Router, clientId int, serializer Serializer) *Context {
	return &Context{
		Protocol:   protocol,
		Router:     router,
		ClientId:   clientId,
		serializer: serializer,
		replyChans: make(map[TSeq]chan *Packet),
		timeout:    10 * time.Second,
	}
}

func (ctx *Context) debug(args ...interface{}) {
	if ctx.Debug {
		if ctx.Tag != "" {
			args = append([]interface{}{"[" + ctx.Tag + "]"}, args...)
		}
		log.Println(args...)
	}
}

func (ctx *Context) sendPacket(flag byte, code string, seq TSeq, payload []byte) error {
	return ctx.Protocol.SendPacket(&Packet{
		ClientId: ctx.ClientId,
		Flag:     flag,
		Code:     code,
		Seq:      seq,
		Payload:  payload,
	})
}

func (ctx *Context) sendError(code string, seq TSeq, err error) error {
	payload := []byte{}
	return ctx.sendPacket(
		FlagResponse,
		err.Error(),
		seq,
		payload,
	)
}

func (ctx *Context) SendMessage(code string, message Message) error {
	payload, err := MessageToBytes(message, ctx.serializer)
	if err != nil {
		return err
	}
	return ctx.sendPacket(FlagWaitResponse, code, ctx.getNextSeq(), payload)
}

func (ctx *Context) GetReply(code string, message Message) ([]byte, error) {
	ctx.debug("Call", code, message)

	payload, err := MessageToBytes(message, ctx.serializer)
	if err != nil {
		return nil, err
	}
	packet := &Packet{
		Flag:    FlagWaitResponse,
		Code:    code,
		Seq:     ctx.getNextSeq(),
		Payload: payload,
	}

	// Send Packet
	if err := ctx.Protocol.SendPacket(packet); err != nil {
		return nil, err
	}

	// init channel before send packet
	replyChan := make(chan *Packet, 1)
	// set replyChan for code | seq
	ctx.replyChans[packet.Seq] = replyChan

	// make sure that replyChan is released
	defer delete(ctx.replyChans, packet.Seq)
	select {
	case rPacket := <-replyChan:
		ctx.debug("reply payload", rPacket.Payload)
		if rPacket.Code != "" {
			ctx.debug("reply error", string(rPacket.Code))
			return nil, newReplyError(string(rPacket.Code), rPacket)
		}
		return rPacket.Payload, nil

	case <-time.After(ctx.timeout):
		return nil, newError(ErrTimeOut)
	}
}

func (ctx *Context) Call(code string, message Message, reply Message) error {
	bytes, err := ctx.GetReply(code, message)
	if err != nil {
		return err
	}
	if reply != nil {
		return ctx.serializer.Unmarshal(bytes, reply)
	}
	return nil
}

func (ctx *Context) GetAsync(code string, message Message) (chan<- []byte, chan<- error) {
	buffChan := make(chan []byte, 1)
	errChan := make(chan error, 1)
	go func() {
		bytes, err := ctx.GetReply(code, message)
		buffChan <- bytes
		errChan <- err
	}()
	return buffChan, errChan
}

func (ctx *Context) emitPacket(pkt *Packet) {
	if pkt.Flag&FlagResponse != 0 {
		replyChan := ctx.replyChans[pkt.Seq]
		if replyChan == nil {
			ctx.debug("No channel found, pkt is :", pkt)
			return
		}
		replyChan <- pkt
		return
	}
	ctx.Packet = pkt
	ctx.debug("OnMessage", pkt.Code, pkt.Flag, pkt.Payload)
	if err := ctx.Router.emitPacket(ctx, pkt); err != nil {
		ctx.debug("Error to call packet", err)
	}
}

func (ctx *Context) getNextSeq() TSeq {
	ctx.nextSeq++
	return ctx.nextSeq
}

func (ctx *Context) OnClose(handler func(*Context)) {
	ctx.closeHandler = handler
}

func (ctx *Context) Close() {
	ctx.debug("closing")
	if ctx.closeHandler != nil {
		ctx.closeHandler(ctx)
	}
}
<commit_msg>fix close<commit_after>package flyrpc

import (
	"log"
	"time"
)

type Context struct {
	Protocol Protocol
	Debug    bool
	Tag      string
	ClientId int
	Session  interface{}
	Packet   *Packet
	Router   Router
	// private
	serializer Serializer
	nextSeq    TSeq
	replyChans map[TSeq]chan *Packet
	timeout    time.Duration
	// close handler
	closeHandler func(*Context)
}

func NewContext(protocol Protocol, router Router, clientId int, serializer Serializer) *Context {
	return &Context{
		Protocol:   protocol,
		Router:     router,
		ClientId:   clientId,
		serializer: serializer,
		replyChans: make(map[TSeq]chan *Packet),
		timeout:    10 * time.Second,
	}
}

func (ctx *Context) debug(args ...interface{}) {
	if ctx.Debug {
		if ctx.Tag != "" {
			args = append([]interface{}{"[" + ctx.Tag + "]"}, args...)
		}
		log.Println(args...)
	}
}

func (ctx *Context) sendPacket(flag byte, code string, seq TSeq, payload []byte) error {
	return ctx.Protocol.SendPacket(&Packet{
		ClientId: ctx.ClientId,
		Flag:     flag,
		Code:     code,
		Seq:      seq,
		Payload:  payload,
	})
}

func (ctx *Context) sendError(code string, seq TSeq, err error) error {
	payload := []byte{}
	return ctx.sendPacket(
		FlagResponse,
		err.Error(),
		seq,
		payload,
	)
}

func (ctx *Context) SendMessage(code string, message Message) error {
	payload, err := MessageToBytes(message, ctx.serializer)
	if err != nil {
		return err
	}
	return ctx.sendPacket(FlagWaitResponse, code, ctx.getNextSeq(), payload)
}

func (ctx *Context) GetReply(code string, message Message) ([]byte, error) {
	ctx.debug("Call", code, message)

	payload, err := MessageToBytes(message, ctx.serializer)
	if err != nil {
		return nil, err
	}
	packet := &Packet{
		Flag:    FlagWaitResponse,
		Code:    code,
		Seq:     ctx.getNextSeq(),
		Payload: payload,
	}

	// Send Packet
	if err := ctx.Protocol.SendPacket(packet); err != nil {
		return nil, err
	}

	// init channel before send packet
	replyChan := make(chan *Packet, 1)
	// set replyChan for code | seq
	ctx.replyChans[packet.Seq] = replyChan

	// make sure that replyChan is released
	defer delete(ctx.replyChans, packet.Seq)
	select {
	case rPacket := <-replyChan:
		ctx.debug("reply payload", rPacket.Payload)
		if rPacket.Code != "" {
			ctx.debug("reply error", string(rPacket.Code))
			return nil, newReplyError(string(rPacket.Code), rPacket)
		}
		return rPacket.Payload, nil

	case <-time.After(ctx.timeout):
		return nil, newError(ErrTimeOut)
	}
}

func (ctx *Context) Call(code string, message Message, reply Message) error {
	bytes, err := ctx.GetReply(code, message)
	if err != nil {
		return err
	}
	if reply != nil {
		return ctx.serializer.Unmarshal(bytes, reply)
	}
	return nil
}

func (ctx *Context) GetAsync(code string, message Message) (chan<- []byte, chan<- error) {
	buffChan := make(chan []byte, 1)
	errChan := make(chan error, 1)
	go func() {
		bytes, err := ctx.GetReply(code, message)
		buffChan <- bytes
		errChan <- err
	}()
	return buffChan, errChan
}

func (ctx *Context) emitPacket(pkt *Packet) {
	if pkt.Flag&FlagResponse != 0 {
		replyChan := ctx.replyChans[pkt.Seq]
		if replyChan == nil {
			ctx.debug("No channel found, pkt is :", pkt)
			return
		}
		replyChan <- pkt
		return
	}
	ctx.Packet = pkt
	ctx.debug("OnMessage", pkt.Code, pkt.Flag, pkt.Payload)
	if err := ctx.Router.emitPacket(ctx, pkt); err != nil {
		ctx.debug("Error to call packet", err)
	}
}

func (ctx *Context) getNextSeq() TSeq {
	ctx.nextSeq++
	return ctx.nextSeq
}

func (ctx *Context) OnClose(handler func(*Context)) {
	ctx.closeHandler = handler
}

func (ctx *Context) Close() {
	ctx.debug("closing")
	ctx.Protocol.Close()
	if ctx.closeHandler != nil {
		ctx.closeHandler(ctx)
	}
}
<|endoftext|>


<commit_before>package endly

import (
	"fmt"
	"github.com/pkg/errors"
	"github.com/viant/endly/common"
	"github.com/viant/toolbox"
	"math/rand"
	"net/url"
	"os"
	"os/exec"
	uuid "github.com/satori/go.uuid"
	"path"
	"strings"
	"time"
)

//TODO Execution detail Tracking of all run (time taken, request, response)

var converter = toolbox.NewColumnConverter("yyyy-MM-dd HH:ss")

var serviceManagerKey = (*manager)(nil)
var deferFunctionsKey = (*[]func())(nil)
var stateKey = (*common.Map)(nil)
var sessionInfoKey = (*SessionInfo)(nil)
var workflowKey = (*Workflow)(nil)

type Context struct {
	toolbox.Context
}

func reportError(err error) error {
	fileName, funcName, line := toolbox.CallerInfo(4)
	return fmt.Errorf("%v at %v:%v -> %v", err, fileName, line, funcName)
}

func (c *Context) ExpandResource(resource *Resource) (*Resource, error) {
	var err error
	if resource == nil {
		return nil, reportError(fmt.Errorf("Resource was empty"))
	}
	if resource.URL == "" {
		return nil, reportError(fmt.Errorf("URL was empty"))
	}

	if !strings.Contains(resource.URL, "://") {
		if workflow := c.Workflow(); workflow != nil && workflow.source != nil {
			baseURL, _ := toolbox.URLSplit(workflow.source.URL)
			resource.URL = toolbox.URLPathJoin(baseURL, resource.URL)
		}
	}

	var result = &Resource{
		URL:         c.Expand(resource.URL),
		Credential:  c.Expand(resource.Credential),
		Name:        c.Expand(resource.Name),
		Version:     resource.Version,
		Type:        c.Expand(resource.Type),
		Cache:       c.Expand(resource.Cache),
		CacheExpiry: resource.CacheExpiry,
	}
	result.ParsedURL, err = url.Parse(result.URL)
	if err != nil {
		return nil, reportError(fmt.Errorf("Failed to parse URL: %v %v", result.URL, err))
	}
	return result, nil
}

func (c *Context) Manager() (Manager, error) {
	var manager = &manager{}
	if !c.GetInto(serviceManagerKey, &manager) {
		return nil, reportError(fmt.Errorf("Failed to lookup Manager"))
	}
	return manager, nil
}

func (c *Context) Sessions() ClientSessions {
	var result *ClientSessions
	if !c.Contains(clientSessionKey) {
		var sessions ClientSessions = make(map[string]*ClientSession)
		result = &sessions
		c.Put(clientSessionKey, result)
	} else {
		c.GetInto(clientSessionKey, &result)
	}
	return *result
}

func (c *Context) Service(name string) (Service, error) {
	manager, err := c.Manager()
	if err != nil {
		return nil, err
	}
	return manager.Service(name)
}

func (c *Context) Deffer(functions ...func()) []func() {
	var result *[]func()
	if !c.Contains(deferFunctionsKey) {
		var functions = make([]func(), 0)
		result = &functions
		c.Put(deferFunctionsKey, result)
	} else {
		c.GetInto(deferFunctionsKey, &result)
	}

	*result = append(*result, functions...)
	c.Put(deferFunctionsKey, &result)
	return *result
}

func (c *Context) State() common.Map {
	var result *common.Map
	if !c.Contains(stateKey) {
		aMap := NewDefaultState()
		result = &aMap
		c.Put(stateKey, result)
	} else {
		c.GetInto(stateKey, &result)
	}
	return *result
}

func (c *Context) SessionInfo() *SessionInfo {
	var result *SessionInfo
	if !c.Contains(sessionInfoKey) {

		result = &SessionInfo{}
		c.Put(sessionInfoKey, result)
	} else {
		c.GetInto(sessionInfoKey, &result)
	}
	return result
}

func (c *Context) Workflow() *Workflow {
	var result *Workflow
	if !c.Contains(workflowKey) {
		return nil
	} else {
		c.GetInto(workflowKey, &result)
	}
	return result
}

func (c *Context) OperatingSystem(sessionName string) *OperatingSystem {
	var sessions = c.Sessions()
	if session, has := sessions[sessionName]; has {
		return session.OperatingSystem
	}
	return nil
}

func (c *Context) ExecuteAsSuperUser(target *Resource, command *ManagedCommand) (*CommandInfo, error) {
	superUserRequest := SuperUserCommandRequest{
		Target:        target,
		MangedCommand: command,
	}
	request, err := superUserRequest.AsCommandRequest(c)
	if err != nil {
		return nil, err
	}
	return c.Execute(target, request.ManagedCommand)
}

func (c *Context) Execute(target *Resource, command interface{}) (*CommandInfo, error) {
	if command == nil {
		return nil, nil
	}
	var commandRequest *ManagedCommandRequest
	switch actualCommand := command.(type) {
	case *CommandRequest:
		actualCommand.Target = target
		commandRequest = actualCommand.AsManagedCommandRequest()
	case *ManagedCommand:
		commandRequest = NewCommandRequest(target, actualCommand)
	case string:
		request := CommandRequest{
			Target:   target,
			Commands: []string{actualCommand},
		}
		commandRequest = request.AsManagedCommandRequest()
	case []string:
		request := CommandRequest{
			Target:   target,
			Commands: actualCommand,
		}
		commandRequest = request.AsManagedCommandRequest()

	default:
		return nil, fmt.Errorf("Unsupported command: %T", command)
	}
	execService, err := c.Service(ExecServiceId)
	if err != nil {
		return nil, err
	}
	response := execService.Run(c, commandRequest)
	if response.Error != "" {
		return nil, errors.New(response.Error)
	}
	if commandResult, ok := response.Response.(*CommandInfo); ok {
		return commandResult, nil
	}
	return nil, nil
}

func (c *Context) Copy(expand bool, source, target *Resource) (interface{}, error) {
	return c.Transfer([]*Transfer{{
		Source: source,
		Target: target,
		Expand: expand}}...)
}

func (c *Context) Transfer(transfers ...*Transfer) (interface{}, error) {
	if transfers == nil {
		return nil, nil
	}
	transferService, err := c.Service(TransferServiceId)
	if err != nil {
		return nil, err
	}
	response := transferService.Run(c, &TransferCopyRequest{Transfers: transfers})
	if response.Error != "" {
		return nil, errors.New(response.Error)
	}
	return nil, nil
}

func (c *Context) Log(logEntry interface{}) error {
	sessionInfo := c.SessionInfo()
	return sessionInfo.Log(logEntry)
}

func (c *Context) Expand(text string) string {
	state := c.State()
	return ExpandAsText(state, text)
}

func (c *Context) AsRequest(serviceName, requestName string, source map[string]interface{}) (interface{}, error) {
	service, err := c.Service(serviceName)
	if err != nil {
		return nil, err
	}
	request, err := service.NewRequest(requestName)
	if err != nil {
		return nil, err
	}
	err = converter.AssignConverted(request, source)
	return request, err
}

func (c *Context) Close() {
	for _, function := range c.Deffer() {
		function()
	}
}

func NewDefaultState() common.Map {
	var result = common.NewMap()
	var now = time.Now()
	source := rand.NewSource(now.UnixNano())
	result.Put("endlyURL", "http://github.com/viant/endly")
	result.Put("rand", source.Int63())
	result.Put("date", now.Format(toolbox.DateFormatToLayout("yyyy-MM-dd")))
	result.Put("time", now.Format(toolbox.DateFormatToLayout("yyyy-MM-dd hh:mm:ss")))
	result.Put("ts", now.Format(toolbox.DateFormatToLayout("yyyyMMddhhmmSSS")))

	result.Put("tmpDir", func(key string) interface{} {
		tempPath := path.Join(os.TempDir(), key)
		exec.Command("mkdir -p " + tempPath)
		return tempPath
	})

	var cachedUUID uuid.UUID
	result.Put("uuid", func(key string) interface{} {
		if key == "next" {
			cachedUUID = uuid.NewV1()
		}
		if len(cachedUUID) > 0 {
			return cachedUUID.String()
		}
		return ""
	})
	result.Put("env", func(key string) interface{} {
		return os.Getenv(key)
	})
	return result
}
<commit_msg>patched state in context<commit_after>package endly

import (
	"fmt"
	"github.com/pkg/errors"
	"github.com/viant/endly/common"
	"github.com/viant/toolbox"
	"math/rand"
	"net/url"
	"os"
	"os/exec"
	uuid "github.com/satori/go.uuid"
	"path"
	"strings"
	"time"
)

//TODO Execution detail Tracking of all run (time taken, request, response)

var converter = toolbox.NewColumnConverter("yyyy-MM-dd HH:ss")

type StateKey *common.Map

var serviceManagerKey = (*manager)(nil)
var deferFunctionsKey = (*[]func())(nil)
var sessionInfoKey = (*SessionInfo)(nil)
var workflowKey = (*Workflow)(nil)

type Context struct {
	state common.Map
	toolbox.Context
}

func reportError(err error) error {
	fileName, funcName, line := toolbox.CallerInfo(4)
	return fmt.Errorf("%v at %v:%v -> %v", err, fileName, line, funcName)
}

func (c *Context) ExpandResource(resource *Resource) (*Resource, error) {
	var err error
	if resource == nil {
		return nil, reportError(fmt.Errorf("Resource was empty"))
	}
	if resource.URL == "" {
		return nil, reportError(fmt.Errorf("URL was empty"))
	}

	if !strings.Contains(resource.URL, "://") {
		if workflow := c.Workflow(); workflow != nil && workflow.source != nil {
			baseURL, _ := toolbox.URLSplit(workflow.source.URL)
			resource.URL = toolbox.URLPathJoin(baseURL, resource.URL)
		}
	}

	var result = &Resource{
		URL:         c.Expand(resource.URL),
		Credential:  c.Expand(resource.Credential),
		Name:        c.Expand(resource.Name),
		Version:     resource.Version,
		Type:        c.Expand(resource.Type),
		Cache:       c.Expand(resource.Cache),
		CacheExpiry: resource.CacheExpiry,
	}
	result.ParsedURL, err = url.Parse(result.URL)
	if err != nil {
		return nil, reportError(fmt.Errorf("Failed to parse URL: %v %v", result.URL, err))
	}
	return result, nil
}

func (c *Context) Manager() (Manager, error) {
	var manager = &manager{}
	if !c.GetInto(serviceManagerKey, &manager) {
		return nil, reportError(fmt.Errorf("Failed to lookup Manager"))
	}
	return manager, nil
}

func (c *Context) Sessions() ClientSessions {
	var result *ClientSessions
	if !c.Contains(clientSessionKey) {
		var sessions ClientSessions = make(map[string]*ClientSession)
		result = &sessions
		c.Put(clientSessionKey, result)
	} else {
		c.GetInto(clientSessionKey, &result)
	}
	return *result
}

func (c *Context) Service(name string) (Service, error) {
	manager, err := c.Manager()
	if err != nil {
		return nil, err
	}
	return manager.Service(name)
}

func (c *Context) Deffer(functions ...func()) []func() {
	var result *[]func()
	if !c.Contains(deferFunctionsKey) {
		var functions = make([]func(), 0)
		result = &functions
		c.Put(deferFunctionsKey, result)
	} else {
		c.GetInto(deferFunctionsKey, &result)
	}

	*result = append(*result, functions...)
	c.Put(deferFunctionsKey, &result)
	return *result
}

func (c *Context) State() common.Map {
	if c.state == nil {
		c.state = NewDefaultState()
	}
	return c.state
}

func (c *Context) SetState(state common.Map) {
	c.state = state
}

func (c *Context) SessionInfo() *SessionInfo {
	var result *SessionInfo
	if !c.Contains(sessionInfoKey) {

		result = &SessionInfo{}
		c.Put(sessionInfoKey, result)
	} else {
		c.GetInto(sessionInfoKey, &result)
	}
	return result
}

func (c *Context) Workflow() *Workflow {
	var result *Workflow
	if !c.Contains(workflowKey) {
		return nil
	} else {
		c.GetInto(workflowKey, &result)
	}
	return result
}

func (c *Context) OperatingSystem(sessionName string) *OperatingSystem {
	var sessions = c.Sessions()
	if session, has := sessions[sessionName]; has {
		return session.OperatingSystem
	}
	return nil
}

func (c *Context) ExecuteAsSuperUser(target *Resource, command *ManagedCommand) (*CommandInfo, error) {
	superUserRequest := SuperUserCommandRequest{
		Target:        target,
		MangedCommand: command,
	}
	request, err := superUserRequest.AsCommandRequest(c)
	if err != nil {
		return nil, err
	}
	return c.Execute(target, request.ManagedCommand)
}

func (c *Context) Execute(target *Resource, command interface{}) (*CommandInfo, error) {
	if command == nil {
		return nil, nil
	}
	var commandRequest *ManagedCommandRequest
	switch actualCommand := command.(type) {
	case *CommandRequest:
		actualCommand.Target = target
		commandRequest = actualCommand.AsManagedCommandRequest()
	case *ManagedCommand:
		commandRequest = NewCommandRequest(target, actualCommand)
	case string:
		request := CommandRequest{
			Target:   target,
			Commands: []string{actualCommand},
		}
		commandRequest = request.AsManagedCommandRequest()
	case []string:
		request := CommandRequest{
			Target:   target,
			Commands: actualCommand,
		}
		commandRequest = request.AsManagedCommandRequest()

	default:
		return nil, fmt.Errorf("Unsupported command: %T", command)
	}
	execService, err := c.Service(ExecServiceId)
	if err != nil {
		return nil, err
	}
	response := execService.Run(c, commandRequest)
	if response.Error != "" {
		return nil, errors.New(response.Error)
	}
	if commandResult, ok := response.Response.(*CommandInfo); ok {
		return commandResult, nil
	}
	return nil, nil
}

func (c *Context) Copy(expand bool, source, target *Resource) (interface{}, error) {
	return c.Transfer([]*Transfer{{
		Source: source,
		Target: target,
		Expand: expand}}...)
}

func (c *Context) Transfer(transfers ...*Transfer) (interface{}, error) {
	if transfers == nil {
		return nil, nil
	}
	transferService, err := c.Service(TransferServiceId)
	if err != nil {
		return nil, err
	}
	response := transferService.Run(c, &TransferCopyRequest{Transfers: transfers})
	if response.Error != "" {
		return nil, errors.New(response.Error)
	}
	return nil, nil
}

func (c *Context) Log(logEntry interface{}) error {
	sessionInfo := c.SessionInfo()
	return sessionInfo.Log(logEntry)
}

func (c *Context) Expand(text string) string {
	state := c.State()
	return ExpandAsText(state, text)
}

func (c *Context) AsRequest(serviceName, requestName string, source map[string]interface{}) (interface{}, error) {
	service, err := c.Service(serviceName)
	if err != nil {
		return nil, err
	}
	request, err := service.NewRequest(requestName)
	if err != nil {
		return nil, err
	}
	err = converter.AssignConverted(request, source)
	return request, err
}

func (c *Context) Close() {
	for _, function := range c.Deffer() {
		function()
	}
}

func NewDefaultState() common.Map {
	var result = common.NewMap()
	var now = time.Now()
	source := rand.NewSource(now.UnixNano())
	result.Put("endlyURL", "http://github.com/viant/endly")
	result.Put("rand", source.Int63())
	result.Put("date", now.Format(toolbox.DateFormatToLayout("yyyy-MM-dd")))
	result.Put("time", now.Format(toolbox.DateFormatToLayout("yyyy-MM-dd hh:mm:ss")))
	result.Put("ts", now.Format(toolbox.DateFormatToLayout("yyyyMMddhhmmSSS")))

	result.Put("tmpDir", func(key string) interface{} {
		tempPath := path.Join(os.TempDir(), key)
		exec.Command("mkdir -p " + tempPath)
		return tempPath
	})

	var cachedUUID uuid.UUID
	result.Put("uuid", func(key string) interface{} {
		if key == "next" {
			cachedUUID = uuid.NewV1()
		}
		if len(cachedUUID) > 0 {
			return cachedUUID.String()
		}
		return ""
	})
	result.Put("env", func(key string) interface{} {
		return os.Getenv(key)
	})
	return result
}
<|endoftext|>


<commit_before>package picoweb

import "net/http"
import "io/ioutil"
import "html/template"
import "fmt"
import "encoding/json"
import "github.com/googollee/go-socket.io"
import "time"
import "strconv"
import "github.com/pkg/errors"

type Context struct {
	w         http.ResponseWriter
	r         *http.Request
	params    map[string]string
	SessionId string
}

func (c *Context) Body() ([]byte, error) {
	bts, err := ioutil.ReadAll(c.r.Body)
	return bts, err
}

func (c *Context) Bytes() []byte {
	bts, _ := ioutil.ReadAll(c.r.Body)
	return bts
}

func (c *Context) Query(key string) string {
	return c.r.URL.Query().Get(key)
}

func (c *Context) QueryInt(key string) (int, error) {
	v := c.Query(key)
	if len(v) == 0 {
		return 0, errors.New("key not found in path")
	}
	i, err := strconv.Atoi(key)
	if err != nil {
		return 0, errors.New("Could not parse as Int")
	}
	return i, nil
}
func (c *Context) QueryBool(key string) (bool, error) {
	v := c.Query(key)
	if len(v) == 0 {
		return false, errors.New("key not found in path")
	}
	b, err := strconv.ParseBool(key)
	if err != nil {
		return false, errors.New("Could not parse as Bool")
	}
	return b, nil
}

func (c *Context) Form(key string) string {
	return c.r.FormValue(key)
}

func (c *Context) Method() string {
	return c.r.Method
}

func (c *Context) Header(key string) string {
	return c.r.Header.Get(key)
}

func (c *Context) RemoteIP() string {
	return c.r.RemoteAddr
}

func (c *Context) R() *http.Request {
	return c.r
}

func (c *Context) SetHeader(key string, value string) {
	c.w.Header().Set(key, value)
}

func (c *Context) File(filePath string, mimeType string) {
	c.w.Header().Set("content-type", mimeType)
	http.ServeFile(c.w, c.r, filePath)
}

func (c *Context) FileHTML(filePath string) {
	c.w.Header().Set("content-type", "text/html; charset=utf-8")
	http.ServeFile(c.w, c.r, filePath)
}

func (c *Context) String(str string) {
	fmt.Fprint(c, str)
}

func (c *Context) Status(statusCode int) {
	c.w.WriteHeader(statusCode)
}

func (c *Context) Json(data interface{}) {
	jsoned, _ := json.Marshal(data)
	c.ResponseHeader().Add("content-type", "application/json")
	fmt.Fprint(c, string(jsoned))
}

func (c *Context) View(filePath string, data interface{}) {
	tmpl, err := template.ParseFiles(filePath)
	if err != nil {
		fmt.Fprint(c, err.Error())
		return
	}
	err = tmpl.Execute(c.w, data)
}

func (c *Context) Params(name string) string {
	v, _ := c.params[name]
	return v
}

func (c *Context) ResponseHeader() http.Header {
	return c.w.Header()
}

func (c *Context) WriteHeader(n int) {
	c.w.WriteHeader(n)
}

func (c *Context) Write(b []byte) (int, error) {
	return c.w.Write(b)
}

func (c *Context) SetCookie(name, value string, expireIn time.Duration) {
	cookie := &http.Cookie{
		Name:     name,
		Value:    value,
		MaxAge:   0,
		HttpOnly: true,
		Secure:   false,
		Expires:  time.Now().Add(expireIn),
		Path:     "/",
		Raw:      value,
		Unparsed: []string{value},
	}
	http.SetCookie(c.w, cookie)
}

func (c *Context) GetCookie(name string) string {
	cookie, err := c.r.Cookie(name)
	if err != nil {
		return ""
	}
	val := cookie.Value
	if len(val) == 0 {
		for _, ck := range c.r.Cookies() {
			if ck.Name == name {
				return ck.Value
			}
		}
	}
	return ""
}

func (c *Context) RemoveCookie(name string) {
	c.SetCookie(name, "", -(time.Hour * 36))
}

type Socket struct {
	socketio.Socket
}
<commit_msg>QueryAsInt fix<commit_after>package picoweb

import "net/http"
import "io/ioutil"
import "html/template"
import "fmt"
import "encoding/json"
import "github.com/googollee/go-socket.io"
import "time"
import "strconv"
import "github.com/pkg/errors"

type Context struct {
	w         http.ResponseWriter
	r         *http.Request
	params    map[string]string
	SessionId string
}

func (c *Context) Body() ([]byte, error) {
	bts, err := ioutil.ReadAll(c.r.Body)
	return bts, err
}

func (c *Context) Bytes() []byte {
	bts, _ := ioutil.ReadAll(c.r.Body)
	return bts
}

func (c *Context) Query(key string) string {
	return c.r.URL.Query().Get(key)
}

func (c *Context) QueryInt(key string) (int, error) {
	v := c.Query(key)
	if len(v) == 0 {
		return 0, errors.New("key not found in path")
	}
	i, err := strconv.Atoi(v)
	if err != nil {
		return 0, errors.New("Could not parse as Int")
	}
	return i, nil
}
func (c *Context) QueryBool(key string) (bool, error) {
	v := c.Query(key)
	if len(v) == 0 {
		return false, errors.New("key not found in path")
	}
	b, err := strconv.ParseBool(key)
	if err != nil {
		return false, errors.New("Could not parse as Bool")
	}
	return b, nil
}

func (c *Context) Form(key string) string {
	return c.r.FormValue(key)
}

func (c *Context) Method() string {
	return c.r.Method
}

func (c *Context) Header(key string) string {
	return c.r.Header.Get(key)
}

func (c *Context) RemoteIP() string {
	return c.r.RemoteAddr
}

func (c *Context) R() *http.Request {
	return c.r
}

func (c *Context) SetHeader(key string, value string) {
	c.w.Header().Set(key, value)
}

func (c *Context) File(filePath string, mimeType string) {
	c.w.Header().Set("content-type", mimeType)
	http.ServeFile(c.w, c.r, filePath)
}

func (c *Context) FileHTML(filePath string) {
	c.w.Header().Set("content-type", "text/html; charset=utf-8")
	http.ServeFile(c.w, c.r, filePath)
}

func (c *Context) String(str string) {
	fmt.Fprint(c, str)
}

func (c *Context) Status(statusCode int) {
	c.w.WriteHeader(statusCode)
}

func (c *Context) Json(data interface{}) {
	jsoned, _ := json.Marshal(data)
	c.ResponseHeader().Add("content-type", "application/json")
	fmt.Fprint(c, string(jsoned))
}

func (c *Context) View(filePath string, data interface{}) {
	tmpl, err := template.ParseFiles(filePath)
	if err != nil {
		fmt.Fprint(c, err.Error())
		return
	}
	err = tmpl.Execute(c.w, data)
}

func (c *Context) Params(name string) string {
	v, _ := c.params[name]
	return v
}

func (c *Context) ResponseHeader() http.Header {
	return c.w.Header()
}

func (c *Context) WriteHeader(n int) {
	c.w.WriteHeader(n)
}

func (c *Context) Write(b []byte) (int, error) {
	return c.w.Write(b)
}

func (c *Context) SetCookie(name, value string, expireIn time.Duration) {
	cookie := &http.Cookie{
		Name:     name,
		Value:    value,
		MaxAge:   0,
		HttpOnly: true,
		Secure:   false,
		Expires:  time.Now().Add(expireIn),
		Path:     "/",
		Raw:      value,
		Unparsed: []string{value},
	}
	http.SetCookie(c.w, cookie)
}

func (c *Context) GetCookie(name string) string {
	cookie, err := c.r.Cookie(name)
	if err != nil {
		return ""
	}
	val := cookie.Value
	if len(val) == 0 {
		for _, ck := range c.r.Cookies() {
			if ck.Name == name {
				return ck.Value
			}
		}
	}
	return ""
}

func (c *Context) RemoveCookie(name string) {
	c.SetCookie(name, "", -(time.Hour * 36))
}

type Socket struct {
	socketio.Socket
}
<|endoftext|>


<commit_before>package rest

import (
	"encoding/json"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strconv"
)

func NewContext() IContext {
	c := new(Context)
	c.params = &urlValues{&url.Values{}}

	// Default "decode"
	c.SetDecodeFunc(func(out interface{}) error {
		if c.reqBody == nil {
			defer c.req.Body.Close()
			v, err := ioutil.ReadAll(c.req.Body)
			c.reqBody = v
			if err != nil {
				return err
			}
		}

		return json.Unmarshal(c.reqBody, out)
	})

	return c
}

type urlValues struct {
	*url.Values
}

func (self *urlValues) Int(key string) int {
	i, _ := strconv.Atoi(self.Get(key))
	return i
}

func (self *urlValues) Bool(key string) bool {
	v := self.Get(key)
	return v == "true" || v == "1"
}

type Request struct {
	*http.Request
}

func (self *Request) Ip() string {
	ip, _, _ := net.SplitHostPort(self.RemoteAddr)
	return ip
}

type Context struct {
	req                   *Request
	reqBody               []byte
	params                *urlValues
	user                  IUser
	runParseMultipartForm bool
	store                 *store
	handler               *Handler
	AutoSetUser           func()
	decode                func(out interface{}) error
}

func (self *Context) User() IUser {
	if self.user == nil {
		self.AutoSetUser()
	}

	return self.user
}

func (self *Context) SetAutoSetUserFunc(fn func()) {
	self.AutoSetUser = fn
}

func (self *Context) Handler() *Handler {
	return self.handler
}

func (self *Context) SetHandler(handler *Handler) {
	self.handler = handler
}

func (self *Context) SetDecodeFunc(fn func(out interface{}) error) {
	self.decode = fn
}

func (self *Context) Decode(out interface{}) error {
	return self.decode(out)
}

func (self *Context) SetUser(u IUser) {
	self.user = u
}

func (self *Context) Store() *store {
	if self.store == nil {
		self.store = newStore()
	}

	return self.store
}

func (self *Context) SetReq(req *http.Request) {
	self.req = &Request{
		Request: req,
	}
}

func (self *Context) Req() *Request {
	return self.req
}

func (self *Context) initParams() {
	if self.runParseMultipartForm {
		return
	}

	// 32m
	self.req.ParseMultipartForm(32 << 20)
	self.params = &urlValues{&self.req.Form}
	self.runParseMultipartForm = true
}

func (self *Context) Params() *urlValues {
	self.initParams()
	return self.params
}
<commit_msg>fix User() method does not return default value<commit_after>package rest

import (
	"encoding/json"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strconv"
)

func NewContext() IContext {
	c := new(Context)
	c.params = &urlValues{&url.Values{}}

	// Default "decode"
	c.SetDecodeFunc(func(out interface{}) error {
		if c.reqBody == nil {
			defer c.req.Body.Close()
			v, err := ioutil.ReadAll(c.req.Body)
			c.reqBody = v
			if err != nil {
				return err
			}
		}

		return json.Unmarshal(c.reqBody, out)
	})

	return c
}

type urlValues struct {
	*url.Values
}

func (self *urlValues) Int(key string) int {
	i, _ := strconv.Atoi(self.Get(key))
	return i
}

func (self *urlValues) Bool(key string) bool {
	v := self.Get(key)
	return v == "true" || v == "1"
}

type Request struct {
	*http.Request
}

func (self *Request) Ip() string {
	ip, _, _ := net.SplitHostPort(self.RemoteAddr)
	return ip
}

type Context struct {
	req                   *Request
	reqBody               []byte
	params                *urlValues
	user                  IUser
	runParseMultipartForm bool
	store                 *store
	handler               *Handler
	AutoSetUser           func()
	decode                func(out interface{}) error
}

func (self *Context) User() IUser {
	if self.user == nil {
		self.AutoSetUser()
		if self.user == nil {
			self.user = new(User)
		}
	}

	return self.user
}

func (self *Context) SetAutoSetUserFunc(fn func()) {
	self.AutoSetUser = fn
}

func (self *Context) Handler() *Handler {
	return self.handler
}

func (self *Context) SetHandler(handler *Handler) {
	self.handler = handler
}

func (self *Context) SetDecodeFunc(fn func(out interface{}) error) {
	self.decode = fn
}

func (self *Context) Decode(out interface{}) error {
	return self.decode(out)
}

func (self *Context) SetUser(u IUser) {
	self.user = u
}

func (self *Context) Store() *store {
	if self.store == nil {
		self.store = newStore()
	}

	return self.store
}

func (self *Context) SetReq(req *http.Request) {
	self.req = &Request{
		Request: req,
	}
}

func (self *Context) Req() *Request {
	return self.req
}

func (self *Context) initParams() {
	if self.runParseMultipartForm {
		return
	}

	// 32m
	self.req.ParseMultipartForm(32 << 20)
	self.params = &urlValues{&self.req.Form}
	self.runParseMultipartForm = true
}

func (self *Context) Params() *urlValues {
	self.initParams()
	return self.params
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 HenryLee. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package teleport

import (
	"net/url"
	"reflect"

	"github.com/henrylee2cn/goutil"

	"github.com/henrylee2cn/teleport/socket"
)

type (
	// RequestCtx request handler context.
	// For example:
	//  type Home struct{ RequestCtx }
	RequestCtx interface {
		PushCtx
		SetBodyCodec(string)
	}
	// PushCtx push handler context.
	// For example:
	//  type Home struct{ PushCtx }
	PushCtx interface {
		Uri() string
		Path() string
		Query() url.Values
		Public() goutil.Map
		PublicLen() int
		Ip() string
		// RealIp() string
	}
	// ApiContext the underlying common instance of RequestCtx and PushCtx.
	ApiContext struct {
		session      *Session
		input        *socket.Packet
		output       *socket.Packet
		apiType      *Handler
		originStruct reflect.Value
		method       reflect.Method
		arg          reflect.Value
		pullCmd      *PullCmd
		uri          *url.URL
		query        url.Values
		public       goutil.Map
		next         *ApiContext
	}
)

var (
	_ RequestCtx = new(ApiContext)
	_ PushCtx    = new(ApiContext)
)

// newApiContext creates a ApiContext for one request/response or push.
func newApiContext() *ApiContext {
	c := new(ApiContext)
	c.input = socket.NewPacket(c.binding)
	c.output = socket.NewPacket(nil)
	return c
}

func (c *ApiContext) reInit(s *Session) {
	c.session = s
	c.public = goutil.RwMap()
	if s.socket.PublicLen() > 0 {
		s.socket.Public().Range(func(key, value interface{}) bool {
			c.public.Store(key, value)
			return true
		})
	}
}

var (
	emptyValue  = reflect.Value{}
	emptyMethod = reflect.Method{}
)

func (c *ApiContext) clean() {
	c.session = nil
	c.apiType = nil
	c.arg = emptyValue
	c.originStruct = emptyValue
	c.method = emptyMethod
	c.pullCmd = nil
	c.public = nil
	c.uri = nil
	c.query = nil
	c.input.Reset(c.binding)
	c.output.Reset(nil)
}

// Public returns temporary public data of Conn Context.
func (c *ApiContext) Public() goutil.Map {
	return c.public
}

// PublicLen returns the length of public data of Conn Context.
func (c *ApiContext) PublicLen() int {
	return c.public.Len()
}

func (c *ApiContext) Uri() string {
	return c.input.Header.Uri
}

func (c *ApiContext) Path() string {
	return c.uri.Path
}

func (c *ApiContext) Query() url.Values {
	if c.query == nil {
		c.query = c.uri.Query()
	}
	return c.query
}

func (c *ApiContext) SetBodyCodec(codecName string) {
	c.output.BodyCodec = codecName
}

func (c *ApiContext) Ip() string {
	return c.session.socket.RemoteAddr().String()
}

func (c *ApiContext) binding(header *socket.Header) interface{} {
	switch header.Type {
	case TypeResponse:
		return c.bindResponse(header)

	case TypePush:
		return c.bindPush(header)

	case TypeRequest:
		return c.bindRequest(header)

	default:
		return nil
	}
}

// TODO
func (c *ApiContext) bindResponse(header *socket.Header) interface{} {
	pullCmd, ok := c.session.pullCmdMap.Load(header.Seq)
	if !ok {
		return nil
	}
	c.session.pullCmdMap.Delete(header.Seq)
	c.pullCmd = pullCmd.(*PullCmd)
	return c.pullCmd.reply
}

func (c *ApiContext) bindPush(header *socket.Header) interface{} {
	var err error
	c.uri, err = url.Parse(header.Uri)
	if err != nil {
		return nil
	}
	var ok bool
	c.apiType, ok = c.session.pushRouter.get(c.Path())
	if !ok {
		return nil
	}
	c.arg = reflect.New(c.apiType.arg)
	return c.arg.Interface()
}

func (c *ApiContext) bindRequest(header *socket.Header) interface{} {
	c.output.Header.Seq = c.input.Header.Seq
	c.output.Header.Type = TypeResponse
	c.output.Header.Uri = c.input.Header.Uri
	c.output.HeaderCodec = c.input.HeaderCodec
	c.output.Header.Gzip = c.input.Header.Gzip

	var err error
	c.uri, err = url.Parse(header.Uri)
	if err != nil {
		c.output.Header.StatusCode = StatusBadRequest
		c.output.Header.Status = err.Error()
		return nil
	}
	var ok bool
	c.apiType, ok = c.session.requestRouter.get(c.Path())
	if !ok {
		c.output.Header.StatusCode = StatusNotFound
		c.output.Header.Status = StatusText(StatusNotFound)
		return nil
	}
	c.arg = reflect.New(c.apiType.arg)
	return c.arg.Interface()
}

// handle handles request and push packet.
func (c *ApiContext) handle() {
	rets := c.apiType.method.Func.Call([]reflect.Value{c.arg})
	if len(rets) == 0 {
		return
	}
	c.output.Body = rets[0].Interface()
	e := rets[0].Interface().(Xerror)
	if e == nil {
		c.output.Header.StatusCode = StatusOK
		c.output.Header.Status = StatusText(StatusOK)
	} else {
		c.output.Header.StatusCode = e.Code()
		c.output.Header.Status = e.Text()
	}
	if len(c.output.BodyCodec) == 0 {
		c.output.BodyCodec = c.input.BodyCodec
	}
}

// respHandle handles request and push packet.
func (c *ApiContext) respHandle() {
	c.pullCmd.done()
}
<commit_msg>optimize comment<commit_after>// Copyright 2015-2017 HenryLee. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package teleport

import (
	"net/url"
	"reflect"

	"github.com/henrylee2cn/goutil"

	"github.com/henrylee2cn/teleport/socket"
)

type (
	// RequestCtx request handler context.
	// For example:
	//  type Home struct{ RequestCtx }
	RequestCtx interface {
		PushCtx
		SetBodyCodec(string)
	}
	// PushCtx push handler context.
	// For example:
	//  type Home struct{ PushCtx }
	PushCtx interface {
		Uri() string
		Path() string
		Query() url.Values
		Public() goutil.Map
		PublicLen() int
		Ip() string
		// RealIp() string
	}
	// ApiContext the underlying common instance of RequestCtx and PushCtx.
	ApiContext struct {
		session      *Session
		input        *socket.Packet
		output       *socket.Packet
		apiType      *Handler
		originStruct reflect.Value
		method       reflect.Method
		arg          reflect.Value
		pullCmd      *PullCmd
		uri          *url.URL
		query        url.Values
		public       goutil.Map
		next         *ApiContext
	}
)

var (
	_ RequestCtx = new(ApiContext)
	_ PushCtx    = new(ApiContext)
)

// newApiContext creates a ApiContext for one request/response or push.
func newApiContext() *ApiContext {
	c := new(ApiContext)
	c.input = socket.NewPacket(c.binding)
	c.output = socket.NewPacket(nil)
	return c
}

func (c *ApiContext) reInit(s *Session) {
	c.session = s
	c.public = goutil.RwMap()
	if s.socket.PublicLen() > 0 {
		s.socket.Public().Range(func(key, value interface{}) bool {
			c.public.Store(key, value)
			return true
		})
	}
}

var (
	emptyValue  = reflect.Value{}
	emptyMethod = reflect.Method{}
)

func (c *ApiContext) clean() {
	c.session = nil
	c.apiType = nil
	c.arg = emptyValue
	c.originStruct = emptyValue
	c.method = emptyMethod
	c.pullCmd = nil
	c.public = nil
	c.uri = nil
	c.query = nil
	c.input.Reset(c.binding)
	c.output.Reset(nil)
}

// Public returns temporary public data of Conn Context.
func (c *ApiContext) Public() goutil.Map {
	return c.public
}

// PublicLen returns the length of public data of Conn Context.
func (c *ApiContext) PublicLen() int {
	return c.public.Len()
}

// Uri returns the input packet uri.
func (c *ApiContext) Uri() string {
	return c.input.Header.Uri
}

// Path returns the input packet uri path.
func (c *ApiContext) Path() string {
	return c.uri.Path
}

// Query returns the input packet uri query.
func (c *ApiContext) Query() url.Values {
	if c.query == nil {
		c.query = c.uri.Query()
	}
	return c.query
}

// SetBodyCodec sets the body codec for response packet.
func (c *ApiContext) SetBodyCodec(codecName string) {
	c.output.BodyCodec = codecName
}

// Ip returns the remote addr.
func (c *ApiContext) Ip() string {
	return c.session.socket.RemoteAddr().String()
}

func (c *ApiContext) binding(header *socket.Header) interface{} {
	switch header.Type {
	case TypeResponse:
		return c.bindResponse(header)

	case TypePush:
		return c.bindPush(header)

	case TypeRequest:
		return c.bindRequest(header)

	default:
		return nil
	}
}

func (c *ApiContext) bindResponse(header *socket.Header) interface{} {
	pullCmd, ok := c.session.pullCmdMap.Load(header.Seq)
	if !ok {
		return nil
	}
	c.session.pullCmdMap.Delete(header.Seq)
	c.pullCmd = pullCmd.(*PullCmd)
	return c.pullCmd.reply
}

func (c *ApiContext) bindPush(header *socket.Header) interface{} {
	var err error
	c.uri, err = url.Parse(header.Uri)
	if err != nil {
		return nil
	}
	var ok bool
	c.apiType, ok = c.session.pushRouter.get(c.Path())
	if !ok {
		return nil
	}
	c.arg = reflect.New(c.apiType.arg)
	return c.arg.Interface()
}

func (c *ApiContext) bindRequest(header *socket.Header) interface{} {
	c.output.Header.Seq = c.input.Header.Seq
	c.output.Header.Type = TypeResponse
	c.output.Header.Uri = c.input.Header.Uri
	c.output.HeaderCodec = c.input.HeaderCodec
	c.output.Header.Gzip = c.input.Header.Gzip

	var err error
	c.uri, err = url.Parse(header.Uri)
	if err != nil {
		c.output.Header.StatusCode = StatusBadRequest
		c.output.Header.Status = err.Error()
		return nil
	}
	var ok bool
	c.apiType, ok = c.session.requestRouter.get(c.Path())
	if !ok {
		c.output.Header.StatusCode = StatusNotFound
		c.output.Header.Status = StatusText(StatusNotFound)
		return nil
	}
	c.arg = reflect.New(c.apiType.arg)
	return c.arg.Interface()
}

// handle handles request and push packet.
func (c *ApiContext) handle() {
	rets := c.apiType.method.Func.Call([]reflect.Value{c.arg})
	if len(rets) == 0 {
		return
	}
	c.output.Body = rets[0].Interface()
	e := rets[0].Interface().(Xerror)
	if e == nil {
		c.output.Header.StatusCode = StatusOK
		c.output.Header.Status = StatusText(StatusOK)
	} else {
		c.output.Header.StatusCode = e.Code()
		c.output.Header.Status = e.Text()
	}
	if len(c.output.BodyCodec) == 0 {
		c.output.BodyCodec = c.input.BodyCodec
	}
}

// respHandle handles request and push packet.
func (c *ApiContext) respHandle() {
	c.pullCmd.done()
}
<|endoftext|>


<commit_before>/*
   Copyright 2012 the go.wde 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 xgb

import (
	"fmt"
	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/xproto"
	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/icccm"
	"github.com/BurntSushi/xgbutil/keybind"
	"github.com/BurntSushi/xgbutil/xgraphics"
	"github.com/BurntSushi/xgbutil/xwindow"
	"github.com/skelterjohn/go.wde"
	"image"
	"sync"
)

func init() {
	wde.BackendNewWindow = func(width, height int) (w wde.Window, err error) {
		w, err = NewWindow(width, height)
		return
	}
	ch := make(chan struct{}, 1)
	wde.BackendRun = func() {
		<-ch
	}
	wde.BackendStop = func() {
		ch <- struct{}{}
	}
}

const AllEventsMask = xproto.EventMaskKeyPress |
	xproto.EventMaskKeyRelease |
	xproto.EventMaskButtonPress |
	xproto.EventMaskButtonRelease |
	xproto.EventMaskEnterWindow |
	xproto.EventMaskLeaveWindow |
	xproto.EventMaskPointerMotion |
	xproto.EventMaskStructureNotify

type Window struct {
	win           *xwindow.Window
	xu            *xgbutil.XUtil
	conn          *xgb.Conn
	buffer        *xgraphics.Image
	bufferLck     *sync.Mutex
	width, height int
	closed        bool

	events chan interface{}
}

func NewWindow(width, height int) (w *Window, err error) {

	w = new(Window)
	w.width, w.height = width, height

	w.xu, err = xgbutil.NewConn()
	if err != nil {
		return
	}

	w.conn = w.xu.Conn()
	screen := w.xu.Screen()

	w.win, err = xwindow.Generate(w.xu)
	if err != nil {
		return
	}

	err = w.win.CreateChecked(screen.Root, 600, 500, width, height, 0)
	if err != nil {
		return
	}

	w.win.Listen(AllEventsMask)

	err = icccm.WmProtocolsSet(w.xu, w.win.Id, []string{"WM_DELETE_WINDOW"})
	if err != nil {
		fmt.Println(err)
		err = nil
	}

	w.bufferLck = &sync.Mutex{}
	w.buffer = xgraphics.New(w.xu, image.Rect(0, 0, width, height))
	w.buffer.XSurfaceSet(w.win.Id)

	keyMap, modMap := keybind.MapsGet(w.xu)
	keybind.KeyMapSet(w.xu, keyMap)
	keybind.ModMapSet(w.xu, modMap)

	w.events = make(chan interface{})

	w.SetIcon(Gordon)
	w.SetIconName("Go")

	go w.handleEvents()

	return
}

func (w *Window) SetTitle(title string) {
	if w.closed {
		return
	}
	err := ewmh.WmNameSet(w.xu, w.win.Id, title)
	if err != nil {
		// TODO: log
	}
	return
}

func (w *Window) SetSize(width, height int) {
	if w.closed {
		return
	}

	w.win.Resize(width, height)
	w.width, w.height = width, height
	return
}

func (w *Window) Size() (width, height int) {
	if w.closed {
		return
	}
	width, height = w.width, w.height
	return
}

func (w *Window) LockSize(lock bool) {

}

func (w *Window) Show() {
	if w.closed {
		return
	}
	w.win.Map()
}

func (w *Window) Screen() (im wde.Image) {
	if w.closed {
		return
	}
	im = &Image{w.buffer}
	return
}

func (w *Window) FlushImage(bounds ...image.Rectangle) {

	if w.closed {
		return
	}
	if w.buffer.Pixmap == 0 {
		w.bufferLck.Lock()
		if err := w.buffer.XSurfaceSet(w.win.Id); err != nil {
			fmt.Println(err)
		}
		w.bufferLck.Unlock()
	}
	w.buffer.XDraw()
	w.buffer.XPaint(w.win.Id)
}

func (w *Window) Close() (err error) {
	if w.closed {
		return
	}
	w.win.Destroy()
	w.closed = true
	return
}

type Image struct {
	*xgraphics.Image
}

func (buffer Image) CopyRGBA(src *image.RGBA, r image.Rectangle) {
        // clip r against each image's bounds and move sp accordingly (see draw.clip())
	sp := image.ZP
	orig := r.Min
	r = r.Intersect(buffer.Bounds())
	r = r.Intersect(src.Bounds().Add(orig.Sub(sp)))
	dx := r.Min.X - orig.X
	dy := r.Min.Y - orig.Y
	(sp).X += dx
	(sp).Y += dy

	i0 := (r.Min.X - buffer.Rect.Min.X) * 4
	i1 := (r.Max.X - buffer.Rect.Min.X) * 4
	si0 := (sp.X - src.Rect.Min.X) * 4
	yMax := r.Max.Y - buffer.Rect.Min.Y

	y := r.Min.Y - buffer.Rect.Min.Y
	sy := sp.Y - src.Rect.Min.Y
	for ; y != yMax; y, sy = y+1, sy+1 {
		dpix := buffer.Pix[y*buffer.Stride:]
		spix := src.Pix[sy*src.Stride:]

		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
			dpix[i+0] = spix[si+2]
			dpix[i+1] = spix[si+1]
			dpix[i+2] = spix[si+0]
			dpix[i+3] = spix[si+3]
		}
	}
}
<commit_msg>Implement LockSize() on xgb<commit_after>/*
   Copyright 2012 the go.wde 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 xgb

import (
	"fmt"
	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/xproto"
	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/icccm"
	"github.com/BurntSushi/xgbutil/keybind"
	"github.com/BurntSushi/xgbutil/xgraphics"
	"github.com/BurntSushi/xgbutil/xwindow"
	"github.com/skelterjohn/go.wde"
	"image"
	"sync"
)

func init() {
	wde.BackendNewWindow = func(width, height int) (w wde.Window, err error) {
		w, err = NewWindow(width, height)
		return
	}
	ch := make(chan struct{}, 1)
	wde.BackendRun = func() {
		<-ch
	}
	wde.BackendStop = func() {
		ch <- struct{}{}
	}
}

const AllEventsMask = xproto.EventMaskKeyPress |
	xproto.EventMaskKeyRelease |
	xproto.EventMaskButtonPress |
	xproto.EventMaskButtonRelease |
	xproto.EventMaskEnterWindow |
	xproto.EventMaskLeaveWindow |
	xproto.EventMaskPointerMotion |
	xproto.EventMaskStructureNotify

type Window struct {
	win           *xwindow.Window
	xu            *xgbutil.XUtil
	conn          *xgb.Conn
	buffer        *xgraphics.Image
	bufferLck     *sync.Mutex
	width, height int
	lockedSize    bool
	closed        bool

	events chan interface{}
}

func NewWindow(width, height int) (w *Window, err error) {

	w = new(Window)
	w.width, w.height = width, height

	w.xu, err = xgbutil.NewConn()
	if err != nil {
		return
	}

	w.conn = w.xu.Conn()
	screen := w.xu.Screen()

	w.win, err = xwindow.Generate(w.xu)
	if err != nil {
		return
	}

	err = w.win.CreateChecked(screen.Root, 600, 500, width, height, 0)
	if err != nil {
		return
	}

	w.win.Listen(AllEventsMask)

	err = icccm.WmProtocolsSet(w.xu, w.win.Id, []string{"WM_DELETE_WINDOW"})
	if err != nil {
		fmt.Println(err)
		err = nil
	}

	w.bufferLck = &sync.Mutex{}
	w.buffer = xgraphics.New(w.xu, image.Rect(0, 0, width, height))
	w.buffer.XSurfaceSet(w.win.Id)

	keyMap, modMap := keybind.MapsGet(w.xu)
	keybind.KeyMapSet(w.xu, keyMap)
	keybind.ModMapSet(w.xu, modMap)

	w.events = make(chan interface{})

	w.SetIcon(Gordon)
	w.SetIconName("Go")

	go w.handleEvents()

	return
}

func (w *Window) SetTitle(title string) {
	if w.closed {
		return
	}
	err := ewmh.WmNameSet(w.xu, w.win.Id, title)
	if err != nil {
		// TODO: log
	}
	return
}

func (w *Window) SetSize(width, height int) {
	if w.closed {
		return
	}

	w.width, w.height = width, height
	if w.lockedSize {
		w.updateSizeHints()
	}
	w.win.Resize(width, height)
	return
}

func (w *Window) Size() (width, height int) {
	if w.closed {
		return
	}
	width, height = w.width, w.height
	return
}

func (w *Window) LockSize(lock bool) {
	w.lockedSize = lock
	w.updateSizeHints()
}

func (w *Window) updateSizeHints() {
	hints := new(icccm.NormalHints)
	if w.lockedSize {
		hints.Flags = icccm.SizeHintPMinSize | icccm.SizeHintPMaxSize
		hints.MinWidth = uint(w.width)
		hints.MaxWidth = uint(w.width)
		hints.MinHeight = uint(w.height)
		hints.MaxHeight = uint(w.height)
	}
	icccm.WmNormalHintsSet(w.xu, w.win.Id, hints)
}

func (w *Window) Show() {
	if w.closed {
		return
	}
	w.win.Map()
}

func (w *Window) Screen() (im wde.Image) {
	if w.closed {
		return
	}
	im = &Image{w.buffer}
	return
}

func (w *Window) FlushImage(bounds ...image.Rectangle) {

	if w.closed {
		return
	}
	if w.buffer.Pixmap == 0 {
		w.bufferLck.Lock()
		if err := w.buffer.XSurfaceSet(w.win.Id); err != nil {
			fmt.Println(err)
		}
		w.bufferLck.Unlock()
	}
	w.buffer.XDraw()
	w.buffer.XPaint(w.win.Id)
}

func (w *Window) Close() (err error) {
	if w.closed {
		return
	}
	w.win.Destroy()
	w.closed = true
	return
}

type Image struct {
	*xgraphics.Image
}

func (buffer Image) CopyRGBA(src *image.RGBA, r image.Rectangle) {
        // clip r against each image's bounds and move sp accordingly (see draw.clip())
	sp := image.ZP
	orig := r.Min
	r = r.Intersect(buffer.Bounds())
	r = r.Intersect(src.Bounds().Add(orig.Sub(sp)))
	dx := r.Min.X - orig.X
	dy := r.Min.Y - orig.Y
	(sp).X += dx
	(sp).Y += dy

	i0 := (r.Min.X - buffer.Rect.Min.X) * 4
	i1 := (r.Max.X - buffer.Rect.Min.X) * 4
	si0 := (sp.X - src.Rect.Min.X) * 4
	yMax := r.Max.Y - buffer.Rect.Min.Y

	y := r.Min.Y - buffer.Rect.Min.Y
	sy := sp.Y - src.Rect.Min.Y
	for ; y != yMax; y, sy = y+1, sy+1 {
		dpix := buffer.Pix[y*buffer.Stride:]
		spix := src.Pix[sy*src.Stride:]

		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
			dpix[i+0] = spix[si+2]
			dpix[i+1] = spix[si+1]
			dpix[i+2] = spix[si+0]
			dpix[i+3] = spix[si+3]
		}
	}
}
<|endoftext|>