diff --git a/monitoring/healthz/src/pages/Nodes.css b/monitoring/healthz/src/pages/Nodes.css index 7cf478d73a5..0cb2f9b20ac 100644 --- a/monitoring/healthz/src/pages/Nodes.css +++ b/monitoring/healthz/src/pages/Nodes.css @@ -5,6 +5,8 @@ --unreachable-shadow-color: rgba(0, 0, 0, 0.1); --is-unhealthy-color: #fff0f0; --is-unhealthy-hover-color: rgba(255, 200, 200, 0.4); + --is-unregistered-color: #fffbe6; + --is-unregistered-hover-color: rgba(255, 255, 176, 0.4); } /* Dark mode */ @@ -15,6 +17,8 @@ --unreachable-shadow-color: rgba(255, 255, 255, 0.1); --is-unhealthy-color: #440000; --is-unhealthy-hover-color: rgba(255, 50, 50, 0.4); + --is-unregistered-color: #665500; + --is-unregistered-hover-color: rgba(255, 255, 100, 0.4); } } @@ -48,4 +52,13 @@ table tr:hover td.is-unhealthy, table tr.is-unhealthy:hover td { background: var(--is-unhealthy-hover-color); +} + +.is-unregistered { + background: var(--is-unregistered-color); +} + +table tr:hover td.is-unregistered, +table tr.is-unregistered:hover td { + background: var(--is-unregistered-hover-color); } \ No newline at end of file diff --git a/monitoring/healthz/src/pages/Nodes.tsx b/monitoring/healthz/src/pages/Nodes.tsx index d8e5104152a..bf6b7e0551e 100644 --- a/monitoring/healthz/src/pages/Nodes.tsx +++ b/monitoring/healthz/src/pages/Nodes.tsx @@ -79,34 +79,49 @@ function HealthRow({ isContent, sp, isStaging }: { isContent: boolean; sp: SP, i const health = data?.data const yourIp = ipCheck?.data - if (!health || !yourIp) + // API response doesn't include isRegistered + if (sp.isRegistered !== false) { + sp.isRegistered = true + } + + if (!health || !yourIp) { + let healthStatus = 'loading' + let healthStatusClass = '' + if (!sp.isRegistered) { + healthStatus = 'Unregistered' + healthStatusClass = 'is-unregistered' + } else if (dataError || ipCheckError) { + healthStatus = 'error' + healthStatusClass = 'is-unhealthy' + } return ( - + {sp.endpoint.replace('https://', '')} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Node Health */} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Block Diff */} - {dataError || ipCheckError ? 'error' : 'loading'} {/* Version */} - {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Storage */} - {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Fast Repair (checked, pulled, deleted) */} - {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Full Repair (checked, pulled, deleted) */} - {!isContent && {relayHealthError || ipCheckError ? 'error' : 'loading'}} {/* Relay */} - {dataError || ipCheckError ? 'error' : 'loading'} {/* DB Size */} - {dataError || ipCheckError ? 'error' : 'loading'} {/* Your IP */} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* ACDC Health */} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Is Signer */} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Peers */} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Producing */} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* ACDC Block */} - {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* ACDC Block Hash */} - {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Started */} - {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Uploads */} - {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Healthy Peers */} + {!isContent && {healthStatus}} {/* Node Health */} + {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Block Diff */} + {dataError || ipCheckError ? 'error' : 'loading'} {/* Version */} + {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Storage */} + {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Fast Repair (checked, pulled, deleted) */} + {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Full Repair (checked, pulled, deleted) */} + {!isContent && {relayHealthError || ipCheckError ? 'error' : 'loading'}} {/* Relay */} + {dataError || ipCheckError ? 'error' : 'loading'} {/* DB Size */} + {dataError || ipCheckError ? 'error' : 'loading'} {/* Your IP */} + {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* ACDC Health */} + {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Is Signer */} + {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Peers */} + {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Producing */} + {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* ACDC Block */} + {!isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* ACDC Block Hash */} + {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Started */} + {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Uploads */} + {isContent && {dataError || ipCheckError ? 'error' : 'loading'}} {/* Healthy Peers */} ) + } // calculate healthy peers counts const now = new Date() @@ -152,7 +167,7 @@ function HealthRow({ isContent, sp, isStaging }: { isContent: boolean; sp: SP, i const MAX_STORAGE_SIZE = isStaging ? 400 : 4000 const totalMediorumSize = mediorumDiskSize && health.blobStorePrefix === 'file' ? mediorumDiskSize : MAX_STORAGE_SIZE - const isBehind = health.block_difference > 5 ? 'is-unhealthy' : '' + const isBehind = 'whitespace-nowrap px-3 py-5 text-sm' + (health.block_difference > 5 ? ' is-unhealthy' : '') const dbSize = bytesToGb(health.database_size) || bytesToGb(health.databaseSize) const isDbLocalhost = health.database_is_localhost || health.isDbLocalhost @@ -188,14 +203,24 @@ function HealthRow({ isContent, sp, isStaging }: { isContent: boolean; sp: SP, i ) } + let healthStatus = 'Healthy' + let healthStatusClass = '' + if (!sp.isRegistered) { + healthStatus = 'Unregistered' + healthStatusClass = 'is-unregistered' + } else if (!isHealthy) { + healthStatus = 'Unhealthy' + healthStatusClass = 'is-unhealthy' + } + return ( - + {sp.endpoint.replace('https://', '')} - {!isContent && ({`${isHealthy ? 'Healthy' : 'Unhealthy: ' + health.errors}`})} + {!isContent && ({`${healthStatus}${healthStatus === 'Unhealthy' ? ': ' + health.errors : ''}`})} {!isContent && {health.block_difference}}
diff --git a/monitoring/healthz/src/useServiceProviders.ts b/monitoring/healthz/src/useServiceProviders.ts index f710860bf39..7e8b8d359a1 100644 --- a/monitoring/healthz/src/useServiceProviders.ts +++ b/monitoring/healthz/src/useServiceProviders.ts @@ -58,6 +58,9 @@ export function useServiceProviders( const { data: sps, error } = useSWR([env, type], async () => { const sps = await apiGatewayFetcher(env, type) hostSort(sps) + if (type === 'discovery') { + sps.push(...unregisteredNodes(env === 'prod')) + } return sps }) return { data: sps, error } @@ -76,3 +79,37 @@ export function hostSort(sps: SP[]) { new URL(sp.endpoint).hostname.split('.').reverse().join('.') sps.sort((a, b) => (hostSortKey(a) < hostSortKey(b) ? -1 : 1)) } + +function unregisteredNodes(prod: boolean) { + if (prod) { + return [ + { + delegateOwnerWallet: '0x32bF5092890bb03A45bd03AaeFAd11d4afC9a851', + endpoint: 'https://discoveryprovider4.audius.co', + isRegistered: false, + type: { id: 'discovery-node' }, + }, + { + delegateOwnerWallet: 'Metabase (no wallet)', + endpoint: 'https://insights.audius.co', + isRegistered: false, + type: { id: 'discovery-node' }, + }, + ] + } else { + return [ + { + delegateOwnerWallet: '0xb1C931A9ac123866372CEbb6bbAF50FfD18dd5DF', + endpoint: 'https://discoveryprovider4.staging.audius.co', + isRegistered: false, + type: { id: 'discovery-node' }, + }, + { + delegateOwnerWallet: 'DDEX (no wallet)', + endpoint: 'https://audius-stage.ddex.audius.co', + isRegistered: false, + type: { id: 'discovery-node' }, + }, + ] + } +}