github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/e2e/consulacls/manage.go (about)

     1  package consulacls
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os/exec"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  // DefaultTFStateFile is the location of the TF state file, as created for the
    17  // e2e test framework. This file is used to extract the TF serial number, which
    18  // is used to determine whether the consul bootstrap process is necessary or has
    19  // already taken place.
    20  const DefaultTFStateFile = "terraform/terraform.tfstate"
    21  
    22  // A Manager is used to manipulate whether Consul ACLs are enabled or disabled.
    23  // Only works with TF provisioned clusters.
    24  type Manager interface {
    25  	// Enable Consul ACLs in the Consul cluster. The Consul ACL master token
    26  	// associated with the Consul cluster is returned.
    27  	//
    28  	// A complete bootstrap process will take place if necessary.
    29  	//
    30  	// Once enabled, Consul ACLs can be disabled with Disable.
    31  	Enable(t *testing.T) string
    32  
    33  	// Disable Consul ACLs in the Consul Cluster.
    34  	//
    35  	// Once disabled, Consul ACLs can be re-enabled with Enable.
    36  	Disable(t *testing.T)
    37  }
    38  
    39  type tfManager struct {
    40  	serial int
    41  }
    42  
    43  func New(tfStateFile string) (*tfManager, error) {
    44  	serial, err := extractSerial(tfStateFile)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	return &tfManager{
    49  		serial: serial,
    50  	}, nil
    51  }
    52  
    53  func (m *tfManager) Enable(t *testing.T) string {
    54  	// Run the consul ACL bootstrap script, which will store the master token
    55  	// in the deterministic path based on the TF state serial number. If the
    56  	// bootstrap process had already taken place, ACLs will be activated but
    57  	// without going through the bootstrap process again, re-using the already
    58  	// existing Consul ACL master token.
    59  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
    60  	defer cancel()
    61  
    62  	response, err := exec.CommandContext(ctx,
    63  		"consulacls/consul-acls-manage.sh", "enable").CombinedOutput()
    64  	require.NoError(t, err, "consul-acls-manage.sh failed: %v", string(response))
    65  	fmt.Println(string(response))
    66  
    67  	// Read the Consul ACL master token that was generated (or if the token
    68  	// already existed because the bootstrap process had already taken place,
    69  	// that one).
    70  	token, err := m.readToken()
    71  	require.NoError(t, err)
    72  	return token
    73  }
    74  
    75  type tfState struct {
    76  	Serial int `json:"serial"`
    77  }
    78  
    79  // extractSerial will parse the TF state file looking for the serial number.
    80  func extractSerial(filename string) (int, error) {
    81  	if filename == "" {
    82  		filename = DefaultTFStateFile
    83  	}
    84  	b, err := ioutil.ReadFile(filename)
    85  	if err != nil {
    86  		return 0, fmt.Errorf("failed to extract TF serial: %w", err)
    87  	}
    88  	var state tfState
    89  	if err := json.Unmarshal(b, &state); err != nil {
    90  		return 0, fmt.Errorf("failed to extract TF serial: %w", err)
    91  	}
    92  	return state.Serial, nil
    93  }
    94  
    95  // tokenPath returns the expected path for the Consul ACL master token generated
    96  // by the consul-acls-manage.sh bootstrap script for the current TF serial version.
    97  func (m *tfManager) tokenPath() string {
    98  	return fmt.Sprintf("/tmp/e2e-consul-bootstrap-%d.token", m.serial)
    99  }
   100  
   101  func (m *tfManager) readToken() (string, error) {
   102  	b, err := ioutil.ReadFile(m.tokenPath())
   103  	if err != nil {
   104  		return "", err
   105  	}
   106  	return strings.TrimSpace(string(b)), nil
   107  }
   108  
   109  func (m *tfManager) Disable(t *testing.T) {
   110  	// Run the consul ACL bootstrap script, which will modify the Consul Server
   111  	// ACL policies to disable ACLs, and then restart those agents.
   112  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
   113  	defer cancel()
   114  
   115  	response, err := exec.CommandContext(ctx,
   116  		"consulacls/consul-acls-manage.sh", "disable").CombinedOutput()
   117  	require.NoError(t, err)
   118  	fmt.Println(string(response))
   119  }