Skip to content
This repository has been archived by the owner on Jan 30, 2020. It is now read-only.

tests: added "fleetctl --tunnel" tests #1492

Merged
merged 10 commits into from
Mar 21, 2016
2 changes: 2 additions & 0 deletions functional/fixtures/units/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[Service]
ExecStart=/bin/bash -c "while true; do echo Hello, World %i!; sleep 1; done"
74 changes: 65 additions & 9 deletions functional/platform/nspawn.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,25 @@ const (
)

var fleetdBinPath string
var fleetctlBinPath string

func init() {
fleetdBinPath = os.Getenv("FLEETD_BIN")
fleetctlBinPath = os.Getenv("FLEETCTL_BIN")
if fleetdBinPath == "" {
fmt.Println("FLEETD_BIN environment variable must be set")
os.Exit(1)
} else if _, err := os.Stat(fleetdBinPath); err != nil {
fmt.Printf("%v\n", err)
os.Exit(1)
}
if fleetctlBinPath == "" {
fmt.Println("FLEETCTL_BIN environment variable must be set")
os.Exit(1)
} else if _, err := os.Stat(fleetctlBinPath); err != nil {
fmt.Printf("%v\n", err)
os.Exit(1)
}
// sanity check etcd availability
cmd := exec.Command("etcdctl", "ls")
out, err := cmd.CombinedOutput()
Expand Down Expand Up @@ -94,13 +103,28 @@ func (nc *nspawnCluster) keyspace() string {
return fmt.Sprintf("/fleet_functional/%s", nc.name)
}

// This function adds --endpoint flag if --tunnel flag is not used
// Usefull for "fleetctl fd-forward" tests
func handleEndpointFlag(m Member, args *[]string) {
result := true
for _, arg := range *args {
if strings.Contains(arg, "-- ") || strings.Contains(arg, "--tunnel") {
result = false
break
}
}
if result {
*args = append([]string{"--endpoint=" + m.Endpoint()}, *args...)
}
}

func (nc *nspawnCluster) Fleetctl(m Member, args ...string) (string, string, error) {
args = append([]string{"--endpoint=" + m.Endpoint()}, args...)
handleEndpointFlag(m, &args)
return util.RunFleetctl(args...)
}

func (nc *nspawnCluster) FleetctlWithInput(m Member, input string, args ...string) (string, string, error) {
args = append([]string{"--endpoint=" + m.Endpoint()}, args...)
handleEndpointFlag(m, &args)
return util.RunFleetctlWithInput(input, args...)
}

Expand Down Expand Up @@ -228,14 +252,14 @@ func (nc *nspawnCluster) prepCluster() (err error) {
return nil
}

func (nc *nspawnCluster) insertFleetd(dir string) error {
cmd := fmt.Sprintf("mkdir -p %s/opt/fleet", dir)
func (nc *nspawnCluster) insertBin(src string, dst string) error {
cmd := fmt.Sprintf("mkdir -p %s/opt/fleet", dst)
if _, _, err := run(cmd); err != nil {
return err
}

fleetdBinDst := path.Join(dir, "opt", "fleet", "fleetd")
return copyFile(fleetdBinPath, fleetdBinDst, 0755)
binDst := path.Join(dst, "opt", "fleet", path.Base(src))
return copyFile(src, binDst, 0755)
}

func (nc *nspawnCluster) buildConfigDrive(dir, ip string) error {
Expand Down Expand Up @@ -303,8 +327,6 @@ func (nc *nspawnCluster) createMember(id string) (m Member, err error) {
// minimum requirements for running systemd/coreos in a container
fmt.Sprintf("mkdir -p %s/usr", fsdir),
fmt.Sprintf("cp /etc/os-release %s/etc", fsdir),
fmt.Sprintf("echo 'core:x:500:500:CoreOS Admin:/home/core:/bin/bash' > %s/etc/passwd", fsdir),
fmt.Sprintf("echo 'core:x:500:' > %s/etc/group", fsdir),
fmt.Sprintf("ln -s /proc/self/mounts %s/etc/mtab", fsdir),
fmt.Sprintf("ln -s usr/lib64 %s/lib64", fsdir),
fmt.Sprintf("ln -s lib64 %s/lib", fsdir),
Expand Down Expand Up @@ -354,11 +376,45 @@ UseDNS no
return
}

if err = nc.insertFleetd(fsdir); err != nil {
filesContents := []struct {
path string
contents string
mode os.FileMode
}{
{
"/etc/passwd",
"core:x:500:500:CoreOS Admin:/home/core:/bin/bash",
0644,
},
{
"/etc/group",
"core:x:500:",
0644,
},
{
"/home/core/.bash_profile",
"export PATH=/opt/fleet:$PATH",
0644,
},
}

for _, file := range filesContents {
if err = ioutil.WriteFile(path.Join(fsdir, file.path), []byte(file.contents), file.mode); err != nil {
log.Printf("Failed writing %s: %v", path.Join(fsdir, file.path), err)
return
}
}

if err = nc.insertBin(fleetdBinPath, fsdir); err != nil {
log.Printf("Failed preparing fleetd in filesystem: %v", err)
return
}

if err = nc.insertBin(fleetctlBinPath, fsdir); err != nil {
log.Printf("Failed preparing fleetctl in filesystem: %v", err)
return
}

if err = nc.buildConfigDrive(fsdir, nm.IP()); err != nil {
log.Printf("Failed building config drive: %v", err)
return
Expand Down
89 changes: 89 additions & 0 deletions functional/tunnel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2016 CoreOS, Inc.
//
// 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 functional

import (
"fmt"
"io/ioutil"
"os"
"strings"
"syscall"
"testing"

"github.com/coreos/fleet/functional/platform"
)

// Start three units using ssh tunnel
func TestTunnelScheduleBatchUnits(t *testing.T) {
cluster, err := platform.NewNspawnCluster("smoke")
if err != nil {
t.Fatal(err)
}
defer cluster.Destroy()

members, err := platform.CreateNClusterMembers(cluster, 3)
if err != nil {
t.Fatal(err)
}
m0 := members[0]
_, err = cluster.WaitForNMachines(m0, 3)
if err != nil {
t.Fatal(err)
}

tmp, err := ioutil.TempFile(os.TempDir(), "known-hosts")
if err != nil {
t.Fatal(err)
}
tmp.Close()
defer syscall.Unlink(tmp.Name())

khFile := tmp.Name()

// Launch one unit
if stdout, stderr, err := cluster.FleetctlWithInput(m0, "yes",
fmt.Sprintf("--tunnel=%s", m0.IP()),
"--strict-host-key-checking=true",
fmt.Sprintf("--known-hosts-file=%s", khFile),
"start",
"fixtures/units/hello.service"); err != nil {
t.Fatalf("Unable to submit one unit using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
} else if strings.Contains(stderr, "Error") {
t.Fatalf("Failed to correctly submit unit using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
}

// Combine all parameters and units in one args slice
args := []string{
fmt.Sprintf("--tunnel=%s", m0.IP()),
"--strict-host-key-checking=true",
fmt.Sprintf("--known-hosts-file=%s", khFile),
"start",
}
for i := 1; i <= 10; i++ {
args = append(args, fmt.Sprintf("fixtures/units/hello@%d.service", i))
}

// Launch a batch of units
if stdout, stderr, err := cluster.Fleetctl(m0, args...); err != nil {
t.Fatalf("Unable to submit batch of units using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
} else if strings.Contains(stderr, "Error") {
t.Fatalf("Failed to correctly submit batch of units using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
}

_, err = cluster.WaitForNActiveUnits(m0, 11)
if err != nil {
t.Fatal(err)
}
}
3 changes: 3 additions & 0 deletions functional/util/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ coreos:
Address={{.IP}}/16
- name: fleet.socket
command: start
- name: fleet-tcp.socket
command: start
content: |
[Socket]
ListenStream={{printf "%d" .FleetAPIPort}}
Service=fleet.service
- name: fleet.service
command: start
content: |
Expand Down
8 changes: 6 additions & 2 deletions ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ import (
type SSHForwardingClient struct {
agentForwarding bool
*gossh.Client
agentForwardingEnabled bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, one minor: could you please rename this to: authAgentReqSent or agentForwardingSent , but not Enabled, and also put some code comment: "Used to check if we have already sent the request to the ssh channel".

}

func (s *SSHForwardingClient) ForwardAgentAuthentication(session *gossh.Session) error {
if s.agentForwarding {
if s.agentForwarding && !s.agentForwardingEnabled {
// We are allowed to send "[email protected]" request only once per channel
// otherwise ssh daemon replies with the "SSH2_MSG_CHANNEL_FAILURE 100"
s.agentForwardingEnabled = true
return gosshagent.RequestAgentForwarding(session)
}
return nil
Expand All @@ -50,7 +54,7 @@ func newSSHForwardingClient(client *gossh.Client, agentForwarding bool) (*SSHFor
return nil, err
}

return &SSHForwardingClient{agentForwarding, client}, nil
return &SSHForwardingClient{agentForwarding, client, false}, nil
}

// makeSession initializes a gossh.Session connected to the invoking process's stdout/stderr/stdout.
Expand Down