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