FromReader updates in place the binary of the instance manager, replacing itself with a new version with the new binary
( cancelFunc context.CancelFunc, exitedCondition concurrency.MultipleExecuted, typedClient client.Client, instance *postgres.Instance, r io.Reader, )
| 51 | // FromReader updates in place the binary of the instance manager, replacing itself |
| 52 | // with a new version with the new binary |
| 53 | func FromReader( |
| 54 | cancelFunc context.CancelFunc, |
| 55 | exitedCondition concurrency.MultipleExecuted, |
| 56 | typedClient client.Client, |
| 57 | instance *postgres.Instance, |
| 58 | r io.Reader, |
| 59 | ) error { |
| 60 | // Create a temporary file to host the new instance manager binary |
| 61 | updatedInstanceManager, err := os.CreateTemp(UploadFolder, "manager_*.new") |
| 62 | if err != nil { |
| 63 | return fmt.Errorf( |
| 64 | "while creating a temporary file to host the new version of the instance manager: %w", err) |
| 65 | } |
| 66 | defer func() { |
| 67 | // This code is executed only if the instance manager has not been updated, and |
| 68 | // this is the only condition we have a temporary file to remove |
| 69 | removeError := os.Remove(updatedInstanceManager.Name()) //nolint:gosec // path from our own temp file |
| 70 | if removeError != nil { |
| 71 | log.Warning("Error while removing temporary instance manager upload file", |
| 72 | "name", updatedInstanceManager.Name(), "err", err) |
| 73 | } |
| 74 | }() |
| 75 | |
| 76 | // Read the new instance manager version |
| 77 | newHash, err := downloadAndCloseInstanceManagerBinary(updatedInstanceManager, r) |
| 78 | if err != nil { |
| 79 | return fmt.Errorf("while reading new instance manager binary: %w", err) |
| 80 | } |
| 81 | |
| 82 | // Validate the hash of this instance manager |
| 83 | if err := validateInstanceManagerHash(typedClient, |
| 84 | instance.GetClusterName(), instance.GetNamespaceName(), |
| 85 | instance.GetArchitecture(), newHash); err != nil { |
| 86 | return fmt.Errorf("while validating instance manager binary: %w", err) |
| 87 | } |
| 88 | |
| 89 | log.Info("Received new version of the instance manager", |
| 90 | "hashCode", newHash, |
| 91 | "temporaryName", updatedInstanceManager.Name()) |
| 92 | |
| 93 | // Grant the executable bit to the new file |
| 94 | err = os.Chmod(updatedInstanceManager.Name(), 0o755) //nolint:gosec // path from our own temp file |
| 95 | if err != nil { |
| 96 | return fmt.Errorf("while granting the executable bit to the instance manager binary: %w", err) |
| 97 | } |
| 98 | |
| 99 | // Replace the new instance manager with the new one |
| 100 | //nolint:gosec // path from our own temp file |
| 101 | if err := os.Rename(updatedInstanceManager.Name(), InstanceManagerPath); err != nil { |
| 102 | return fmt.Errorf("while replacing instance manager binary: %w", err) |
| 103 | } |
| 104 | |
| 105 | // We are ready to reload the instance manager |
| 106 | // First we are going to cancel the context, this will trigger the shutdown of all |
| 107 | // the Runnables handled by the manager. |
| 108 | // Only the postgres process will not be actually killed, as the postgres lifecycle |
| 109 | // manager will not kill it if InstanceManagerIsUpgrading is set to true. |
| 110 | cancelFunc() |
no test coverage detected