vitess.io/vitess@v0.16.2/go/test/endtoend/vault/vault_server.go (about)

     1  /*
     2  Copyright 2020 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package vault
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"net/http"
    24  	"os"
    25  	"os/exec"
    26  	"path"
    27  	"strings"
    28  	"syscall"
    29  	"time"
    30  
    31  	"vitess.io/vitess/go/vt/log"
    32  )
    33  
    34  const (
    35  	vaultExecutableName = "vault"
    36  	vaultDownloadSource = "https://vitess-operator.storage.googleapis.com/install/vault"
    37  	vaultDownloadSize   = 132738840
    38  	vaultDirName        = "vault"
    39  	vaultConfigFileName = "vault.hcl"
    40  	vaultCertFileName   = "vault-cert.pem"
    41  	vaultCAFileName     = "ca.pem"
    42  	vaultKeyFileName    = "vault-key.pem"
    43  	vaultSetupScript    = "vault-setup.sh"
    44  )
    45  
    46  // Server : Basic parameters for the running the Vault server
    47  type Server struct {
    48  	address  string
    49  	port1    int
    50  	port2    int
    51  	execPath string
    52  	logDir   string
    53  
    54  	proc *exec.Cmd
    55  	exit chan error
    56  }
    57  
    58  // Start the Vault server in dev mode
    59  func (vs *Server) start() error {
    60  	// Download and unpack vault binary
    61  	vs.execPath = path.Join(os.Getenv("EXTRA_BIN"), vaultExecutableName)
    62  	fileStat, err := os.Stat(vs.execPath)
    63  	if err != nil || fileStat.Size() != vaultDownloadSize {
    64  		log.Warningf("Downloading Vault binary to: %v", vs.execPath)
    65  		err := downloadExecFile(vs.execPath, vaultDownloadSource)
    66  		if err != nil {
    67  			log.Error(err)
    68  			return err
    69  		}
    70  	} else {
    71  		log.Warningf("Vault binary already present at %v , not re-downloading", vs.execPath)
    72  	}
    73  
    74  	// Create Vault log directory
    75  	vs.logDir = path.Join(os.Getenv("VTDATAROOT"), fmt.Sprintf("%s_%d", vaultDirName, vs.port1))
    76  	if _, err := os.Stat(vs.logDir); os.IsNotExist(err) {
    77  		err := os.Mkdir(vs.logDir, 0700)
    78  		if err != nil {
    79  			log.Error(err)
    80  			return err
    81  		}
    82  	}
    83  
    84  	hclFile := path.Join(os.Getenv("PWD"), vaultConfigFileName)
    85  	hcl, _ := os.ReadFile(hclFile)
    86  	// Replace variable parts in Vault config file
    87  	hcl = bytes.Replace(hcl, []byte("$server"), []byte(vs.address), 1)
    88  	hcl = bytes.Replace(hcl, []byte("$port"), []byte(fmt.Sprintf("%d", vs.port1)), 1)
    89  	hcl = bytes.Replace(hcl, []byte("$cert"), []byte(path.Join(os.Getenv("PWD"), vaultCertFileName)), 1)
    90  	hcl = bytes.Replace(hcl, []byte("$key"), []byte(path.Join(os.Getenv("PWD"), vaultKeyFileName)), 1)
    91  	newHclFile := path.Join(vs.logDir, vaultConfigFileName)
    92  	err = os.WriteFile(newHclFile, hcl, 0700)
    93  	if err != nil {
    94  		log.Error(err)
    95  		return err
    96  	}
    97  
    98  	vs.proc = exec.Command(
    99  		vs.execPath,
   100  		"server",
   101  		fmt.Sprintf("-config=%s", newHclFile),
   102  	)
   103  
   104  	logFile, err := os.Create(path.Join(vs.logDir, "log.txt"))
   105  	if err != nil {
   106  		log.Error(err)
   107  		return err
   108  	}
   109  	vs.proc.Stderr = logFile
   110  	vs.proc.Stdout = logFile
   111  
   112  	vs.proc.Env = append(vs.proc.Env, os.Environ()...)
   113  
   114  	log.Infof("Running Vault server with command: %v", strings.Join(vs.proc.Args, " "))
   115  
   116  	err = vs.proc.Start()
   117  	if err != nil {
   118  		return err
   119  	}
   120  	vs.exit = make(chan error)
   121  	go func() {
   122  		if vs.proc != nil {
   123  			vs.exit <- vs.proc.Wait()
   124  		}
   125  	}()
   126  	return nil
   127  }
   128  
   129  func (vs *Server) stop() error {
   130  	if vs.proc == nil || vs.exit == nil {
   131  		return nil
   132  	}
   133  	// Attempt graceful shutdown with SIGTERM first
   134  	vs.proc.Process.Signal(syscall.SIGTERM)
   135  
   136  	select {
   137  	case err := <-vs.exit:
   138  		vs.proc = nil
   139  		return err
   140  
   141  	case <-time.After(10 * time.Second):
   142  		vs.proc.Process.Kill()
   143  		vs.proc = nil
   144  		return <-vs.exit
   145  	}
   146  }
   147  
   148  // Download file from url to path; making it executable
   149  func downloadExecFile(path string, url string) error {
   150  	resp, err := http.Get(url)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	defer resp.Body.Close()
   155  
   156  	err = os.WriteFile(path, []byte(""), 0700)
   157  	if err != nil {
   158  		return err
   159  	}
   160  	out, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
   161  	if err != nil {
   162  		return err
   163  	}
   164  	defer out.Close()
   165  
   166  	_, err = io.Copy(out, resp.Body)
   167  	return err
   168  }