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 }