github.com/vmware/govmomi@v0.51.0/vapi/library/library_item_updatesession_file.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package library
     6  
     7  import (
     8  	"bufio"
     9  	"context"
    10  	"fmt"
    11  	"io"
    12  	"net/http"
    13  	"strings"
    14  
    15  	"github.com/vmware/govmomi/vapi/internal"
    16  	"github.com/vmware/govmomi/vapi/rest"
    17  	"github.com/vmware/govmomi/vim25/soap"
    18  )
    19  
    20  // TransferEndpoint provides information on the source of a library item file.
    21  type TransferEndpoint struct {
    22  	URI                      string `json:"uri,omitempty"`
    23  	SSLCertificate           string `json:"ssl_certificate,omitempty"`
    24  	SSLCertificateThumbprint string `json:"ssl_certificate_thumbprint,omitempty"`
    25  }
    26  
    27  type ProbeResult struct {
    28  	Status         string                    `json:"status"`
    29  	SSLThumbprint  string                    `json:"ssl_thumbprint,omitempty"`
    30  	SSLCertificate string                    `json:"ssl_certificate,omitempty"`
    31  	ErrorMessages  []rest.LocalizableMessage `json:"error_messages,omitempty"`
    32  }
    33  
    34  // UpdateFile is the specification for the updatesession
    35  // operations file:add, file:get, and file:list.
    36  type UpdateFile struct {
    37  	BytesTransferred int64                    `json:"bytes_transferred,omitempty"`
    38  	Checksum         *Checksum                `json:"checksum_info,omitempty"`
    39  	ErrorMessage     *rest.LocalizableMessage `json:"error_message,omitempty"`
    40  	Name             string                   `json:"name"`
    41  	Size             int64                    `json:"size,omitempty"`
    42  	SourceEndpoint   *TransferEndpoint        `json:"source_endpoint,omitempty"`
    43  	SourceType       string                   `json:"source_type"`
    44  	Status           string                   `json:"status,omitempty"`
    45  	UploadEndpoint   *TransferEndpoint        `json:"upload_endpoint,omitempty"`
    46  }
    47  
    48  // FileValidationError contains the validation error of a file in the update session
    49  type FileValidationError struct {
    50  	Name         string                  `json:"name"`
    51  	ErrorMessage rest.LocalizableMessage `json:"error_message"`
    52  }
    53  
    54  // UpdateFileValidation contains the result of validating the files in the update session
    55  type UpdateFileValidation struct {
    56  	HasErrors    bool                  `json:"has_errors"`
    57  	MissingFiles []string              `json:"missing_files,omitempty"`
    58  	InvalidFiles []FileValidationError `json:"invalid_files,omitempty"`
    59  }
    60  
    61  // AddLibraryItemFile adds a file
    62  func (c *Manager) AddLibraryItemFile(ctx context.Context, sessionID string, updateFile UpdateFile) (*UpdateFile, error) {
    63  	url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("add")
    64  	spec := struct {
    65  		FileSpec UpdateFile `json:"file_spec"`
    66  	}{updateFile}
    67  	var res UpdateFile
    68  	err := c.Do(ctx, url.Request(http.MethodPost, spec), &res)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	if res.Status == "ERROR" {
    73  		return nil, res.ErrorMessage
    74  	}
    75  	return &res, nil
    76  }
    77  
    78  // AddLibraryItemFileFromURI adds a file from a remote URI.
    79  func (c *Manager) AddLibraryItemFileFromURI(ctx context.Context, sessionID, name, uri string, checksum ...Checksum) (*UpdateFile, error) {
    80  	source := &TransferEndpoint{
    81  		URI: uri,
    82  	}
    83  
    84  	file := UpdateFile{
    85  		Name:           name,
    86  		SourceType:     "PULL",
    87  		SourceEndpoint: source,
    88  	}
    89  
    90  	if len(checksum) == 1 && checksum[0].Checksum != "" {
    91  		file.Checksum = &checksum[0]
    92  	} else if len(checksum) > 1 {
    93  		return nil, fmt.Errorf("expected 0 or 1 checksum, got %d", len(checksum))
    94  	}
    95  
    96  	if res, err := c.Head(uri); err == nil {
    97  		file.Size = res.ContentLength
    98  		if res.TLS != nil {
    99  			source.SSLCertificateThumbprint = soap.ThumbprintSHA1(res.TLS.PeerCertificates[0])
   100  		}
   101  	} else {
   102  		res, err := c.ProbeTransferEndpoint(ctx, *source)
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  		if res.SSLCertificate != "" {
   107  			source.SSLCertificate = res.SSLCertificate
   108  		} else {
   109  			source.SSLCertificateThumbprint = res.SSLThumbprint
   110  		}
   111  	}
   112  
   113  	return c.AddLibraryItemFile(ctx, sessionID, file)
   114  }
   115  
   116  // GetLibraryItemUpdateSessionFile retrieves information about a specific file
   117  // that is a part of an update session.
   118  func (c *Manager) GetLibraryItemUpdateSessionFile(ctx context.Context, sessionID string, fileName string) (*UpdateFile, error) {
   119  	url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("get")
   120  	spec := struct {
   121  		Name string `json:"file_name"`
   122  	}{fileName}
   123  	var res UpdateFile
   124  	return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
   125  }
   126  
   127  // ListLibraryItemUpdateSessionFile lists all files in the library item associated with the update session
   128  func (c *Manager) ListLibraryItemUpdateSessionFile(ctx context.Context, sessionID string) ([]UpdateFile, error) {
   129  	url := c.Resource(internal.LibraryItemUpdateSessionFile).WithParam("update_session_id", sessionID)
   130  	var res []UpdateFile
   131  	return res, c.Do(ctx, url.Request(http.MethodGet), &res)
   132  }
   133  
   134  // ValidateLibraryItemUpdateSessionFile validates all files in the library item associated with the update session
   135  func (c *Manager) ValidateLibraryItemUpdateSessionFile(ctx context.Context, sessionID string) (*UpdateFileValidation, error) {
   136  	url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("validate")
   137  	var res UpdateFileValidation
   138  	return &res, c.Do(ctx, url.Request(http.MethodPost), &res)
   139  }
   140  
   141  // RemoveLibraryItemUpdateSessionFile requests a file to be removed. The file will only be effectively removed when the update session is completed.
   142  func (c *Manager) RemoveLibraryItemUpdateSessionFile(ctx context.Context, sessionID string, fileName string) error {
   143  	url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("remove")
   144  	spec := struct {
   145  		Name string `json:"file_name"`
   146  	}{fileName}
   147  	return c.Do(ctx, url.Request(http.MethodPost, spec), nil)
   148  }
   149  
   150  func (c *Manager) ProbeTransferEndpoint(ctx context.Context, endpoint TransferEndpoint) (*ProbeResult, error) {
   151  	url := c.Resource(internal.LibraryItemUpdateSessionFile).WithAction("probe")
   152  	spec := struct {
   153  		SourceEndpoint TransferEndpoint `json:"source_endpoint"`
   154  	}{endpoint}
   155  	var res ProbeResult
   156  	return &res, c.Do(ctx, url.Request(http.MethodPost, spec), &res)
   157  }
   158  
   159  // ReadManifest converts an ovf manifest to a map of file name -> Checksum.
   160  func ReadManifest(m io.Reader) (map[string]*Checksum, error) {
   161  	// expected format: openssl sha1 *.{ovf,vmdk}
   162  	c := make(map[string]*Checksum)
   163  
   164  	scanner := bufio.NewScanner(m)
   165  	for scanner.Scan() {
   166  		line := strings.SplitN(scanner.Text(), ")=", 2)
   167  		if len(line) != 2 {
   168  			continue
   169  		}
   170  		name := strings.SplitN(line[0], "(", 2)
   171  		if len(name) != 2 {
   172  			continue
   173  		}
   174  		sum := &Checksum{
   175  			Algorithm: strings.TrimSpace(name[0]),
   176  			Checksum:  strings.TrimSpace(line[1]),
   177  		}
   178  		c[name[1]] = sum
   179  	}
   180  
   181  	return c, scanner.Err()
   182  }