google.golang.org/grpc@v1.72.2/internal/testutils/xds/e2e/bootstrap.go (about)

     1  /*
     2   *
     3   * Copyright 2020 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package e2e
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  	"os"
    25  	"path"
    26  	"testing"
    27  
    28  	"google.golang.org/grpc/internal/xds/bootstrap"
    29  	"google.golang.org/grpc/testdata"
    30  )
    31  
    32  // DefaultFileWatcherConfig is a helper function to create a default certificate
    33  // provider plugin configuration. The test is expected to have setup the files
    34  // appropriately before this configuration is used to instantiate providers.
    35  func DefaultFileWatcherConfig(certPath, keyPath, caPath string) json.RawMessage {
    36  	return json.RawMessage(fmt.Sprintf(`{
    37  			"plugin_name": "file_watcher",
    38  			"config": {
    39  				"certificate_file": %q,
    40  				"private_key_file": %q,
    41  				"ca_certificate_file": %q,
    42  				"refresh_interval": "600s"
    43  			}
    44  		}`, certPath, keyPath, caPath))
    45  }
    46  
    47  // DefaultBootstrapContents creates a default bootstrap configuration with the
    48  // given node ID and server URI. It also creates certificate provider
    49  // configuration and sets the listener resource name template to be used on the
    50  // server side.
    51  func DefaultBootstrapContents(t *testing.T, nodeID, serverURI string) []byte {
    52  	t.Helper()
    53  
    54  	// Create a directory to hold certs and key files used on the server side.
    55  	serverDir, err := createTmpDirWithCerts("testServerSideXDS*", "x509/server1_cert.pem", "x509/server1_key.pem", "x509/client_ca_cert.pem")
    56  	if err != nil {
    57  		t.Fatalf("Failed to create bootstrap configuration: %v", err)
    58  	}
    59  
    60  	// Create a directory to hold certs and key files used on the client side.
    61  	clientDir, err := createTmpDirWithCerts("testClientSideXDS*", "x509/client1_cert.pem", "x509/client1_key.pem", "x509/server_ca_cert.pem")
    62  	if err != nil {
    63  		t.Fatalf("Failed to create bootstrap configuration: %v", err)
    64  	}
    65  
    66  	// Create certificate providers section of the bootstrap config with entries
    67  	// for both the client and server sides.
    68  	cpc := map[string]json.RawMessage{
    69  		ServerSideCertProviderInstance: DefaultFileWatcherConfig(path.Join(serverDir, certFile), path.Join(serverDir, keyFile), path.Join(serverDir, rootFile)),
    70  		ClientSideCertProviderInstance: DefaultFileWatcherConfig(path.Join(clientDir, certFile), path.Join(clientDir, keyFile), path.Join(clientDir, rootFile)),
    71  	}
    72  
    73  	// Create the bootstrap configuration.
    74  	bs, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{
    75  		Servers: []byte(fmt.Sprintf(`[{
    76  			"server_uri": "passthrough:///%s",
    77  			"channel_creds": [{"type": "insecure"}]
    78  		}]`, serverURI)),
    79  		Node:                               []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)),
    80  		CertificateProviders:               cpc,
    81  		ServerListenerResourceNameTemplate: ServerListenerResourceNameTemplate,
    82  	})
    83  	if err != nil {
    84  		t.Fatalf("Failed to create bootstrap configuration: %v", err)
    85  	}
    86  	return bs
    87  }
    88  
    89  const (
    90  	// Names of files inside tempdir, for certprovider plugin to watch.
    91  	certFile = "cert.pem"
    92  	keyFile  = "key.pem"
    93  	rootFile = "ca.pem"
    94  )
    95  
    96  func createTmpFile(src, dst string) error {
    97  	data, err := os.ReadFile(src)
    98  	if err != nil {
    99  		return fmt.Errorf("os.ReadFile(%q) failed: %v", src, err)
   100  	}
   101  	if err := os.WriteFile(dst, data, os.ModePerm); err != nil {
   102  		return fmt.Errorf("os.WriteFile(%q) failed: %v", dst, err)
   103  	}
   104  	return nil
   105  }
   106  
   107  // createTmpDirWithCerts creates a temporary directory under the system default
   108  // tempDir with the given dirPattern. It also reads from certSrc, keySrc and
   109  // rootSrc files and creates appropriate files under the newly create tempDir.
   110  // Returns the path of the created tempDir if successful, and an error
   111  // otherwise.
   112  func createTmpDirWithCerts(dirPattern, certSrc, keySrc, rootSrc string) (string, error) {
   113  	// Create a temp directory. Passing an empty string for the first argument
   114  	// uses the system temp directory.
   115  	dir, err := os.MkdirTemp("", dirPattern)
   116  	if err != nil {
   117  		return "", fmt.Errorf("os.MkdirTemp() failed: %v", err)
   118  	}
   119  
   120  	if err := createTmpFile(testdata.Path(certSrc), path.Join(dir, certFile)); err != nil {
   121  		return "", err
   122  	}
   123  	if err := createTmpFile(testdata.Path(keySrc), path.Join(dir, keyFile)); err != nil {
   124  		return "", err
   125  	}
   126  	if err := createTmpFile(testdata.Path(rootSrc), path.Join(dir, rootFile)); err != nil {
   127  		return "", err
   128  	}
   129  	return dir, nil
   130  }