// Update modifies an existing resource.
// Updates are synchronous - we update content and/or permissions directly.
func (p *Plugin) Update(ctx context.Context, req *resource.UpdateRequest) (*resource.UpdateResult, error) {
// Get SFTP client
client, err := p.getClient(req.TargetConfig)
if err != nil {
return &resource.UpdateResult{
ProgressResult: &resource.ProgressResult{
Operation: resource.OperationUpdate,
OperationStatus: resource.OperationStatusFailure,
ErrorCode: resource.OperationErrorCodeInternalFailure,
StatusMessage: err.Error(),
},
}, nil
}
// Parse desired properties
desiredProps, err := parseFileProperties(req.DesiredProperties)
if err != nil {
return &resource.UpdateResult{
ProgressResult: &resource.ProgressResult{
Operation: resource.OperationUpdate,
OperationStatus: resource.OperationStatusFailure,
ErrorCode: resource.OperationErrorCodeInvalidRequest,
StatusMessage: err.Error(),
},
}, nil
}
// Parse prior properties to detect changes
priorProps, _ := parseFileProperties(req.PriorProperties)
// Check if content changed - need to rewrite file
if priorProps == nil || priorProps.Content != desiredProps.Content {
var perm os.FileMode = 0644
if desiredProps.Permissions != "" {
_, _ = fmt.Sscanf(desiredProps.Permissions, "%o", &perm)
}
// Upload new content (blocks until complete)
opID := client.StartUpload(req.NativeID, desiredProps.Content, perm)
// Wait for completion
for {
op, err := client.GetStatus(opID)
if err != nil {
return &resource.UpdateResult{
ProgressResult: &resource.ProgressResult{
Operation: resource.OperationUpdate,
OperationStatus: resource.OperationStatusFailure,
ErrorCode: resource.OperationErrorCodeInternalFailure,
StatusMessage: err.Error(),
},
}, nil
}
if op.State == asyncsftp.StateCompleted {
break
}
if op.State == asyncsftp.StateFailure {
return &resource.UpdateResult{
ProgressResult: &resource.ProgressResult{
Operation: resource.OperationUpdate,
OperationStatus: resource.OperationStatusFailure,
ErrorCode: resource.OperationErrorCodeInternalFailure,
StatusMessage: op.Error,
},
}, nil
}
}
} else if priorProps.Permissions != desiredProps.Permissions {
// Only permissions changed - use chmod
var perm os.FileMode = 0644
_, _ = fmt.Sscanf(desiredProps.Permissions, "%o", &perm)
if err := client.SetPermissions(req.NativeID, perm); err != nil {
return &resource.UpdateResult{
ProgressResult: &resource.ProgressResult{
Operation: resource.OperationUpdate,
OperationStatus: resource.OperationStatusFailure,
ErrorCode: resource.OperationErrorCodeInternalFailure,
StatusMessage: err.Error(),
},
}, nil
}
}
// Read back the updated file to return current state
fileInfo, err := client.ReadFile(req.NativeID)
if err != nil {
return &resource.UpdateResult{
ProgressResult: &resource.ProgressResult{
Operation: resource.OperationUpdate,
OperationStatus: resource.OperationStatusFailure,
ErrorCode: resource.OperationErrorCodeInternalFailure,
StatusMessage: err.Error(),
},
}, nil
}
resourceProps, _ := json.Marshal(FileProperties{
Path: fileInfo.Path,
Content: fileInfo.Content,
Permissions: fileInfo.Permissions,
Size: fileInfo.Size,
ModifiedAt: fileInfo.ModifiedAt.Format("2006-01-02T15:04:05Z07:00"),
})
return &resource.UpdateResult{
ProgressResult: &resource.ProgressResult{
Operation: resource.OperationUpdate,
OperationStatus: resource.OperationStatusSuccess,
NativeID: req.NativeID,
ResourceProperties: resourceProps,
},
}, nil
}