Skip to content

Commit

Permalink
feat: node updates (must manually check for updates) (#613)
Browse files Browse the repository at this point in the history
* feat: check for node updates. only checking part completed

* release notes url. update detailed changes modal start

* checkin: rename check to getCheckForControllerUpdate. modal ready for spec diff message

* check-in: add node spec diff tool and modal with changes

* feat: appy node update with result notification

* injectDefaultControllerConfig for controllers

* fix client update notifications. client release urls

* cleanup controller api and add env var

* couple missing js endings on file imports

* feat: developer mode for dev info in app
  • Loading branch information
jgresham authored Jul 10, 2024
1 parent 33b31d8 commit 59b7b20
Show file tree
Hide file tree
Showing 45 changed files with 1,089 additions and 108 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@
"test/**/__snapshots__": true,
"package-lock.json": true,
"*.{css,sass,scss}.d.ts": true
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ SENTRY_DSN=fake-token
MP_PROJECT_TOKEN=fake-token
MP_PROJECT_ENV=dev
NICENODE_ENV=development
CONTROLLER_API_URL=http://localhost:3000/api
```

`SENTRY_DSN` and `MP_PROJECT_TOKEN` should be fake unless testing. Contact Johns, @jgresham, if you want to test new error or event reporting code.
Expand Down
6 changes: 6 additions & 0 deletions assets/locales/en/genericComponents.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"AboutSecondsRemaining": "About {{seconds}} seconds remaining",
"CheckForUpdates": "Check for updates...",
"Confirm": "Confirm",
"FinishingUp": "Finishing up...",
"Hide": "Hide",
Expand Down Expand Up @@ -55,6 +56,7 @@
"PodmanIsNotRunning": "Podman is not running",
"ClickToStartPodman": "Click to start Podman",
"UpdateAvailable": "Update available",
"Update": "Update",
"NewVersionAvailable": "New version ready to install",
"PodmanInstalling": "Installing...",
"PodmanLoading": "Loading...",
Expand Down Expand Up @@ -96,10 +98,14 @@
"SetUp": "Set up",
"SkipForNow": "Skip for now",
"UpdateClient": "Update your client",
"UpdateNamedClient": "Update {{client}}",
"UpdateStopClient": "{{client}} will stop momentarily.",
"UpdateClientDescription": "{{client}} has been downloaded and is ready to install.",
"InstallUpdate": "Install Update",
"Skip": "Skip",
"ViewReleaseNotes": "View release notes",
"ViewNamedReleaseNotes": "View {{name}} release notes",
"ViewDetailedChanges": "View detailed changes...",
"InitialSyncInProgress": "Initial sync in progress...",
"NodeSettings": "Node Settings...",
"RemoveNode": "Remove Node...",
Expand Down
4 changes: 4 additions & 0 deletions assets/locales/en/notifications.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"ClientSuccessfulyUpdatedTitle": "Client successfully updated",
"ClientSuccessfulyUpdatedDescription": "{{variable}} has been updated",
"ClientUpdateErrorTitle": "Client update error",
"ClientUpdateErrorDescription": "An error occurred while updating {{variable}}",
"LowDiskSpaceTitle": "Low disk space",
"LowDiskSpaceDescription": "Disk space is lower than 40GB",
"InternetConnectionDownTitle": "Internet connection down",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions src/common/NodeSpecs/besu/besu-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -410,12 +410,14 @@
"type": "text"
},
"infoDescription": "Set to lower number to use less bandwidth",
"documentation": "https://besu.hyperledger.org/public-networks/reference/cli/options#max-peers"
"documentation": "https://besu.hyperledger.org/public-networks/reference/cli/options#max-peers",
"releaseNotesUrl": "https://github.com/NethermindEth/nethermind/releases"
}
},
"documentation": {
"default": "https://besu.hyperledger.org/en/stable/",
"docker": "https://besu.hyperledger.org/en/stable/HowTo/Get-Started/Installation-Options/Run-Docker-Image/"
"docker": "https://besu.hyperledger.org/en/stable/HowTo/Get-Started/Installation-Options/Run-Docker-Image/",
"releaseNotesUrl": "https://github.com/hyperledger/besu/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/execution-clients/besu-text-logo.png",
"resources": [
Expand Down
4 changes: 4 additions & 0 deletions src/common/NodeSpecs/erigon/erigon-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@
},
"category": "L1/ExecutionClient",
"rpcTranslation": "eth-l1",
"documentation": {
"default": "https://erigon.tech/",
"releaseNotesUrl": "https://github.com/ledgerwatch/erigon/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/execution-clients/erigon-text-logo.png",
"resources": [
{
Expand Down
5 changes: 5 additions & 0 deletions src/common/NodeSpecs/geth/geth-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -333,5 +333,10 @@
"defaultValue": "localhost,host.containers.internal"
}
},
"documentation": {
"default": "https://geth.ethereum.org/",
"docker": "https://geth.ethereum.org/docs/getting-started/installing-geth#docker-container",
"releaseNotesUrl": "https://github.com/ethereum/go-ethereum/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/execution-clients/geth-logo.png"
}
3 changes: 2 additions & 1 deletion src/common/NodeSpecs/lighthouse/lighthouse-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@
},
"documentation": {
"default": "https://lighthouse-book.sigmaprime.io/intro.html",
"docker": "https://lighthouse-book.sigmaprime.io/docker.html"
"docker": "https://lighthouse-book.sigmaprime.io/docker.html",
"releaseNotesUrl": "https://github.com/sigp/lighthouse/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/consensus-clients/lighthouse-logo.png",
"resources": [
Expand Down
3 changes: 2 additions & 1 deletion src/common/NodeSpecs/lodestar/lodestar-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@
},
"documentation": {
"default": "https://chainsafe.github.io/lodestar/",
"docker": "https://chainsafe.github.io/lodestar/installation/#install-with-docker"
"docker": "https://chainsafe.github.io/lodestar/installation/#install-with-docker",
"releaseNotesUrl": "https://github.com/ChainSafe/lodestar/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/consensus-clients/lodestar-logo-text.png",
"resources": [
Expand Down
3 changes: 2 additions & 1 deletion src/common/NodeSpecs/nethermind/nethermind-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@
"type": "text"
},
"infoDescription": "Set to lower number to use less bandwidth",
"documentation": "https://docs.nethermind.io/nethermind/ethereum-client/configuration/network"
"documentation": "https://docs.nethermind.io/nethermind/ethereum-client/configuration/network",
"releaseNotesUrl": "https://github.com/NethermindEth/nethermind/releases"
}
},
"documentation": {
Expand Down
3 changes: 2 additions & 1 deletion src/common/NodeSpecs/nimbus/nimbus-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@
},
"documentation": {
"default": "https://nimbus.guide/",
"docker": "https://nimbus.guide/docker.html"
"docker": "https://nimbus.guide/docker.html",
"releaseNotesUrl": "https://github.com/status-im/nimbus-eth2/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/consensus-clients/nimbus-logo-text.png",
"resources": [
Expand Down
3 changes: 2 additions & 1 deletion src/common/NodeSpecs/prysm/prysm-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@
},
"documentation": {
"default": "https://docs.prylabs.network/docs/getting-started",
"docker": "https://docs.prylabs.network/docs/install/install-with-docker/"
"docker": "https://docs.prylabs.network/docs/install/install-with-docker/",
"releaseNotesUrl": "https://github.com/prysmaticlabs/prysm/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/consensus-clients/prysm-logo.png",
"resources": [
Expand Down
3 changes: 2 additions & 1 deletion src/common/NodeSpecs/reth/reth-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@
}
},
"documentation": {
"default": "https://paradigmxyz.github.io/reth"
"default": "https://paradigmxyz.github.io/reth",
"releaseNotesUrl": "https://github.com/paradigmxyz/reth/releases"
},
"resources": [
{
Expand Down
3 changes: 2 additions & 1 deletion src/common/NodeSpecs/teku/teku-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@
},
"documentation": {
"default": "https://docs.teku.consensys.net/en/stable/",
"docker": "https://docs.teku.consensys.net/en/stable/HowTo/Get-Started/Installation-Options/Run-Docker-Image/"
"docker": "https://docs.teku.consensys.net/en/stable/HowTo/Get-Started/Installation-Options/Run-Docker-Image/",
"releaseNotesUrl": "https://github.com/ConsenSys/teku/releases"
},
"iconUrl": "https://clientdiversity.org/assets/img/consensus-clients/teku-logo.png",
"resources": [
Expand Down
52 changes: 52 additions & 0 deletions src/common/node-spec-tool/injectDefaultControllerConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type {
NodeSpecification,
DockerExecution as PodmanExecution,
} from '../nodeSpec.js';

/**
* Injects default controller configuration (cliInput, serviceVersion, etc.)
* into the nodeSpec. It does NOT overwrite existing values.
* Always updated is the default serviceVersion value to spec.excution.defaultImageTag
* For example, if `cliInput` is defined, it does NOT get overwritten.
* @param nodeSpec
*/
export const injectDefaultControllerConfig = (nodeSpec: NodeSpecification) => {
// "inject" serviceVersion and dataDir (todo) here. Universal for all nodes.
const execution = nodeSpec.execution as PodmanExecution;
let defaultImageTag = 'latest';
// if the defaultImageTag is set in the spec use that, otherwise 'latest'
if (execution.defaultImageTag !== undefined) {
defaultImageTag = execution.defaultImageTag;
}

if (!nodeSpec.configTranslation) {
nodeSpec.configTranslation = {};
}

if (!nodeSpec.configTranslation.cliInput) {
nodeSpec.configTranslation.cliInput = {
displayName: `${nodeSpec.displayName} CLI input`,
uiControl: {
type: 'text',
},
defaultValue: '',
addNodeFlow: 'advanced',
infoDescription: 'Additional CLI input',
};
}
if (!nodeSpec.configTranslation.serviceVersion) {
nodeSpec.configTranslation.serviceVersion = {
displayName: `${nodeSpec.displayName} version`,
uiControl: {
type: 'text',
},
defaultValue: defaultImageTag,
addNodeFlow: 'advanced',
infoDescription:
'Possible values: latest, v1.0.0, or stable. Check service documenation.',
};
}

// always update the default serviceVersion value to the latest excution.defaultImageTag
nodeSpec.configTranslation.serviceVersion.defaultValue = defaultImageTag;
};
118 changes: 118 additions & 0 deletions src/common/node-spec-tool/specDiff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import type { SelectControl, SelectTranslation } from '../nodeConfig.js';
import type { DockerExecution, NodeSpecification } from '../nodeSpec.js';
import { assert, compareObjects } from './util.js';

export type UserSpecDiff = {
message: string;
};

// Only time a user default would be overridden is if the user default is not in the new spec as
// an option on a select config. In that case, the default should be used. So we should highlight any
// removal of select options.
// returns a list of changes
export const calcUserSpecDiff = (
oldSpec: NodeSpecification,
newSpec: NodeSpecification,
): UserSpecDiff[] => {
assert(oldSpec.specId === newSpec.specId, 'specId mismatch');
assert(
oldSpec.version < newSpec.version,
'newSpec version is not greater than oldSpec version',
);

const diffs: UserSpecDiff[] = [];
diffs.push({
message: `Controller version: ${oldSpec.version} -> ${newSpec.version}`,
});
if (oldSpec.displayName !== newSpec.displayName) {
diffs.push({
message: `Name: ${oldSpec.displayName} -> ${newSpec.displayName}`,
});
}

/////// [start] Execution
const oldSpecExecution = oldSpec.execution as DockerExecution;
const newSpecExecution = newSpec.execution as DockerExecution;
if (oldSpecExecution.imageName !== newSpecExecution.imageName) {
diffs.push({
message: `Download URL: ${oldSpecExecution.imageName} -> ${newSpecExecution.imageName}`,
});
}
if (oldSpecExecution.defaultImageTag !== newSpecExecution.defaultImageTag) {
diffs.push({
message: `${newSpec.displayName} Version: ${oldSpecExecution.defaultImageTag} -> ${newSpecExecution.defaultImageTag}`,
});
}
/////// [end] Execution

/////// [start] System Requirements
const oldSysReq = oldSpec.systemRequirements;
const newSysReq = newSpec.systemRequirements;
if (!compareObjects(oldSysReq, newSysReq)) {
let oldSysReqString = '';
let newSysReqString = '';
if (!compareObjects(oldSysReq?.cpu, newSysReq?.cpu)) {
oldSysReqString += ` CPU: ${JSON.stringify(oldSysReq?.cpu)}`;
newSysReqString += ` CPU: ${JSON.stringify(newSysReq?.cpu)}`;
}
if (!compareObjects(oldSysReq?.memory, newSysReq?.memory)) {
oldSysReqString += ` Memory: ${JSON.stringify(oldSysReq?.memory)}`;
newSysReqString += ` Memory: ${JSON.stringify(newSysReq?.memory)}`;
}
if (!compareObjects(oldSysReq?.storage, newSysReq?.storage)) {
oldSysReqString += ` Storage: ${JSON.stringify(oldSysReq?.storage)}`;
newSysReqString += ` Storage: ${JSON.stringify(newSysReq?.storage)}`;
}
if (!compareObjects(oldSysReq?.internet, newSysReq?.internet)) {
oldSysReqString += ` Internet: ${JSON.stringify(oldSysReq?.internet)}`;
newSysReqString += ` Internet: ${JSON.stringify(newSysReq?.internet)}`;
}

diffs.push({
message: `System requirements: ${oldSysReqString} -> ${newSysReqString}`,
});
}
/////// [end] System Requirements

/////// [start] Config Tralsations
const oldTranslations = oldSpec.configTranslation ?? {};
const newTranslations = newSpec.configTranslation ?? {};
const oldTranslationKeys = Object.keys(oldTranslations);
const newTranslationKeys = Object.keys(newTranslations);
for (const key of oldTranslationKeys) {
if (!newTranslationKeys.includes(key)) {
diffs.push({
message: `Removed setting: ${oldTranslations[key]?.displayName}`,
});
} else {
if (oldTranslations[key]?.uiControl?.type.includes('select')) {
const oldSelectOptions = (
oldTranslations[key].uiControl as SelectControl
)?.controlTranslations as SelectTranslation[];
const newSelectOptions = (
newTranslations[key].uiControl as SelectControl
)?.controlTranslations as SelectTranslation[];
if (!compareObjects(oldSelectOptions, newSelectOptions)) {
diffs.push({
message: `Changed setting options: ${JSON.stringify(
oldSelectOptions,
)} -> ${JSON.stringify(newSelectOptions)}`,
});
}
}

// else, they're the same
}
}
for (const key of newTranslationKeys) {
if (!oldTranslationKeys.includes(key)) {
diffs.push({
message: `New setting: ${newTranslations[key]?.displayName}`,
});
}
// else, they were compared when iterating over oldTranslationKeys
}
/////// [end] Config Tralsations

return diffs;
};
Loading

0 comments on commit 59b7b20

Please sign in to comment.