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

     1  /*
     2  Copyright (c) 2019-2023 VMware, Inc. All Rights Reserved.
     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 library
    18  
    19  import (
    20  	"bufio"
    21  	"context"
    22  	"io"
    23  	"net/http"
    24  	"strings"
    25  
    26  	"github.com/vmware/govmomi/vapi/internal"
    27  	"github.com/vmware/govmomi/vapi/rest"
    28  	"github.com/vmware/govmomi/vim25/soap"
    29  )
    30  
    31  // TransferEndpoint provides information on the source of a library item file.
    32  type TransferEndpoint struct {
    33  	URI                      string `json:"uri,omitempty"`
    34  	SSLCertificateThumbprint string `json:"ssl_certificate_thumbprint,omitempty"`
    35  }
    36  
    37  type ProbeResult struct {
    38  	Status         string                    `json:"status"`
    39  	SSLThumbprint  string                    `json:"ssl_thumbprint,omitempty"`
    40  	SSLCertificate string                    `json:"ssl_certificate,omitempty"`
    41  	ErrorMessages  []rest.LocalizableMessage `json:"error_messages,omitempty"`
    42  }
    43  
    44  // UpdateFile is the specification for the updatesession
    45  // operations file:add, file:get, and file:list.
    46  type UpdateFile struct {
    47  	BytesTransferred int64                    `json:"bytes_transferred,omitempty"`
    48  	Checksum         *Checksum                `json:"checksum_info,omitempty"`
    49  	ErrorMessage     *rest.LocalizableMessage `json:"error_message,omitempty"`
    50  	Name             string                   `json:"name"`
    51  	Size             int64                    `json:"size,omitempty"`
    52  	SourceEndpoint   *TransferEndpoint        `json:"source_endpoint,omitempty"`
    53  	SourceType       string                   `json:"source_type"`
    54  	Status           string                   `json:"status,omitempty"`
    55  	UploadEndpoint   *TransferEndpoint        `json:"upload_endpoint,omitempty"`
    56  }
    57  
    58  // FileValidationError contains the validation error of a file in the update session
    59  type FileValidationError struct {
    60  	Name         string                  `json:"name"`
    61  	ErrorMessage rest.LocalizableMessage `json:"error_message"`
    62  }
    63  
    64  // UpdateFileValidation contains the result of validating the files in the update session
    65  type UpdateFileValidation struct {
    66  	HasErrors    bool                  `json:"has_errors"`
    67  	MissingFiles []string              `json:"missing_files,omitempty"`
    68  	InvalidFiles []FileValidationError `json:"invalid_files,omitempty"`
    69  }
    70  
    71  // AddLibraryItemFile adds a file
    72  func (c *Manager) AddLibraryItemFile(ctx context.Context, sessionID string, updateFile UpdateFile) (*UpdateFile, error) {
    73  	url := c.Resource(internal.LibraryItemUpdateSessionFile).WithID(sessionID).WithAction("add")
    74  	spec := struct {
    75  		FileSpec UpdateFile `json:"file_spec"`
    76  	}{updateFile}
    77  	var res UpdateFile
    78  	err := c.Do(ctx, url.Request(http.MethodPost, spec), &res)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	if res.Status == "ERROR" {
    83  		return nil, res.ErrorMessage
    84  	}
    85  	return &res, nil
    86  }
    87  
    88  // AddLibraryItemFileFromURI adds a file from a remote URI.
    89  func (c *Manager) AddLibraryItemFileFromURI(ctx context.Context, sessionID, name, uri string) (*UpdateFile, error) {
    90  	source := &TransferEndpoint{
    91  		URI: uri,
    92  	}
    93  
    94  	file := UpdateFile{
    95  		Name:           name,
    96  		SourceType:     "PULL",
    97  		SourceEndpoint: source,
    98  	}
    99  
   100  	if res, err := c.Head(uri); err == nil {
   101  		file.Size = res.ContentLength
   102  		if res.TLS != nil {
   103  			source.SSLCertificateThumbprint = soap.ThumbprintSHA1(res.TLS.PeerCertificates[0])
   104  		}
   105  	} else {
   106  		res, err := c.ProbeTransferEndpoint(ctx, *source)
   107  		if err != nil {
   108  			return nil, err
   109  		}
   110  		source.SSLCertificateThumbprint = res.SSLThumbprint
   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  }