<commit_before>/*
Copyright 2019 The Kubernetes Authors 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 problem

import "regexp"

// re is a shortcut around regexp.MustCompile
func re(s string) *regexp.Regexp {
	return regexp.MustCompile(s)
}

// vmProblems are VM related problems
var vmProblems = map[string]match{
	"SERVICE_NOT_FOUND": {
		Regexp: re(`Could not find finalized endpoint being pointed to by`),
		Advice: "Please make sure the service you are looking for is deployed or is in the correct namespace.",
		Issues: []int{4599},
	},
	"HYPERKIT_NO_IP": {
		Regexp: re(`IP address never found in dhcp leases file Temporary Error: Could not find an IP address for`),
		Advice: "Install the latest minikube hyperkit driver, and run 'minikube delete'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver",
		Issues: []int{1926, 4206},
	},
	"VBOX_NOT_FOUND": {
		Regexp: re(`VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path`),
		Advice: "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver",
		URL:    "https://www.virtualbox.org/wiki/Downloads",
		Issues: []int{3784, 3776},
	},
	"VBOX_VTX_DISABLED": {
		Regexp: re(`This computer doesn't have VT-X/AMD-v enabled`),
		Advice: "In some environments, this message is incorrect. Try 'minikube start --no-vtx-check'",
		Issues: []int{3900},
	},
	"VBOX_VERR_VMX_NO_VMX": {
		Regexp: re(`VT-x is not available.*VERR_VMX_NO_VMX`),
		Advice: "Please check your BIOS, and ensure that you are running without HyperV or other nested virtualization that may interfere",
		Issues: []int{1994},
	},
	"VBOX_BLOCKED": {
		Regexp: re(`NS_ERROR_FAILURE.*0x80004005`),
		Advice: "Reinstall VirtualBox and verify that it is not blocked: System Preferences -> Security & Privacy -> General -> Some system software was blocked from loading",
		Issues: []int{4107},
		GOOS:   "darwin",
	},
	"VBOX_DRV_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"VBOX_DEVICE_MISSING": {
		Regexp: re(`/dev/vboxdrv does not exist`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{3974},
	},
	"VBOX_HARDENING": {
		Regexp: re(`terminated unexpectedly.*VBoxHardening`),
		Advice: "Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.",
		Issues: []int{3859, 3910},
		URL:    "https://forums.virtualbox.org/viewtopic.php?f=25&t=82106",
		GOOS:   "windows",
	},
	"VBOX_HOST_ADAPTER": {
		Regexp: re(`The host-only adapter we just created is not visible`),
		Advice: "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system",
		Issues: []int{3614, 4222},
		URL:    "https://stackoverflow.com/questions/52277019/how-to-fix-vm-issue-with-minikube-start",
	},
	"VBOX_KERNEL_MODULE_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"KVM2_NOT_FOUND": {
		Regexp: re(`Driver "kvm2" not found. Do you have the plugin binary .* accessible in your PATH`),
		Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
	},
	"KVM2_RESTART_NO_IP": {
		Regexp: re(`Error starting stopped host: Machine didn't return an IP after 120 seconds`),
		Advice: "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.",
		Issues: []int{3901, 3434},
	},
	"KVM2_START_NO_IP": {
		Regexp: re(`Error in driver during machine creation: Machine didn't return an IP after 120 seconds`),
		Advice: "Install the latest kvm2 driver and run 'virt-host-validate'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
		Issues: []int{4249, 3566},
	},
	"KVM2_NETWORK_DEFINE_XML": {
		Regexp: re(`not supported by the connection driver: virNetworkDefineXML`),
		Advice: "Rebuild libvirt with virt-network support",
		URL:    "https://forums.gentoo.org/viewtopic-t-981692-start-0.html",
		Issues: []int{4195},
	},
	"KVM2_QEMU_MONITOR": {
		Regexp: re(`qemu unexpectedly closed the monitor`),
		Advice: "Upgrade to QEMU v3.1.0+, run 'virt-host-validate', or ensure that you are not running in a nested VM environment.",
		Issues: []int{4277},
	},
	"KVM_UNAVAILABLE": {
		Regexp: re(`invalid argument: could not find capabilities for domaintype=kvm`),
		Advice: "Your host does not support KVM virtualization. Ensure that qemu-kvm is installed, and run 'virt-host-validate' to debug the problem",
		URL:    "http://mikko.repolainen.fi/documents/virtualization-with-kvm",
		Issues: []int{2991},
	},
	"KVM_CONNECTION_ERROR": {
		Regexp: re(`error connecting to libvirt socket`),
		Advice: "Have you set up libvirt correctly?",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
	},
	"DRIVER_CRASHED": {
		Regexp: re(`Error attempting to get plugin server address for RPC`),
		Advice: "The VM driver exited with an error, and may be corrupt. Run 'minikube start' with --alsologtostderr -v=8 to see the error",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md",
	},
	"DRIVER_EXITED": {
		Regexp: re(`Unable to start VM: create: creating: exit status 1`),
		Advice: "Re-run 'minikube start' with --alsologtostderr -v=8 to see the VM driver error message",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#troubleshooting",
	},
	"VM_BOOT_FAILED_HYPERV_ENABLED": {
		Regexp: re(`VirtualBox won't boot a 64bits VM when Hyper-V is activated`),
		Advice: "Disable Hyper-V when you want to run VirtualBox to boot the VM",
		Issues: []int{4051},
	},
	"HYPERV_NO_VSWITCH": {
		Regexp: re(`no External vswitch found. A valid vswitch must be available for this command to run.`),
		Advice: "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=<switch-name>` to `minikube start`",
		URL:    "https://docs.docker.com/machine/drivers/hyper-v/",
	},
	"HOST_CIDR_CONFLICT": {
		Regexp: re(`host-only cidr conflicts with the network address of a host interface`),
		Advice: "Specify an alternate --host-only-cidr value, such as 172.16.0.1/24",
		Issues: []int{3594},
	},
	"OOM_KILL_SSH": {
		Regexp: re(`Process exited with status 137 from signal KILL`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
	"OOM_KILL_SCP": {
		Regexp: re(`An existing connection was forcibly closed by the remote host`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
}

// proxyDoc is the URL to proxy documentation
const proxyDoc = "https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md"

// netProblems are network related problems.
var netProblems = map[string]match{
	"GCR_UNAVAILABLE": {
		Regexp: re(`gcr.io.*443: connect: invalid argument`),
		Advice: "minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.",
		URL:    proxyDoc,
		Issues: []int{3860},
	},
	"DOWNLOAD_RESET_BY_PEER": {
		Regexp: re(`Error downloading .*connection reset by peer`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3909},
	},
	"DOWNLOAD_IO_TIMEOUT": {
		Regexp: re(`Error downloading .*timeout`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3846},
	},
	"DOWNLOAD_TLS_OVERSIZED": {
		Regexp: re(`tls: oversized record received with length`),
		Advice: "A firewall is interfering with minikube's ability to make outgoing HTTPS requests. You may need to change the value of the HTTPS_PROXY environment variable.",
		URL:    proxyDoc,
		Issues: []int{3857, 3759, 4252},
	},
	"ISO_DOWNLOAD_FAILED": {
		Regexp: re(`iso: failed to download`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3922},
	},
	"PULL_TIMEOUT_EXCEEDED": {
		Regexp: re(`failed to pull image k8s.gcr.io.*Client.Timeout exceeded while awaiting headers`),
		Advice: "A firewall is blocking Docker within the minikube VM from reaching the internet. You may need to configure it to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3898},
	},
	"SSH_AUTH_FAILURE": {
		Regexp: re(`ssh: handshake failed: ssh: unable to authenticate.*, no supported methods remain`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3930},
	},
	"SSH_TCP_FAILURE": {
		Regexp: re(`dial tcp .*:22: connectex: A connection attempt failed because the connected party did not properly respond`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3388},
	},
	"INVALID_PROXY_HOSTNAME": {
		Regexp: re(`dial tcp: lookup.*: no such host`),
		Advice: "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.",
		URL:    proxyDoc,
	},
}

// deployProblems are Kubernetes deployment problems.
var deployProblems = map[string]match{
	"DOCKER_UNAVAILABLE": {
		Regexp: re(`Error configuring auth on host: OS type not recognized`),
		Advice: "Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.",
		Issues: []int{3952},
	},
	"INVALID_KUBERNETES_VERSION": {
		Regexp: re(`No Major.Minor.Patch elements found`),
		Advice: "Specify --kubernetes-version in v<major>.<minor.<build> form. example: 'v1.1.14'",
	},
	"KUBERNETES_VERSION_MISSING_V": {
		Regexp: re(`strconv.ParseUint: parsing "": invalid syntax`),
		Advice: "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'",
	},
	"APISERVER_TIMEOUT": {
		Regexp: re(`wait: waiting for component=kube-apiserver: timed out waiting for the condition`),
		Advice: "Run 'minikube delete'. If the problem persists, check your proxy or firewall configuration",
		Issues: []int{4202, 3836, 4221},
	},
}

// osProblems are operating-system specific issues
var osProblems = map[string]match{
	"NON_C_DRIVE": {
		Regexp: re(`.iso: The system cannot find the path specified.`),
		Advice: "Run minikube from the C: drive.",
		Issues: []int{1574},
	},
	"SYSTEMCTL_EXIT_1": {
		Regexp: re(`Failed to enable container runtime: .*sudo systemctl start docker: exit status 1`),
		Advice: "If using the none driver, ensure that systemctl is installed",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md",
		Issues: []int{2704},
	},
}

// stateProblems are issues relating to local state
var stateProblems = map[string]match{
	"MACHINE_DOES_NOT_EXST": {
		Regexp: re(`Error getting state for host: machine does not exist`),
		Advice: "Run 'minikube delete' to delete the stale VM",
		Issues: []int{3864},
	},
	"IP_NOT_FOUND": {
		Regexp: re(`Error getting ssh host name for driver: IP not found`),
		Advice: "The minikube VM is offline. Please run 'minikube start' to start it again.",
		Issues: []int{3849, 3648},
	},
}
<commit_msg>hyperv: Powershell was not found in the path<commit_after>/*
Copyright 2019 The Kubernetes Authors 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 problem

import "regexp"

// re is a shortcut around regexp.MustCompile
func re(s string) *regexp.Regexp {
	return regexp.MustCompile(s)
}

// vmProblems are VM related problems
var vmProblems = map[string]match{
	"SERVICE_NOT_FOUND": {
		Regexp: re(`Could not find finalized endpoint being pointed to by`),
		Advice: "Please make sure the service you are looking for is deployed or is in the correct namespace.",
		Issues: []int{4599},
	},
	"HYPERKIT_NO_IP": {
		Regexp: re(`IP address never found in dhcp leases file Temporary Error: Could not find an IP address for`),
		Advice: "Install the latest minikube hyperkit driver, and run 'minikube delete'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver",
		Issues: []int{1926, 4206},
	},
	"VBOX_NOT_FOUND": {
		Regexp: re(`VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path`),
		Advice: "Install VirtualBox, ensure that VBoxManage is executable and in path, or select an alternative value for --vm-driver",
		URL:    "https://www.virtualbox.org/wiki/Downloads",
		Issues: []int{3784, 3776},
	},
	"VBOX_VTX_DISABLED": {
		Regexp: re(`This computer doesn't have VT-X/AMD-v enabled`),
		Advice: "In some environments, this message is incorrect. Try 'minikube start --no-vtx-check'",
		Issues: []int{3900},
	},
	"VBOX_VERR_VMX_NO_VMX": {
		Regexp: re(`VT-x is not available.*VERR_VMX_NO_VMX`),
		Advice: "Please check your BIOS, and ensure that you are running without HyperV or other nested virtualization that may interfere",
		Issues: []int{1994},
	},
	"VBOX_BLOCKED": {
		Regexp: re(`NS_ERROR_FAILURE.*0x80004005`),
		Advice: "Reinstall VirtualBox and verify that it is not blocked: System Preferences -> Security & Privacy -> General -> Some system software was blocked from loading",
		Issues: []int{4107},
		GOOS:   "darwin",
	},
	"VBOX_DRV_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"VBOX_DEVICE_MISSING": {
		Regexp: re(`/dev/vboxdrv does not exist`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{3974},
	},
	"VBOX_HARDENING": {
		Regexp: re(`terminated unexpectedly.*VBoxHardening`),
		Advice: "Disable real-time anti-virus software, reboot, and reinstall VirtualBox if the problem continues.",
		Issues: []int{3859, 3910},
		URL:    "https://forums.virtualbox.org/viewtopic.php?f=25&t=82106",
		GOOS:   "windows",
	},
	"VBOX_HOST_ADAPTER": {
		Regexp: re(`The host-only adapter we just created is not visible`),
		Advice: "Reboot to complete VirtualBox installation, and verify that VirtualBox is not blocked by your system",
		Issues: []int{3614, 4222},
		URL:    "https://stackoverflow.com/questions/52277019/how-to-fix-vm-issue-with-minikube-start",
	},
	"VBOX_KERNEL_MODULE_NOT_LOADED": {
		Regexp: re(`The vboxdrv kernel module is not loaded`),
		Advice: "Run 'sudo modprobe vboxdrv' and reinstall VirtualBox if it fails.",
		Issues: []int{4043},
	},
	"KVM2_NOT_FOUND": {
		Regexp: re(`Driver "kvm2" not found. Do you have the plugin binary .* accessible in your PATH`),
		Advice: "Please install the minikube kvm2 VM driver, or select an alternative --vm-driver",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
	},
	"KVM2_RESTART_NO_IP": {
		Regexp: re(`Error starting stopped host: Machine didn't return an IP after 120 seconds`),
		Advice: "The KVM driver is unable to resurrect this old VM. Please run `minikube delete` to delete it and try again.",
		Issues: []int{3901, 3434},
	},
	"KVM2_START_NO_IP": {
		Regexp: re(`Error in driver during machine creation: Machine didn't return an IP after 120 seconds`),
		Advice: "Install the latest kvm2 driver and run 'virt-host-validate'",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
		Issues: []int{4249, 3566},
	},
	"KVM2_NETWORK_DEFINE_XML": {
		Regexp: re(`not supported by the connection driver: virNetworkDefineXML`),
		Advice: "Rebuild libvirt with virt-network support",
		URL:    "https://forums.gentoo.org/viewtopic-t-981692-start-0.html",
		Issues: []int{4195},
	},
	"KVM2_QEMU_MONITOR": {
		Regexp: re(`qemu unexpectedly closed the monitor`),
		Advice: "Upgrade to QEMU v3.1.0+, run 'virt-host-validate', or ensure that you are not running in a nested VM environment.",
		Issues: []int{4277},
	},
	"KVM_UNAVAILABLE": {
		Regexp: re(`invalid argument: could not find capabilities for domaintype=kvm`),
		Advice: "Your host does not support KVM virtualization. Ensure that qemu-kvm is installed, and run 'virt-host-validate' to debug the problem",
		URL:    "http://mikko.repolainen.fi/documents/virtualization-with-kvm",
		Issues: []int{2991},
	},
	"KVM_CONNECTION_ERROR": {
		Regexp: re(`error connecting to libvirt socket`),
		Advice: "Have you set up libvirt correctly?",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver",
	},
	"DRIVER_CRASHED": {
		Regexp: re(`Error attempting to get plugin server address for RPC`),
		Advice: "The VM driver exited with an error, and may be corrupt. Run 'minikube start' with --alsologtostderr -v=8 to see the error",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md",
	},
	"DRIVER_EXITED": {
		Regexp: re(`Unable to start VM: create: creating: exit status 1`),
		Advice: "Re-run 'minikube start' with --alsologtostderr -v=8 to see the VM driver error message",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#troubleshooting",
	},
	"VM_BOOT_FAILED_HYPERV_ENABLED": {
		Regexp: re(`VirtualBox won't boot a 64bits VM when Hyper-V is activated`),
		Advice: "Disable Hyper-V when you want to run VirtualBox to boot the VM",
		Issues: []int{4051},
	},
	"HYPERV_NO_VSWITCH": {
		Regexp: re(`no External vswitch found. A valid vswitch must be available for this command to run.`),
		Advice: "Configure an external network switch following the official documentation, then add `--hyperv-virtual-switch=<switch-name>` to `minikube start`",
		URL:    "https://docs.docker.com/machine/drivers/hyper-v/",
	},
	"HYPERV_POWERSHELL_NOT_FOUND": {
		Regexp: re(`Powershell was not found in the path`),
		Advice: "To start minikube with HyperV Powershell must be in your PATH`",
		URL:    "https://docs.docker.com/machine/drivers/hyper-v/",
	},

	"HOST_CIDR_CONFLICT": {
		Regexp: re(`host-only cidr conflicts with the network address of a host interface`),
		Advice: "Specify an alternate --host-only-cidr value, such as 172.16.0.1/24",
		Issues: []int{3594},
	},
	"OOM_KILL_SSH": {
		Regexp: re(`Process exited with status 137 from signal KILL`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
	"OOM_KILL_SCP": {
		Regexp: re(`An existing connection was forcibly closed by the remote host`),
		Advice: "Disable dynamic memory in your VM manager, or pass in a larger --memory value",
		Issues: []int{1766},
	},
}

// proxyDoc is the URL to proxy documentation
const proxyDoc = "https://github.com/kubernetes/minikube/blob/master/docs/http_proxy.md"

// netProblems are network related problems.
var netProblems = map[string]match{
	"GCR_UNAVAILABLE": {
		Regexp: re(`gcr.io.*443: connect: invalid argument`),
		Advice: "minikube is unable to access the Google Container Registry. You may need to configure it to use a HTTP proxy.",
		URL:    proxyDoc,
		Issues: []int{3860},
	},
	"DOWNLOAD_RESET_BY_PEER": {
		Regexp: re(`Error downloading .*connection reset by peer`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3909},
	},
	"DOWNLOAD_IO_TIMEOUT": {
		Regexp: re(`Error downloading .*timeout`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3846},
	},
	"DOWNLOAD_TLS_OVERSIZED": {
		Regexp: re(`tls: oversized record received with length`),
		Advice: "A firewall is interfering with minikube's ability to make outgoing HTTPS requests. You may need to change the value of the HTTPS_PROXY environment variable.",
		URL:    proxyDoc,
		Issues: []int{3857, 3759, 4252},
	},
	"ISO_DOWNLOAD_FAILED": {
		Regexp: re(`iso: failed to download`),
		Advice: "A firewall is likely blocking minikube from reaching the internet. You may need to configure minikube to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3922},
	},
	"PULL_TIMEOUT_EXCEEDED": {
		Regexp: re(`failed to pull image k8s.gcr.io.*Client.Timeout exceeded while awaiting headers`),
		Advice: "A firewall is blocking Docker within the minikube VM from reaching the internet. You may need to configure it to use a proxy.",
		URL:    proxyDoc,
		Issues: []int{3898},
	},
	"SSH_AUTH_FAILURE": {
		Regexp: re(`ssh: handshake failed: ssh: unable to authenticate.*, no supported methods remain`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3930},
	},
	"SSH_TCP_FAILURE": {
		Regexp: re(`dial tcp .*:22: connectex: A connection attempt failed because the connected party did not properly respond`),
		Advice: "Your host is failing to route packets to the minikube VM. If you have VPN software, try turning it off or configuring it so that it does not re-route traffic to the VM IP. If not, check your VM environment routing options.",
		Issues: []int{3388},
	},
	"INVALID_PROXY_HOSTNAME": {
		Regexp: re(`dial tcp: lookup.*: no such host`),
		Advice: "Verify that your HTTP_PROXY and HTTPS_PROXY environment variables are set correctly.",
		URL:    proxyDoc,
	},
}

// deployProblems are Kubernetes deployment problems.
var deployProblems = map[string]match{
	"DOCKER_UNAVAILABLE": {
		Regexp: re(`Error configuring auth on host: OS type not recognized`),
		Advice: "Docker inside the VM is unavailable. Try running 'minikube delete' to reset the VM.",
		Issues: []int{3952},
	},
	"INVALID_KUBERNETES_VERSION": {
		Regexp: re(`No Major.Minor.Patch elements found`),
		Advice: "Specify --kubernetes-version in v<major>.<minor.<build> form. example: 'v1.1.14'",
	},
	"KUBERNETES_VERSION_MISSING_V": {
		Regexp: re(`strconv.ParseUint: parsing "": invalid syntax`),
		Advice: "Check that your --kubernetes-version has a leading 'v'. For example: 'v1.1.14'",
	},
	"APISERVER_TIMEOUT": {
		Regexp: re(`wait: waiting for component=kube-apiserver: timed out waiting for the condition`),
		Advice: "Run 'minikube delete'. If the problem persists, check your proxy or firewall configuration",
		Issues: []int{4202, 3836, 4221},
	},
}

// osProblems are operating-system specific issues
var osProblems = map[string]match{
	"NON_C_DRIVE": {
		Regexp: re(`.iso: The system cannot find the path specified.`),
		Advice: "Run minikube from the C: drive.",
		Issues: []int{1574},
	},
	"SYSTEMCTL_EXIT_1": {
		Regexp: re(`Failed to enable container runtime: .*sudo systemctl start docker: exit status 1`),
		Advice: "If using the none driver, ensure that systemctl is installed",
		URL:    "https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md",
		Issues: []int{2704},
	},
}

// stateProblems are issues relating to local state
var stateProblems = map[string]match{
	"MACHINE_DOES_NOT_EXST": {
		Regexp: re(`Error getting state for host: machine does not exist`),
		Advice: "Run 'minikube delete' to delete the stale VM",
		Issues: []int{3864},
	},
	"IP_NOT_FOUND": {
		Regexp: re(`Error getting ssh host name for driver: IP not found`),
		Advice: "The minikube VM is offline. Please run 'minikube start' to start it again.",
		Issues: []int{3849, 3648},
	},
}
<|endoftext|>


<commit_before>// +build linux

/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package ipvs

import (
	"fmt"
	"net"
	"syscall"
	// TODO: replace syscall with golang.org/x/sys/unix?
	// The Go doc for syscall says:
	// NOTE: This package is locked down.
	// Code outside the standard Go repository should be migrated to use the corresponding package in the golang.org/x/sys repository.
	// That is also where updates required by new systems or versions should be applied.
	// See https://golang.org/s/go1.4-syscall for more information.

	"k8s.io/apimachinery/pkg/util/sets"

	"github.com/vishvananda/netlink"
)

type netlinkHandle struct {
	netlink.Handle
}

// NewNetLinkHandle will crate a new NetLinkHandle
func NewNetLinkHandle() NetLinkHandle {
	return &netlinkHandle{netlink.Handle{}}
}

// EnsureAddressBind checks if address is bound to the interface and, if not, binds it. If the address is already bound, return true.
func (h *netlinkHandle) EnsureAddressBind(address, devName string) (exist bool, err error) {
	dev, err := h.LinkByName(devName)
	if err != nil {
		return false, fmt.Errorf("error get interface: %s, err: %v", devName, err)
	}
	addr := net.ParseIP(address)
	if addr == nil {
		return false, fmt.Errorf("error parse ip address: %s", address)
	}
	if err := h.AddrAdd(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
		// "EEXIST" will be returned if the address is already bound to device
		if err == syscall.Errno(syscall.EEXIST) {
			return true, nil
		}
		return false, fmt.Errorf("error bind address: %s to interface: %s, err: %v", address, devName, err)
	}
	return false, nil
}

// UnbindAddress unbind address from the interface
func (h *netlinkHandle) UnbindAddress(address, devName string) error {
	dev, err := h.LinkByName(devName)
	if err != nil {
		return fmt.Errorf("error get interface: %s, err: %v", devName, err)
	}
	addr := net.ParseIP(address)
	if addr == nil {
		return fmt.Errorf("error parse ip address: %s", address)
	}
	if err := h.AddrDel(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
		return fmt.Errorf("error unbind address: %s from interface: %s, err: %v", address, devName, err)
	}
	return nil
}

// EnsureDummyDevice is part of interface
func (h *netlinkHandle) EnsureDummyDevice(devName string) (bool, error) {
	_, err := h.LinkByName(devName)
	if err == nil {
		// found dummy device
		return true, nil
	}
	dummy := &netlink.Dummy{
		LinkAttrs: netlink.LinkAttrs{Name: devName},
	}
	return false, h.LinkAdd(dummy)
}

// DeleteDummyDevice is part of interface.
func (h *netlinkHandle) DeleteDummyDevice(devName string) error {
	link, err := h.LinkByName(devName)
	if err != nil {
		return fmt.Errorf("error deleting a non-exist dummy device: %s", devName)
	}
	dummy, ok := link.(*netlink.Dummy)
	if !ok {
		return fmt.Errorf("expect dummy device, got device type: %s", link.Type())
	}
	return h.LinkDel(dummy)
}

// GetLocalAddresses lists all LOCAL type IP addresses from host based on filter device.
// If filter device is not specified, it's equivalent to exec:
// $ ip route show table local type local proto kernel
// 10.0.0.1 dev kube-ipvs0  scope host  src 10.0.0.1
// 10.0.0.10 dev kube-ipvs0  scope host  src 10.0.0.10
// 10.0.0.252 dev kube-ipvs0  scope host  src 10.0.0.252
// 100.106.89.164 dev eth0  scope host  src 100.106.89.164
// 127.0.0.0/8 dev lo  scope host  src 127.0.0.1
// 127.0.0.1 dev lo  scope host  src 127.0.0.1
// 172.17.0.1 dev docker0  scope host  src 172.17.0.1
// 192.168.122.1 dev virbr0  scope host  src 192.168.122.1
// Then cut the unique src IP fields,
// --> result set: [10.0.0.1, 10.0.0.10, 10.0.0.252, 100.106.89.164, 127.0.0.1, 192.168.122.1]

// If filter device is specified, it's equivalent to exec:
// $ ip route show table local type local proto kernel dev kube-ipvs0
// 10.0.0.1  scope host  src 10.0.0.1
// 10.0.0.10  scope host  src 10.0.0.10
// Then cut the unique src IP fields,
// --> result set: [10.0.0.1, 10.0.0.10]
func (h *netlinkHandle) GetLocalAddresses(filterDev string) (sets.String, error) {
	linkIndex := -1
	if len(filterDev) != 0 {
		link, err := h.LinkByName(filterDev)
		if err != nil {
			return nil, fmt.Errorf("error get filter device %s, err: %v", filterDev, err)
		}
		linkIndex = link.Attrs().Index
	}

	routeFilter := &netlink.Route{
		Table:    syscall.RT_TABLE_LOCAL,
		Type:     syscall.RTN_LOCAL,
		Protocol: syscall.RTPROT_KERNEL,
	}
	filterMask := netlink.RT_FILTER_TABLE | netlink.RT_FILTER_TYPE | netlink.RT_FILTER_PROTOCOL

	// find filter device
	if linkIndex != -1 {
		routeFilter.LinkIndex = linkIndex
		filterMask |= netlink.RT_FILTER_OIF
	}

	routes, err := h.RouteListFiltered(netlink.FAMILY_ALL, routeFilter, filterMask)
	if err != nil {
		return nil, fmt.Errorf("error list route table, err: %v", err)
	}
	res := sets.NewString()
	for _, route := range routes {
		if route.Src != nil {
			res.Insert(route.Src.String())
		}
	}
	return res, nil
}
<commit_msg>replace syscall with sys/unix pkg<commit_after>// +build linux

/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package ipvs

import (
	"fmt"
	"net"

	"k8s.io/apimachinery/pkg/util/sets"

	"github.com/vishvananda/netlink"
	"golang.org/x/sys/unix"
)

type netlinkHandle struct {
	netlink.Handle
}

// NewNetLinkHandle will crate a new NetLinkHandle
func NewNetLinkHandle() NetLinkHandle {
	return &netlinkHandle{netlink.Handle{}}
}

// EnsureAddressBind checks if address is bound to the interface and, if not, binds it. If the address is already bound, return true.
func (h *netlinkHandle) EnsureAddressBind(address, devName string) (exist bool, err error) {
	dev, err := h.LinkByName(devName)
	if err != nil {
		return false, fmt.Errorf("error get interface: %s, err: %v", devName, err)
	}
	addr := net.ParseIP(address)
	if addr == nil {
		return false, fmt.Errorf("error parse ip address: %s", address)
	}
	if err := h.AddrAdd(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
		// "EEXIST" will be returned if the address is already bound to device
		if err == unix.EEXIST {
			return true, nil
		}
		return false, fmt.Errorf("error bind address: %s to interface: %s, err: %v", address, devName, err)
	}
	return false, nil
}

// UnbindAddress unbind address from the interface
func (h *netlinkHandle) UnbindAddress(address, devName string) error {
	dev, err := h.LinkByName(devName)
	if err != nil {
		return fmt.Errorf("error get interface: %s, err: %v", devName, err)
	}
	addr := net.ParseIP(address)
	if addr == nil {
		return fmt.Errorf("error parse ip address: %s", address)
	}
	if err := h.AddrDel(dev, &netlink.Addr{IPNet: netlink.NewIPNet(addr)}); err != nil {
		return fmt.Errorf("error unbind address: %s from interface: %s, err: %v", address, devName, err)
	}
	return nil
}

// EnsureDummyDevice is part of interface
func (h *netlinkHandle) EnsureDummyDevice(devName string) (bool, error) {
	_, err := h.LinkByName(devName)
	if err == nil {
		// found dummy device
		return true, nil
	}
	dummy := &netlink.Dummy{
		LinkAttrs: netlink.LinkAttrs{Name: devName},
	}
	return false, h.LinkAdd(dummy)
}

// DeleteDummyDevice is part of interface.
func (h *netlinkHandle) DeleteDummyDevice(devName string) error {
	link, err := h.LinkByName(devName)
	if err != nil {
		return fmt.Errorf("error deleting a non-exist dummy device: %s", devName)
	}
	dummy, ok := link.(*netlink.Dummy)
	if !ok {
		return fmt.Errorf("expect dummy device, got device type: %s", link.Type())
	}
	return h.LinkDel(dummy)
}

// GetLocalAddresses lists all LOCAL type IP addresses from host based on filter device.
// If filter device is not specified, it's equivalent to exec:
// $ ip route show table local type local proto kernel
// 10.0.0.1 dev kube-ipvs0  scope host  src 10.0.0.1
// 10.0.0.10 dev kube-ipvs0  scope host  src 10.0.0.10
// 10.0.0.252 dev kube-ipvs0  scope host  src 10.0.0.252
// 100.106.89.164 dev eth0  scope host  src 100.106.89.164
// 127.0.0.0/8 dev lo  scope host  src 127.0.0.1
// 127.0.0.1 dev lo  scope host  src 127.0.0.1
// 172.17.0.1 dev docker0  scope host  src 172.17.0.1
// 192.168.122.1 dev virbr0  scope host  src 192.168.122.1
// Then cut the unique src IP fields,
// --> result set: [10.0.0.1, 10.0.0.10, 10.0.0.252, 100.106.89.164, 127.0.0.1, 192.168.122.1]

// If filter device is specified, it's equivalent to exec:
// $ ip route show table local type local proto kernel dev kube-ipvs0
// 10.0.0.1  scope host  src 10.0.0.1
// 10.0.0.10  scope host  src 10.0.0.10
// Then cut the unique src IP fields,
// --> result set: [10.0.0.1, 10.0.0.10]
func (h *netlinkHandle) GetLocalAddresses(filterDev string) (sets.String, error) {
	linkIndex := -1
	if len(filterDev) != 0 {
		link, err := h.LinkByName(filterDev)
		if err != nil {
			return nil, fmt.Errorf("error get filter device %s, err: %v", filterDev, err)
		}
		linkIndex = link.Attrs().Index
	}

	routeFilter := &netlink.Route{
		Table:    unix.RT_TABLE_LOCAL,
		Type:     unix.RTN_LOCAL,
		Protocol: unix.RTPROT_KERNEL,
	}
	filterMask := netlink.RT_FILTER_TABLE | netlink.RT_FILTER_TYPE | netlink.RT_FILTER_PROTOCOL

	// find filter device
	if linkIndex != -1 {
		routeFilter.LinkIndex = linkIndex
		filterMask |= netlink.RT_FILTER_OIF
	}

	routes, err := h.RouteListFiltered(netlink.FAMILY_ALL, routeFilter, filterMask)
	if err != nil {
		return nil, fmt.Errorf("error list route table, err: %v", err)
	}
	res := sets.NewString()
	for _, route := range routes {
		if route.Src != nil {
			res.Insert(route.Src.String())
		}
	}
	return res, nil
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/slinga/server/controller"
	"github.com/Aptomi/aptomi/pkg/slinga/object/codec"
	"github.com/julienschmidt/httprouter"
	"io/ioutil"
	"net/http"
)

type PolicyAPI struct {
	ctl   controller.PolicyController
	codec codec.MarshalUnmarshaler
}

func (h *PolicyAPI) handleGetPolicy(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	rev, key, ns := p.ByName("rev"), p.ByName("key"), p.ByName("ns")

	fmt.Printf("[handleGetPolicy] rev: %s, key: %s, ns: %s\n", rev, key, ns)

	if len(rev) == 0 {
		// todo(slukjanov): fail better
		panic("Revision should be specified (0 for current)")
	}

	if (len(key) == 0) && (len(ns) == 0) {
		// get full policy from specific revision
	}

	if (len(key) > 0) && (len(ns) > 0) {
		// todo(slukjanov): unreachable, better failing
		panic("Only one of key or namespace could specified")
	}

	if len(key) != 0 {
		// get by key from specific revision
	}

	if len(ns) != 0 {
		// get all by ns from specific revision
	}
}

func (h *PolicyAPI) handlePolicyUpdate(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		panic(fmt.Sprintf("Error while reading bytes from request Body: %s", err))
	}

	// todo remove bad logging
	fmt.Println(string(body))

	objects, err := h.codec.UnmarshalOneOrMany(body)
	if err != nil {
		panic(fmt.Sprintf("Error unmarshaling policy update request: %s", err))
	}
	policy, err := h.ctl.UpdatePolicy(objects)
	if err != nil {
		panic(fmt.Sprintf("Error while updating policy: %s", err))
	}

	// todo remove bad logging
	fmt.Println(policy)

	// temp send back received data (to impl some table output on client side)
	_, err = fmt.Fprint(w, string(body))
	if err != nil {
		panic(fmt.Sprintf("Error while writing response bytes: %s", err))
	}
}

func Serve(router *httprouter.Router, ctl controller.PolicyController, cod codec.MarshalUnmarshaler) {
	h := PolicyAPI{ctl, cod}

	router.GET("/api/v1/revision/:rev/policy", h.handleGetPolicy)               // get full policy from specific revision
	router.GET("/api/v1/revision/:rev/policy/key/:key", h.handleGetPolicy)      // get by key from specific revision
	router.GET("/api/v1/revision/:rev/policy/namespace/:ns", h.handleGetPolicy) // get policy for namespace from specific revision

	router.POST("/api/v1/revision", h.handlePolicyUpdate)
}
<commit_msg>Add important todo<commit_after>package api

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/slinga/object/codec"
	"github.com/Aptomi/aptomi/pkg/slinga/server/controller"
	"github.com/julienschmidt/httprouter"
	"io/ioutil"
	"net/http"
)

type PolicyAPI struct {
	ctl   controller.PolicyController
	codec codec.MarshalUnmarshaler
}

func (h *PolicyAPI) handleGetPolicy(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	rev, key, ns := p.ByName("rev"), p.ByName("key"), p.ByName("ns")

	fmt.Printf("[handleGetPolicy] rev: %s, key: %s, ns: %s\n", rev, key, ns)

	if len(rev) == 0 {
		// todo(slukjanov): fail better
		panic("Revision should be specified (0 for current)")
	}

	if (len(key) == 0) && (len(ns) == 0) {
		// get full policy from specific revision
	}

	if (len(key) > 0) && (len(ns) > 0) {
		// todo(slukjanov): unreachable, better failing
		panic("Only one of key or namespace could specified")
	}

	if len(key) != 0 {
		// get by key from specific revision
	}

	if len(ns) != 0 {
		// get all by ns from specific revision
	}
}

func (h *PolicyAPI) handlePolicyUpdate(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		panic(fmt.Sprintf("Error while reading bytes from request Body: %s", err))
	}

	// todo remove bad logging
	fmt.Println(string(body))

	objects, err := h.codec.UnmarshalOneOrMany(body)
	if err != nil {
		panic(fmt.Sprintf("Error unmarshaling policy update request: %s", err))
	}
	policy, err := h.ctl.UpdatePolicy(objects)
	if err != nil {
		panic(fmt.Sprintf("Error while updating policy: %s", err))
	}

	// todo remove bad logging
	fmt.Println(policy)

	// temp send back received data (to impl some table output on client side)
	// todo send full updated policy
	_, err = fmt.Fprint(w, string(body))
	if err != nil {
		panic(fmt.Sprintf("Error while writing response bytes: %s", err))
	}
}

func Serve(router *httprouter.Router, ctl controller.PolicyController, cod codec.MarshalUnmarshaler) {
	h := PolicyAPI{ctl, cod}

	router.GET("/api/v1/revision/:rev/policy", h.handleGetPolicy)               // get full policy from specific revision
	router.GET("/api/v1/revision/:rev/policy/key/:key", h.handleGetPolicy)      // get by key from specific revision
	router.GET("/api/v1/revision/:rev/policy/namespace/:ns", h.handleGetPolicy) // get policy for namespace from specific revision

	router.POST("/api/v1/revision", h.handlePolicyUpdate)
}
<|endoftext|>


<commit_before>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package snapshot

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

func createBlockDevices(buildDir string) error {
	// Grab all the block device pseudo-directories from /sys/block symlinks
	// (excluding loopback devices) and inject them into our build filesystem
	// with all but the circular symlink'd subsystem directories
	devLinks, err := ioutil.ReadDir("/sys/block")
	if err != nil {
		return err
	}
	for _, devLink := range devLinks {
		dname := devLink.Name()
		if strings.HasPrefix(dname, "loop") {
			continue
		}
		devPath := filepath.Join("/sys/block", dname)
		trace("processing block device %q\n", devPath)

		// from the sysfs layout, we know this is always a symlink
		linkContentPath, err := os.Readlink(devPath)
		if err != nil {
			return err
		}
		trace("link target for block device %q is %q\n", devPath, linkContentPath)

		// Create a symlink in our build filesystem that is a directory
		// pointing to the actual device bus path where the block device's
		// information directory resides
		linkPath := filepath.Join(buildDir, "sys/block", dname)
		linkTargetPath := filepath.Join(
			buildDir,
			"sys/block",
			strings.TrimPrefix(linkContentPath, string(os.PathSeparator)),
		)
		trace("creating device directory %s\n", linkTargetPath)
		if err = os.MkdirAll(linkTargetPath, os.ModePerm); err != nil {
			return err
		}

		trace("linking device directory %s to %s\n", linkPath, linkContentPath)
		// Make sure the link target is a relative path!
		// if we use absolute path, the link target will be an absolute path starting
		// with buildDir, hence the snapshot will contain broken link.
		// Otherwise, the unpack directory will never have the same prefix of buildDir!
		if err = os.Symlink(linkContentPath, linkPath); err != nil {
			return err
		}
		// Now read the source block device directory and populate the
		// newly-created target link in the build directory with the
		// appropriate block device pseudofiles
		srcDeviceDir := filepath.Join(
			"/sys/block",
			strings.TrimPrefix(linkContentPath, string(os.PathSeparator)),
		)
		trace("creating device directory %q from %q\n", linkTargetPath, srcDeviceDir)
		if err = createBlockDeviceDir(linkTargetPath, srcDeviceDir); err != nil {
			return err
		}
	}
	return nil
}

func createBlockDeviceDir(buildDeviceDir string, srcDeviceDir string) error {
	// Populate the supplied directory (in our build filesystem) with all the
	// appropriate information pseudofile contents for the block device.
	devName := filepath.Base(srcDeviceDir)
	devFiles, err := ioutil.ReadDir(srcDeviceDir)
	if err != nil {
		return err
	}
	for _, f := range devFiles {
		fname := f.Name()
		fp := filepath.Join(srcDeviceDir, fname)
		fi, err := os.Lstat(fp)
		if err != nil {
			return err
		}
		if fi.Mode()&os.ModeSymlink != 0 {
			// Ignore any symlinks in the deviceDir since they simply point to
			// either self-referential links or information we aren't
			// interested in like "subsystem"
			continue
		} else if fi.IsDir() {
			if strings.HasPrefix(fname, devName) {
				// We're interested in are the directories that begin with the
				// block device name. These are directories with information
				// about the partitions on the device
				buildPartitionDir := filepath.Join(
					buildDeviceDir, fname,
				)
				srcPartitionDir := filepath.Join(
					srcDeviceDir, fname,
				)
				trace("creating partition directory %s\n", buildPartitionDir)
				err = os.MkdirAll(buildPartitionDir, os.ModePerm)
				if err != nil {
					return err
				}
				err = createPartitionDir(buildPartitionDir, srcPartitionDir)
				if err != nil {
					return err
				}
			}
		} else if fi.Mode().IsRegular() {
			// Regular files in the block device directory are both regular and
			// pseudofiles containing information such as the size (in sectors)
			// and whether the device is read-only
			buf, err := ioutil.ReadFile(fp)
			if err != nil {
				return err
			}
			targetPath := filepath.Join(buildDeviceDir, fname)
			trace("creating %s\n", targetPath)
			f, err := os.Create(targetPath)
			if err != nil {
				return err
			}
			if _, err = f.Write(buf); err != nil {
				return err
			}
			f.Close()
		}
	}
	// There is a special file $DEVICE_DIR/queue/rotational that, for some hard
	// drives, contains a 1 or 0 indicating whether the device is a spinning
	// disk or not
	srcQueueDir := filepath.Join(
		srcDeviceDir,
		"queue",
	)
	buildQueueDir := filepath.Join(
		buildDeviceDir,
		"queue",
	)
	err = os.MkdirAll(buildQueueDir, os.ModePerm)
	if err != nil {
		return err
	}
	fp := filepath.Join(srcQueueDir, "rotational")
	buf, err := ioutil.ReadFile(fp)
	if err != nil {
		return err
	}
	targetPath := filepath.Join(buildQueueDir, "rotational")
	trace("creating %s\n", targetPath)
	f, err := os.Create(targetPath)
	if err != nil {
		return err
	}
	if _, err = f.Write(buf); err != nil {
		return err
	}
	f.Close()

	return nil
}

func createPartitionDir(buildPartitionDir string, srcPartitionDir string) error {
	// Populate the supplied directory (in our build filesystem) with all the
	// appropriate information pseudofile contents for the partition.
	partFiles, err := ioutil.ReadDir(srcPartitionDir)
	if err != nil {
		return err
	}
	for _, f := range partFiles {
		fname := f.Name()
		fp := filepath.Join(srcPartitionDir, fname)
		fi, err := os.Lstat(fp)
		if err != nil {
			return err
		}
		if fi.Mode()&os.ModeSymlink != 0 {
			// Ignore any symlinks in the partition directory since they simply
			// point to information we aren't interested in like "subsystem"
			continue
		} else if fi.IsDir() {
			// The subdirectories in the partition directory are not
			// interesting for us. They have information about power events and
			// traces
			continue
		} else if fi.Mode().IsRegular() {
			// Regular files in the block device directory are both regular and
			// pseudofiles containing information such as the size (in sectors)
			// and whether the device is read-only
			buf, err := ioutil.ReadFile(fp)
			if err != nil {
				return err
			}
			targetPath := filepath.Join(buildPartitionDir, fname)
			trace("creating %s\n", targetPath)
			f, err := os.Create(targetPath)
			if err != nil {
				return err
			}
			if _, err = f.Write(buf); err != nil {
				return err
			}
			f.Close()
		}
	}
	return nil
}
<commit_msg>snapshot: clonetree: handle read error<commit_after>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package snapshot

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

func createBlockDevices(buildDir string) error {
	// Grab all the block device pseudo-directories from /sys/block symlinks
	// (excluding loopback devices) and inject them into our build filesystem
	// with all but the circular symlink'd subsystem directories
	devLinks, err := ioutil.ReadDir("/sys/block")
	if err != nil {
		return err
	}
	for _, devLink := range devLinks {
		dname := devLink.Name()
		if strings.HasPrefix(dname, "loop") {
			continue
		}
		devPath := filepath.Join("/sys/block", dname)
		trace("processing block device %q\n", devPath)

		// from the sysfs layout, we know this is always a symlink
		linkContentPath, err := os.Readlink(devPath)
		if err != nil {
			return err
		}
		trace("link target for block device %q is %q\n", devPath, linkContentPath)

		// Create a symlink in our build filesystem that is a directory
		// pointing to the actual device bus path where the block device's
		// information directory resides
		linkPath := filepath.Join(buildDir, "sys/block", dname)
		linkTargetPath := filepath.Join(
			buildDir,
			"sys/block",
			strings.TrimPrefix(linkContentPath, string(os.PathSeparator)),
		)
		trace("creating device directory %s\n", linkTargetPath)
		if err = os.MkdirAll(linkTargetPath, os.ModePerm); err != nil {
			return err
		}

		trace("linking device directory %s to %s\n", linkPath, linkContentPath)
		// Make sure the link target is a relative path!
		// if we use absolute path, the link target will be an absolute path starting
		// with buildDir, hence the snapshot will contain broken link.
		// Otherwise, the unpack directory will never have the same prefix of buildDir!
		if err = os.Symlink(linkContentPath, linkPath); err != nil {
			return err
		}
		// Now read the source block device directory and populate the
		// newly-created target link in the build directory with the
		// appropriate block device pseudofiles
		srcDeviceDir := filepath.Join(
			"/sys/block",
			strings.TrimPrefix(linkContentPath, string(os.PathSeparator)),
		)
		trace("creating device directory %q from %q\n", linkTargetPath, srcDeviceDir)
		if err = createBlockDeviceDir(linkTargetPath, srcDeviceDir); err != nil {
			return err
		}
	}
	return nil
}

func createBlockDeviceDir(buildDeviceDir string, srcDeviceDir string) error {
	// Populate the supplied directory (in our build filesystem) with all the
	// appropriate information pseudofile contents for the block device.
	devName := filepath.Base(srcDeviceDir)
	devFiles, err := ioutil.ReadDir(srcDeviceDir)
	if err != nil {
		return err
	}
	for _, f := range devFiles {
		fname := f.Name()
		fp := filepath.Join(srcDeviceDir, fname)
		fi, err := os.Lstat(fp)
		if err != nil {
			return err
		}
		if fi.Mode()&os.ModeSymlink != 0 {
			// Ignore any symlinks in the deviceDir since they simply point to
			// either self-referential links or information we aren't
			// interested in like "subsystem"
			continue
		} else if fi.IsDir() {
			if strings.HasPrefix(fname, devName) {
				// We're interested in are the directories that begin with the
				// block device name. These are directories with information
				// about the partitions on the device
				buildPartitionDir := filepath.Join(
					buildDeviceDir, fname,
				)
				srcPartitionDir := filepath.Join(
					srcDeviceDir, fname,
				)
				trace("creating partition directory %s\n", buildPartitionDir)
				err = os.MkdirAll(buildPartitionDir, os.ModePerm)
				if err != nil {
					return err
				}
				err = createPartitionDir(buildPartitionDir, srcPartitionDir)
				if err != nil {
					return err
				}
			}
		} else if fi.Mode().IsRegular() {
			// Regular files in the block device directory are both regular and
			// pseudofiles containing information such as the size (in sectors)
			// and whether the device is read-only
			buf, err := ioutil.ReadFile(fp)
			if err != nil {
				if os.IsPermission(err) {
					// example: /sys/devices/virtual/block/zram0/compact is 0400
					trace("permission denied reading %q - skipped\n", fp)
					continue
				}
				return err
			}
			targetPath := filepath.Join(buildDeviceDir, fname)
			trace("creating %s\n", targetPath)
			f, err := os.Create(targetPath)
			if err != nil {
				return err
			}
			if _, err = f.Write(buf); err != nil {
				return err
			}
			f.Close()
		}
	}
	// There is a special file $DEVICE_DIR/queue/rotational that, for some hard
	// drives, contains a 1 or 0 indicating whether the device is a spinning
	// disk or not
	srcQueueDir := filepath.Join(
		srcDeviceDir,
		"queue",
	)
	buildQueueDir := filepath.Join(
		buildDeviceDir,
		"queue",
	)
	err = os.MkdirAll(buildQueueDir, os.ModePerm)
	if err != nil {
		return err
	}
	fp := filepath.Join(srcQueueDir, "rotational")
	buf, err := ioutil.ReadFile(fp)
	if err != nil {
		return err
	}
	targetPath := filepath.Join(buildQueueDir, "rotational")
	trace("creating %s\n", targetPath)
	f, err := os.Create(targetPath)
	if err != nil {
		return err
	}
	if _, err = f.Write(buf); err != nil {
		return err
	}
	f.Close()

	return nil
}

func createPartitionDir(buildPartitionDir string, srcPartitionDir string) error {
	// Populate the supplied directory (in our build filesystem) with all the
	// appropriate information pseudofile contents for the partition.
	partFiles, err := ioutil.ReadDir(srcPartitionDir)
	if err != nil {
		return err
	}
	for _, f := range partFiles {
		fname := f.Name()
		fp := filepath.Join(srcPartitionDir, fname)
		fi, err := os.Lstat(fp)
		if err != nil {
			return err
		}
		if fi.Mode()&os.ModeSymlink != 0 {
			// Ignore any symlinks in the partition directory since they simply
			// point to information we aren't interested in like "subsystem"
			continue
		} else if fi.IsDir() {
			// The subdirectories in the partition directory are not
			// interesting for us. They have information about power events and
			// traces
			continue
		} else if fi.Mode().IsRegular() {
			// Regular files in the block device directory are both regular and
			// pseudofiles containing information such as the size (in sectors)
			// and whether the device is read-only
			buf, err := ioutil.ReadFile(fp)
			if err != nil {
				return err
			}
			targetPath := filepath.Join(buildPartitionDir, fname)
			trace("creating %s\n", targetPath)
			f, err := os.Create(targetPath)
			if err != nil {
				return err
			}
			if _, err = f.Write(buf); err != nil {
				return err
			}
			f.Close()
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Camlistore 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 camtypes

import (
	"camlistore.org/pkg/blob"

	"go4.org/types"
)

// Discovery is the JSON response for discovery requests.
type Discovery struct {
	BlobRoot     string `json:"blobRoot"`
	JSONSignRoot string `json:"jsonSignRoot"`
	HelpRoot     string `json:"helpRoot"`
	ImporterRoot string `json:"importerRoot"`
	SearchRoot   string `json:"searchRoot"`
	StatusRoot   string `json:"statusRoot"`
	ShareRoot    string `json:"shareRoot"`

	OwnerName string `json:"ownerName"` // Name of the owner.
	UserName  string `json:"userName"`  // Name of the user.

	// StorageGeneration is the UUID for the storage generation.
	StorageGeneration string `json:"storageGeneration,omitempty"`
	// StorageGenerationError is the error that occurred on generating the storage, if any.
	StorageGenerationError string `json:"storageGenerationError,omitempty"`
	// StorageInitTime is the initialization time of the storage.
	StorageInitTime types.Time3339 `json:"storageInitTime,omitempty"`

	ThumbVersion string `json:"thumbVersion"` // Thumbnailing version.

	// AuthToken is an auth.OpAll token used by the web UI and the WebSocket.
	// It is randomly generated the first time discovery is served.
	AuthToken string `json:"authToken"`

	// SyncHandlers lists discovery information about the available sync handlers.
	SyncHandlers []SyncHandlerDiscovery `json:"syncHanlders,omitempty"`
	// Signing contains discovery information for signing.
	Signing *SignDiscovery `json:"signing,omitempty"`
	// UIDiscovery contains discovery information for the UI.
	*UIDiscovery
}

// SignDiscovery contains discovery information for jsonsign.
// It is part of the server's JSON response for discovery requests.
type SignDiscovery struct {
	// PublicKey is the path to the public signing key.
	PublicKey string `json:"publicKey,omitempty"`
	// PublicKeyBlobRef is the blob.Ref for the public key.
	PublicKeyBlobRef blob.Ref `json:"publicKeyBlobRef,omitempty"`
	// PublicKeyID is the ID of the public key.
	PublicKeyID string `json:"publicKeyId"`
	// SignHandler is the URL path prefix to the signing handler.
	SignHandler string `json:"signHandler"`
	// VerifyHandler it the URL path prefix to the signature verification handler.
	VerifyHandler string `json:"verifyHandler"`
}

// SyncHandlerDiscovery contains discovery information about a sync handler.
// It is part of the JSON response to discovery requests.
type SyncHandlerDiscovery struct {
	// From is the source of the sync handler.
	From string `json:"from"`
	// To is the destination of the sync handler.
	To string `json:"to"`
	// ToIndex is true if the sync is from a blob storage to an index.
	ToIndex bool `json:"toIndex"`
}

// UIDiscovery contains discovery information for the user interface.
// It is part of the JSON response to discovery requests.
type UIDiscovery struct {
	// UIRoot is the URL prefix path to the UI handler.
	UIRoot string `json:"uiRoot"`
	// UploadHelper is the path to the upload helper.
	UploadHelper string `json:"uploadHelper"`
	// DirectoryHelper is the path to the directory helper.
	DirectoryHelper string `json:"directoryHelper"`
	// DownloaderHelper is the path to the downloader helper.
	DownloadHelper string `json:"downloadHelper"`
	// PublishRoots lists discovery information for all publishing roots,
	// mapped by the respective root name.
	PublishRoots map[string]*PublishRootDiscovery `json:"publishRoots"`
	// MapClustering defines whether to cluster position markers on the map aspect.
	MapClustering bool `json:"mapClustering"`
}

// PublishRootDiscovery contains discovery information for the publish roots.
type PublishRootDiscovery struct {
	Name string `json:"name"`
	// Prefix lists prefixes belonging to the publishing root.
	Prefix []string `json:"prefix"`
	// CurrentPermanode is the permanode associated with the publishing root.
	CurrentPermanode blob.Ref `json:"currentPermanode"`
}
<commit_msg>pkg/types/camtypes: fix a typo<commit_after>/*
Copyright 2015 The Camlistore 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 camtypes

import (
	"camlistore.org/pkg/blob"

	"go4.org/types"
)

// Discovery is the JSON response for discovery requests.
type Discovery struct {
	BlobRoot     string `json:"blobRoot"`
	JSONSignRoot string `json:"jsonSignRoot"`
	HelpRoot     string `json:"helpRoot"`
	ImporterRoot string `json:"importerRoot"`
	SearchRoot   string `json:"searchRoot"`
	StatusRoot   string `json:"statusRoot"`
	ShareRoot    string `json:"shareRoot"`

	OwnerName string `json:"ownerName"` // Name of the owner.
	UserName  string `json:"userName"`  // Name of the user.

	// StorageGeneration is the UUID for the storage generation.
	StorageGeneration string `json:"storageGeneration,omitempty"`
	// StorageGenerationError is the error that occurred on generating the storage, if any.
	StorageGenerationError string `json:"storageGenerationError,omitempty"`
	// StorageInitTime is the initialization time of the storage.
	StorageInitTime types.Time3339 `json:"storageInitTime,omitempty"`

	ThumbVersion string `json:"thumbVersion"` // Thumbnailing version.

	// AuthToken is an auth.OpAll token used by the web UI and the WebSocket.
	// It is randomly generated the first time discovery is served.
	AuthToken string `json:"authToken"`

	// SyncHandlers lists discovery information about the available sync handlers.
	SyncHandlers []SyncHandlerDiscovery `json:"syncHandlers,omitempty"`
	// Signing contains discovery information for signing.
	Signing *SignDiscovery `json:"signing,omitempty"`
	// UIDiscovery contains discovery information for the UI.
	*UIDiscovery
}

// SignDiscovery contains discovery information for jsonsign.
// It is part of the server's JSON response for discovery requests.
type SignDiscovery struct {
	// PublicKey is the path to the public signing key.
	PublicKey string `json:"publicKey,omitempty"`
	// PublicKeyBlobRef is the blob.Ref for the public key.
	PublicKeyBlobRef blob.Ref `json:"publicKeyBlobRef,omitempty"`
	// PublicKeyID is the ID of the public key.
	PublicKeyID string `json:"publicKeyId"`
	// SignHandler is the URL path prefix to the signing handler.
	SignHandler string `json:"signHandler"`
	// VerifyHandler it the URL path prefix to the signature verification handler.
	VerifyHandler string `json:"verifyHandler"`
}

// SyncHandlerDiscovery contains discovery information about a sync handler.
// It is part of the JSON response to discovery requests.
type SyncHandlerDiscovery struct {
	// From is the source of the sync handler.
	From string `json:"from"`
	// To is the destination of the sync handler.
	To string `json:"to"`
	// ToIndex is true if the sync is from a blob storage to an index.
	ToIndex bool `json:"toIndex"`
}

// UIDiscovery contains discovery information for the user interface.
// It is part of the JSON response to discovery requests.
type UIDiscovery struct {
	// UIRoot is the URL prefix path to the UI handler.
	UIRoot string `json:"uiRoot"`
	// UploadHelper is the path to the upload helper.
	UploadHelper string `json:"uploadHelper"`
	// DirectoryHelper is the path to the directory helper.
	DirectoryHelper string `json:"directoryHelper"`
	// DownloaderHelper is the path to the downloader helper.
	DownloadHelper string `json:"downloadHelper"`
	// PublishRoots lists discovery information for all publishing roots,
	// mapped by the respective root name.
	PublishRoots map[string]*PublishRootDiscovery `json:"publishRoots"`
	// MapClustering defines whether to cluster position markers on the map aspect.
	MapClustering bool `json:"mapClustering"`
}

// PublishRootDiscovery contains discovery information for the publish roots.
type PublishRootDiscovery struct {
	Name string `json:"name"`
	// Prefix lists prefixes belonging to the publishing root.
	Prefix []string `json:"prefix"`
	// CurrentPermanode is the permanode associated with the publishing root.
	CurrentPermanode blob.Ref `json:"currentPermanode"`
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator 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 k8sutil

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/coreos/etcd-operator/pkg/spec"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/meta/metatypes"
	k8sv1api "k8s.io/kubernetes/pkg/api/v1"
)

const (
	shouldCheckpointAnnotation = "checkpointer.alpha.coreos.com/checkpoint" // = "true"
)

var (
	envPodIP = api.EnvVar{
		Name: "MY_POD_IP",
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				FieldPath: "status.podIP",
			},
		},
	}
)

func PodWithAddMemberInitContainer(p *api.Pod, endpoints []string, name string, peerURLs []string, cs *spec.ClusterSpec) *api.Pod {
	containerSpec := []api.Container{
		{
			Name:  "add-member",
			Image: MakeEtcdImage(cs.Version),
			Command: []string{
				"/bin/sh", "-c",
				fmt.Sprintf("ETCDCTL_API=3 etcdctl --endpoints=%s member add %s --peer-urls=%s", strings.Join(endpoints, ","), name, strings.Join(peerURLs, ",")),
			},
			Env: []api.EnvVar{envPodIP},
		},
	}
	b, err := json.Marshal(containerSpec)
	if err != nil {
		panic(err)
	}
	p.Annotations[k8sv1api.PodInitContainersAnnotationKey] = string(b)
	return p
}

func MakeSelfHostedEtcdPod(name string, initialCluster []string, clusterName, state, token string, cs *spec.ClusterSpec, owner metatypes.OwnerReference) *api.Pod {
	commands := fmt.Sprintf("/usr/local/bin/etcd --data-dir=%s --name=%s --initial-advertise-peer-urls=http://$(MY_POD_IP):2380 "+
		"--listen-peer-urls=http://$(MY_POD_IP):2380 --listen-client-urls=http://$(MY_POD_IP):2379 --advertise-client-urls=http://$(MY_POD_IP):2379 "+
		"--initial-cluster=%s --initial-cluster-state=%s",
		dataDir, name, strings.Join(initialCluster, ","), state)

	if state == "new" {
		commands = fmt.Sprintf("%s --initial-cluster-token=%s", commands, token)
	}

	c := etcdContainer(commands, cs.Version)
	c.Env = []api.EnvVar{envPodIP}
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"app":          "etcd",
				"etcd_node":    name,
				"etcd_cluster": clusterName,
			},
			Annotations: map[string]string{
				shouldCheckpointAnnotation: "true",
			},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{c},
			// Self-hosted etcd pod need to endure node restart.
			// If we set it to Never, the pod won't restart. If etcd won't come up, nor does other k8s API components.
			RestartPolicy: api.RestartPolicyAlways,
			SecurityContext: &api.PodSecurityContext{
				HostNetwork: true,
			},
			Volumes: []api.Volume{
				{Name: "etcd-data", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
			},
		},
	}

	SetEtcdVersion(pod, cs.Version)

	pod = PodWithAntiAffinity(pod, clusterName)

	if len(cs.NodeSelector) != 0 {
		pod = PodWithNodeSelector(pod, cs.NodeSelector)
	}
	addOwnerRefToObject(pod.GetObjectMeta(), owner)
	return pod
}
<commit_msg>self_hosted: init container add default apiVersion to handle regression in k8s v1.5<commit_after>// Copyright 2016 The etcd-operator 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 k8sutil

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/coreos/etcd-operator/pkg/spec"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/meta/metatypes"
	k8sv1api "k8s.io/kubernetes/pkg/api/v1"
)

const (
	shouldCheckpointAnnotation = "checkpointer.alpha.coreos.com/checkpoint" // = "true"
)

var (
	envPodIP = api.EnvVar{
		Name: "MY_POD_IP",
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "status.podIP",
			},
		},
	}
)

func PodWithAddMemberInitContainer(p *api.Pod, endpoints []string, name string, peerURLs []string, cs *spec.ClusterSpec) *api.Pod {
	containerSpec := []api.Container{
		{
			Name:  "add-member",
			Image: MakeEtcdImage(cs.Version),
			Command: []string{
				"/bin/sh", "-c",
				fmt.Sprintf("ETCDCTL_API=3 etcdctl --endpoints=%s member add %s --peer-urls=%s", strings.Join(endpoints, ","), name, strings.Join(peerURLs, ",")),
			},
			Env: []api.EnvVar{envPodIP},
		},
	}
	b, err := json.Marshal(containerSpec)
	if err != nil {
		panic(err)
	}
	p.Annotations[k8sv1api.PodInitContainersAnnotationKey] = string(b)
	return p
}

func MakeSelfHostedEtcdPod(name string, initialCluster []string, clusterName, state, token string, cs *spec.ClusterSpec, owner metatypes.OwnerReference) *api.Pod {
	commands := fmt.Sprintf("/usr/local/bin/etcd --data-dir=%s --name=%s --initial-advertise-peer-urls=http://$(MY_POD_IP):2380 "+
		"--listen-peer-urls=http://$(MY_POD_IP):2380 --listen-client-urls=http://$(MY_POD_IP):2379 --advertise-client-urls=http://$(MY_POD_IP):2379 "+
		"--initial-cluster=%s --initial-cluster-state=%s",
		dataDir, name, strings.Join(initialCluster, ","), state)

	if state == "new" {
		commands = fmt.Sprintf("%s --initial-cluster-token=%s", commands, token)
	}

	c := etcdContainer(commands, cs.Version)
	c.Env = []api.EnvVar{envPodIP}
	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"app":          "etcd",
				"etcd_node":    name,
				"etcd_cluster": clusterName,
			},
			Annotations: map[string]string{
				shouldCheckpointAnnotation: "true",
			},
		},
		Spec: api.PodSpec{
			Containers: []api.Container{c},
			// Self-hosted etcd pod need to endure node restart.
			// If we set it to Never, the pod won't restart. If etcd won't come up, nor does other k8s API components.
			RestartPolicy: api.RestartPolicyAlways,
			SecurityContext: &api.PodSecurityContext{
				HostNetwork: true,
			},
			Volumes: []api.Volume{
				{Name: "etcd-data", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
			},
		},
	}

	SetEtcdVersion(pod, cs.Version)

	pod = PodWithAntiAffinity(pod, clusterName)

	if len(cs.NodeSelector) != 0 {
		pod = PodWithNodeSelector(pod, cs.NodeSelector)
	}
	addOwnerRefToObject(pod.GetObjectMeta(), owner)
	return pod
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/longears/sortpixels/myimage"
	"github.com/longears/sortpixels/utils"
	"os"
	"runtime"
	"runtime/debug"
	"strings"
)

// How many times to repeat the vertical & horizontal sort step
const N_SORTS = 6

// How many threads to run in parallel
var THREADPOOL_SIZE int

func init() {
	THREADPOOL_SIZE = runtime.NumCPU()
	runtime.GOMAXPROCS(runtime.NumCPU())
}

//================================================================================
// IMAGE MODIFICATION ALGORITHMS

// Read the image from the path inFn,
// sort the pixels,
// and save the result to the path outFn.
// Return an error if the input file is not decodable as an image.
func sortPixels(inFn, outFn string) {
	myImage := myimage.MakeMyImageFromPath(inFn)

	fmt.Println("  sorting")
	for ii := 0; ii < N_SORTS; ii++ {
		myImage.SortColumns("v", THREADPOOL_SIZE)
		myImage.SortRows("h2", THREADPOOL_SIZE)
	}
	myImage.SortColumns("v", THREADPOOL_SIZE)

	myImage.SaveAs(outFn)
}

func congregatePixels(inFn, outFn string) {
	myImage := myimage.MakeMyImageFromPath(inFn)

	////fmt.Println("  scrambling")
	////myImage.SortColumns("random", THREADPOOL_SIZE)
	////myImage.SortRows("random", THREADPOOL_SIZE)

	fmt.Println("  congregating")
	for ii := 0; ii < 3; ii++ {
		myImage.Congregate(0.01, 100) // thumb size, percent of image visited per iteration
		tempFn := outFn + "." + fmt.Sprintf("%03d", ii) + ".png"
		fmt.Println(tempFn)
		myImage.SaveAs(tempFn)
	}

	//fmt.Println("  showing thumb")
	//myImage.ShowThumb(0.01)

	myImage.SaveAs(outFn)
}

//================================================================================
// MAIN

func main() {
	fmt.Println("------------------------------------------------------------\\")
	defer fmt.Println("------------------------------------------------------------/")

	// handle command line
	if len(os.Args) < 2 {
		fmt.Println()
		fmt.Println("  usage:  sort  input.png  [input2.jpg input3.png ...]")
		fmt.Println()
		fmt.Println("  Sort the pixels in the image(s) and save to the ./output/ folder.")
		fmt.Println()
		return
	}

	// make output directory if needed
	if !utils.PathExists("output") {
		err := os.Mkdir("output", 0755)
		if err != nil {
			panic(fmt.Sprintf("%v", err))
		}
	}

	// open, sort, and save input images
	for inputII := 1; inputII < len(os.Args); inputII++ {
		inFn := os.Args[inputII]

		// build outFn from inFn
		outFn := inFn
		if strings.Contains(outFn, ".") {
			dotii := strings.LastIndex(outFn, ".")
			outFn = outFn[:dotii] + ".sorted.png"
		} else {
			outFn += ".sorted"
		}
		if strings.Contains(outFn, "/") {
			outFn = outFn[strings.LastIndex(outFn, "/")+1:]
		}
		outFn = "output/" + outFn

		// read, sort, and save (unless file has already been sorted)
		fmt.Println(inFn)
		if utils.PathExists(outFn) {
			fmt.Println("  SKIPPING: already exists")
		} else {
			//sortPixels(inFn, outFn)
			congregatePixels(inFn, outFn)
		}

		// attempt to give memory back to the OS
		debug.FreeOSMemory()

		fmt.Println()
	}
}
<commit_msg>Adjust constants<commit_after>package main

import (
	"fmt"
	"github.com/longears/sortpixels/myimage"
	"github.com/longears/sortpixels/utils"
	"os"
	"runtime"
	"runtime/debug"
	"strings"
)

// How many times to repeat the vertical & horizontal sort step
const N_SORTS = 6

// How many threads to run in parallel
var THREADPOOL_SIZE int

func init() {
	THREADPOOL_SIZE = runtime.NumCPU()
	runtime.GOMAXPROCS(runtime.NumCPU())
}

//================================================================================
// IMAGE MODIFICATION ALGORITHMS

// Read the image from the path inFn,
// sort the pixels,
// and save the result to the path outFn.
// Return an error if the input file is not decodable as an image.
func sortPixels(inFn, outFn string) {
	myImage := myimage.MakeMyImageFromPath(inFn)

	fmt.Println("  sorting")
	for ii := 0; ii < N_SORTS; ii++ {
		myImage.SortColumns("v", THREADPOOL_SIZE)
		myImage.SortRows("h2", THREADPOOL_SIZE)
	}
	myImage.SortColumns("v", THREADPOOL_SIZE)

	myImage.SaveAs(outFn)
}

func congregatePixels(inFn, outFn string) {
	myImage := myimage.MakeMyImageFromPath(inFn)

	////fmt.Println("  scrambling")
	////myImage.SortColumns("random", THREADPOOL_SIZE)
	////myImage.SortRows("random", THREADPOOL_SIZE)

	fmt.Println("  congregating")
	for ii := 0; ii < 5; ii++ {
		myImage.Congregate(0.015, 50) // thumb size, percent of image visited per iteration
		tempFn := outFn + "." + fmt.Sprintf("%03d", ii) + ".png"
		fmt.Println(tempFn)
		myImage.SaveAs(tempFn)
	}

	//fmt.Println("  showing thumb")
	//myImage.ShowThumb(0.015)

	myImage.SaveAs(outFn)
}

//================================================================================
// MAIN

func main() {
	fmt.Println("------------------------------------------------------------\\")
	defer fmt.Println("------------------------------------------------------------/")

	// handle command line
	if len(os.Args) < 2 {
		fmt.Println()
		fmt.Println("  usage:  sort  input.png  [input2.jpg input3.png ...]")
		fmt.Println()
		fmt.Println("  Sort the pixels in the image(s) and save to the ./output/ folder.")
		fmt.Println()
		return
	}

	// make output directory if needed
	if !utils.PathExists("output") {
		err := os.Mkdir("output", 0755)
		if err != nil {
			panic(fmt.Sprintf("%v", err))
		}
	}

	// open, sort, and save input images
	for inputII := 1; inputII < len(os.Args); inputII++ {
		inFn := os.Args[inputII]

		// build outFn from inFn
		outFn := inFn
		if strings.Contains(outFn, ".") {
			dotii := strings.LastIndex(outFn, ".")
			outFn = outFn[:dotii] + ".sorted.png"
		} else {
			outFn += ".sorted"
		}
		if strings.Contains(outFn, "/") {
			outFn = outFn[strings.LastIndex(outFn, "/")+1:]
		}
		outFn = "output/" + outFn

		// read, sort, and save (unless file has already been sorted)
		fmt.Println(inFn)
		if utils.PathExists(outFn) {
			fmt.Println("  SKIPPING: already exists")
		} else {
			//sortPixels(inFn, outFn)
			congregatePixels(inFn, outFn)
		}

		// attempt to give memory back to the OS
		debug.FreeOSMemory()

		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"time"

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

	"database/sql"
	"reflect"
	"testing"

	"github.com/kyokomi/goma"
	"github.com/kyokomi/goma/test/mysql/dao"
	"github.com/kyokomi/goma/test/mysql/entity"
)

const testID = int64(1234567894)

func TestNumeric(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// numeric
	d := dao.GomaNumericTypes(db)

	insertData := entity.GomaNumericTypes{
		ID:               id,
		TinyintColumns:   int(8),
		BoolColumns:      false,
		SmallintColumns:  int(123),
		MediumintColumns: int(256),
		IntColumns:       int(11111111),
		IntegerColumns:   int(22222222),
		SerialColumns:    int64(testID),
		DecimalColumns:   "1234567890",
		NumericColumns:   "1234567890",
		FloatColumns:     float32(1.234),
		DoubleColumns:    float64(1000.234),
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		insertData.SerialColumns = e.SerialColumns // TODO: AutoIncrement
		if !reflect.DeepEqual(e, insertData) {
			t.Errorf("ERROR: %+v != %+v", e, insertData)
		}
	}

	insertData.IntColumns = 111111
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestString(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// string
	d := dao.GomaStringTypes(db)

	insertData := entity.GomaStringTypes{
		ID:                id,
		TextColumns:       "あいうえおかきくけこ",
		TinytextColumns:   "abc",
		MediumtextColumns: "abcdefg",
		LongtextColumns:   "鉄1234567890abcdefghijkelmnopqrstuvwxyz1234567890abcdefghijkelmnopqrstuvwxyz柱",
		CharColumns:       "a      a",
		VarcharColumns:    "1234567890abcdefghijkelmnopqrstuvwxyz",
		EnumColumns:       entity.EnumColumnsClose,
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if !reflect.DeepEqual(e, insertData) {
		t.Errorf("ERROR: \n%+v\n%+v", e, insertData)
	}

	insertData.TextColumns = "hogehoge"
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestDate(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// date
	d := dao.GomaDateTypes(db)

	now := time.Now()
	insertData := entity.GomaDateTypes{
		ID:               id,
		DatetimeColumns:  time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, now.Location()),
		TimestampColumns: time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, now.Location()),
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if !reflect.DeepEqual(e, insertData) {
		t.Errorf("ERROR: %+v != %+v", e, insertData)
	}

	insertData.TimestampColumns = time.Now()
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestBinary(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// date
	d := dao.GomaBinaryTypes(db)

	insertData := entity.GomaBinaryTypes{
		BinaryID:          id,
		BinaryColumns:     []uint8{49, 49, 49},
		TinyblobColumns:   []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
		BlobColumns:       []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
		MediumblobColumns: []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
		LongblobColumns:   []uint8{110, 111, 112, 113, 114, 115, 116, 117, 118},
		VarbinaryColumns:  []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if !reflect.DeepEqual(e, insertData) {
		t.Errorf("ERROR: %+v != %+v", e, insertData)
	}

	insertData.BinaryColumns = []uint8{50, 50, 50}
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestTx(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	log.SetFlags(log.Llongfile)

	id := testID

	tx, err := db.Begin()
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// string
	dtx := dao.TxGomaStringTypes(tx)

	e := entity.GomaStringTypes{
		ID:                id,
		TextColumns:       "あいうえおかきくけこ",
		TinytextColumns:   "abc",
		MediumtextColumns: "abcdefg",
		LongtextColumns:   "鉄1234567890abcdefghijkelmnopqrstuvwxyz1234567890abcdefghijkelmnopqrstuvwxyz柱",
		CharColumns:       "a      a",
		VarcharColumns:    "1234567890abcdefghijkelmnopqrstuvwxyz",
		EnumColumns:       entity.EnumColumnsOpen,
	}

	_, err = dtx.Insert(e)
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// Rollback（insertを無効にする）
	if err := tx.Rollback(); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// rollbackしたのでトランザクション生成しなおす
	tx, err = db.Begin()
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// string
	dtx = dao.TxGomaStringTypes(tx)

	// Rollbackでnilのはず
	if _, err := dtx.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}

	// Insertする
	_, err = dtx.Insert(e)
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// Commit
	if err := tx.Commit(); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// commitしたのでtxじゃないdao
	d := dao.GomaStringTypes(db)

	if _, err := d.SelectByID(id); err == sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Commitしたのにnil")
	} else if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	_, err = d.Delete(id)
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}
<commit_msg>同じ時間だとupdateされないため<commit_after>package main

import (
	"log"

	"time"

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

	"database/sql"
	"reflect"
	"testing"

	"github.com/kyokomi/goma"
	"github.com/kyokomi/goma/test/mysql/dao"
	"github.com/kyokomi/goma/test/mysql/entity"
)

const testID = int64(1234567894)

func TestNumeric(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// numeric
	d := dao.GomaNumericTypes(db)

	insertData := entity.GomaNumericTypes{
		ID:               id,
		TinyintColumns:   int(8),
		BoolColumns:      false,
		SmallintColumns:  int(123),
		MediumintColumns: int(256),
		IntColumns:       int(11111111),
		IntegerColumns:   int(22222222),
		SerialColumns:    int64(testID),
		DecimalColumns:   "1234567890",
		NumericColumns:   "1234567890",
		FloatColumns:     float32(1.234),
		DoubleColumns:    float64(1000.234),
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		insertData.SerialColumns = e.SerialColumns // TODO: AutoIncrement
		if !reflect.DeepEqual(e, insertData) {
			t.Errorf("ERROR: %+v != %+v", e, insertData)
		}
	}

	insertData.IntColumns = 111111
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestString(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// string
	d := dao.GomaStringTypes(db)

	insertData := entity.GomaStringTypes{
		ID:                id,
		TextColumns:       "あいうえおかきくけこ",
		TinytextColumns:   "abc",
		MediumtextColumns: "abcdefg",
		LongtextColumns:   "鉄1234567890abcdefghijkelmnopqrstuvwxyz1234567890abcdefghijkelmnopqrstuvwxyz柱",
		CharColumns:       "a      a",
		VarcharColumns:    "1234567890abcdefghijkelmnopqrstuvwxyz",
		EnumColumns:       entity.EnumColumnsClose,
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if !reflect.DeepEqual(e, insertData) {
		t.Errorf("ERROR: \n%+v\n%+v", e, insertData)
	}

	insertData.TextColumns = "hogehoge"
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestDate(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// date
	d := dao.GomaDateTypes(db)

	now := time.Now()
	insertData := entity.GomaDateTypes{
		ID:               id,
		DatetimeColumns:  time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, now.Location()),
		TimestampColumns: time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, now.Location()),
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if !reflect.DeepEqual(e, insertData) {
		t.Errorf("ERROR: %+v != %+v", e, insertData)
	}

	insertData.TimestampColumns = time.Now().Add(1 * time.Second)
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestBinary(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	id := testID

	// date
	d := dao.GomaBinaryTypes(db)

	insertData := entity.GomaBinaryTypes{
		BinaryID:          id,
		BinaryColumns:     []uint8{49, 49, 49},
		TinyblobColumns:   []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
		BlobColumns:       []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
		MediumblobColumns: []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
		LongblobColumns:   []uint8{110, 111, 112, 113, 114, 115, 116, 117, 118},
		VarbinaryColumns:  []uint8{49, 49, 50, 51, 52, 53, 54, 55, 56},
	}

	if es, err := d.SelectAll(); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if len(es) != 0 {
		t.Errorf("ERROR: len %d", len(es))
	}

	if _, err := d.Insert(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if e, err := d.SelectByID(id); err != nil {
		t.Errorf("ERROR: %s", err)
	} else if !reflect.DeepEqual(e, insertData) {
		t.Errorf("ERROR: %+v != %+v", e, insertData)
	}

	insertData.BinaryColumns = []uint8{50, 50, 50}
	if result, err := d.Update(insertData); err != nil {
		t.Errorf("ERROR: %s", err)
	} else {
		rows, err := result.RowsAffected()
		if err != nil {
			t.Errorf("ERROR: %s", err)
		}
		if rows != 1 {
			t.Errorf("ERROR: update len 1 != %d", rows)
		}
	}

	if _, err := d.Delete(id); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}

func TestTx(t *testing.T) {
	db, err := goma.Open("config.json")
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}
	defer db.Close()

	log.SetFlags(log.Llongfile)

	id := testID

	tx, err := db.Begin()
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// string
	dtx := dao.TxGomaStringTypes(tx)

	e := entity.GomaStringTypes{
		ID:                id,
		TextColumns:       "あいうえおかきくけこ",
		TinytextColumns:   "abc",
		MediumtextColumns: "abcdefg",
		LongtextColumns:   "鉄1234567890abcdefghijkelmnopqrstuvwxyz1234567890abcdefghijkelmnopqrstuvwxyz柱",
		CharColumns:       "a      a",
		VarcharColumns:    "1234567890abcdefghijkelmnopqrstuvwxyz",
		EnumColumns:       entity.EnumColumnsOpen,
	}

	_, err = dtx.Insert(e)
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// Rollback（insertを無効にする）
	if err := tx.Rollback(); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// rollbackしたのでトランザクション生成しなおす
	tx, err = db.Begin()
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// string
	dtx = dao.TxGomaStringTypes(tx)

	// Rollbackでnilのはず
	if _, err := dtx.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}

	// Insertする
	_, err = dtx.Insert(e)
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// Commit
	if err := tx.Commit(); err != nil {
		t.Errorf("ERROR: %s", err)
	}

	// commitしたのでtxじゃないdao
	d := dao.GomaStringTypes(db)

	if _, err := d.SelectByID(id); err == sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Commitしたのにnil")
	} else if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	_, err = d.Delete(id)
	if err != nil {
		t.Errorf("ERROR: %s", err)
	}

	if _, err := d.SelectByID(id); err != sql.ErrNoRows {
		t.Errorf("ERROR: %s", "Deleteしたのにnilじゃない")
	}
}
<|endoftext|>