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 }