github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/tests/rkt_socket_activation_test.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"bufio"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"math/rand"
    22  	"net"
    23  	"os"
    24  	"path/filepath"
    25  	"strconv"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	sd_dbus "github.com/coreos/go-systemd/dbus"
    31  	sd_util "github.com/coreos/go-systemd/util"
    32  	"github.com/coreos/rkt/tests/testutils"
    33  )
    34  
    35  func randomFreePort(t *testing.T) (int, error) {
    36  	l, err := net.Listen("tcp", "")
    37  	if err != nil {
    38  		return -1, err
    39  	}
    40  	defer l.Close()
    41  
    42  	addr := l.Addr().String()
    43  
    44  	n := strings.LastIndex(addr, ":")
    45  	port, err := strconv.Atoi(addr[n+1:])
    46  	if err != nil {
    47  		return -1, err
    48  	}
    49  
    50  	return port, nil
    51  }
    52  
    53  func TestSocketActivation(t *testing.T) {
    54  	if !sd_util.IsRunningSystemd() {
    55  		t.Skip("Systemd is not running on the host.")
    56  	}
    57  
    58  	r := rand.New(rand.NewSource(time.Now().UnixNano()))
    59  
    60  	port, err := randomFreePort(t)
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	echoImage := patchTestACI("rkt-inspect-echo.aci",
    66  		"--exec=/echo-socket-activated",
    67  		fmt.Sprintf("--ports=%d-tcp,protocol=tcp,port=%d,socketActivated=true", port, port))
    68  	defer os.Remove(echoImage)
    69  
    70  	ctx := testutils.NewRktRunCtx()
    71  	defer ctx.Cleanup()
    72  
    73  	conn, err := sd_dbus.New()
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  
    78  	rktTestingEchoService := `
    79  	[Unit]
    80  	Description=Socket-activated echo server
    81  
    82  	[Service]
    83  	ExecStart=%s
    84  	KillMode=process
    85  	`
    86  
    87  	rnd := r.Int()
    88  
    89  	// Write unit files directly to runtime system units directory
    90  	// (/run/systemd/system) to avoid calling LinkUnitFiles - it is buggy in
    91  	// systemd v219 as it does not work with absolute paths.
    92  	unitsDir := "/run/systemd/system"
    93  
    94  	cmd := fmt.Sprintf("%s --insecure-options=image run --mds-register=false %s", ctx.Cmd(), echoImage)
    95  	serviceContent := fmt.Sprintf(rktTestingEchoService, cmd)
    96  	serviceTargetBase := fmt.Sprintf("rkt-testing-socket-activation-%d.service", rnd)
    97  	serviceTarget := filepath.Join(unitsDir, serviceTargetBase)
    98  
    99  	if err := ioutil.WriteFile(serviceTarget, []byte(serviceContent), 0666); err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	defer os.Remove(serviceTarget)
   103  
   104  	rktTestingEchoSocket := `
   105  	[Unit]
   106  	Description=Socket-activated netcat server socket
   107  
   108  	[Socket]
   109  	ListenStream=%d
   110  	`
   111  	socketContent := fmt.Sprintf(rktTestingEchoSocket, port)
   112  	socketTargetBase := fmt.Sprintf("rkt-testing-socket-activation-%d.socket", rnd)
   113  	socketTarget := filepath.Join(unitsDir, socketTargetBase)
   114  
   115  	if err := ioutil.WriteFile(socketTarget, []byte(socketContent), 0666); err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	defer os.Remove(socketTarget)
   119  
   120  	reschan := make(chan string)
   121  	doJob := func() {
   122  		job := <-reschan
   123  		if job != "done" {
   124  			t.Fatal("Job is not done:", job)
   125  		}
   126  	}
   127  
   128  	if _, err := conn.StartUnit(socketTargetBase, "replace", reschan); err != nil {
   129  		t.Fatal(err)
   130  	}
   131  	doJob()
   132  
   133  	defer func() {
   134  		if _, err := conn.StopUnit(socketTargetBase, "replace", reschan); err != nil {
   135  			t.Fatal(err)
   136  		}
   137  		doJob()
   138  
   139  		if _, err := conn.StopUnit(serviceTargetBase, "replace", reschan); err != nil {
   140  			t.Fatal(err)
   141  		}
   142  		doJob()
   143  	}()
   144  
   145  	expected := "HELO\n"
   146  	sockConn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", port))
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  
   151  	if _, err := fmt.Fprintf(sockConn, expected); err != nil {
   152  		t.Fatal(err)
   153  	}
   154  
   155  	answer, err := bufio.NewReader(sockConn).ReadString('\n')
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  
   160  	if answer != expected {
   161  		t.Fatalf("Expected %q, Got %q", expected, answer)
   162  	}
   163  
   164  	return
   165  }