Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

00761-mirror-node-bug [branch] #776

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions charts/fullstack-deployment/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,9 @@ hedera-mirror-node:
name: "{{ .Release.Name }}-redis"
- secretRef:
name: uploader-mirror-secrets
# This is a single node address book, node account id = 0.0.3
# The addressbook.bin file updates will be handled by infrastructure code
addressBook: CvYGCgwxMC45Ni4xMzEuMzYaBTAuMC4zIswGMzA4MjAxYTIzMDBkMDYwOTJhODY0ODg2ZjcwZDAxMDEwMTA1MDAwMzgyMDE4ZjAwMzA4MjAxOGEwMjgyMDE4MTAwYTEyMDA2ZjI1MjcyNDJjZDdmNTNiOWM0ZmQ1ZGU4NjljNTYyZmY0ZWQ4YTRhYjNhNjI5NjNmM2Y4MTg4YmU3OGYyNThlYWY0MmI5YzNlM2U4ZjU4Njk3MTYwNDEzYmJmNzdhYWRmYWYwZDlmZmQ4Njk4NGIzYmM0ZmI1ZjAyZTExZThhY2I2ZWM2N2U0MjY0YWRkY2ExM2ZmZGU4MzY3NTc4YzI3OTJmYzZhZTMyNmU3YjM0ODU2ZDIzZjAyNTc0ZjVhMjc0ODE1NjAwMzJkNzM3NDlkYWY5ZDMzMmE3ODgzNTEwZTYwZWEyMjI4ODlhM2JmYzNiZWRmMzUwZjNhMzZjYWRhMzliOTQ1MzljNzRmYjgyNjU2NzhiZDVjMTQ4ZmJjOTE2OWFkY2FjZjY3MTliOTJlZThkNDJhOWQyZjg5MjNjYzRmZTNiNDk0YzQ2N2Y0ZTk4YTJhNDllMGEwZWY1YWE0MzNjYmVjNDM4YmFhMjU2YWU2MWEwNTkwY2U0ZTY3ZDBiM2ZlNWYyZGE5YWQ5MGMyNmUyMjlkMjhkNjc5NDU2OTc4ZDY1NzM1NzNlYmI0NjIzOWJhZDRhYmZhYjRmZmU2NGVhNGEzOTdjNmJjNWY3MTc1ZTFhYzM2NDg4ZjE3YzY3NzNiNWVkOTM0MTVlNTdjNDFjNmNkODg2NmRiZDEyMzYwMDYyMzM5Y2IxNTRkODVhZDFhZWNkMWQ3NjBhMDk0MWQ4MGUyOGZlMjQ2MDMzYTg2OGRiYmM4OTc1ZjM2MDQ0MzFmY2U5YWY5MWRjNDI1NDBhYjA0YjFiYmVjMjFmMzVmNzVmMzBhZjZmMDVjODk4NjQyOTM4NmUyYjQzOWJmZDJmZDU5MTJjODI2MDA4MDFlOWMwODU3ZjE2NWU4ODdmMjIzM2RjMmMwOThiYTEyNjdiMDU5ZGI4YTJkYjcxNGZlNTA2NjhkYmYwOTM2MDRhNWRmM2MyMzIxNDY3MjMyMTFjZTU4NTUyNjM4ZmFlOWZjMDY0YTdmMDliMDIwMzAxMDAwMTICGANCCgoECmCDJBC/hwNQAQ==
# This is a corrupted addressbook to prevent mirror importer from starting correctly
# The addressbook.bin file updates will be handled by infrastructure code or solo
addressBook: ZmFpbC1pbXBvcnRlci1zdGFydC11cAo=
config:
# importer is a springboot app, its application.yaml configuration starts here
# This config is mounted at [/usr/etc/hedera/application.yaml] in the importer pod
Expand Down
8 changes: 5 additions & 3 deletions solo/package-lock.json

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

2 changes: 2 additions & 0 deletions solo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"author": "Swirlds Labs",
"license": "Apache2.0",
"dependencies": {
"@hashgraph/proto": "^2.14.0-beta.3",
"@hashgraph/sdk": "^2.40.0",
"@kubernetes/client-node": "^0.20.0",
"@listr2/prompt-adapter-enquirer": "^1.0.2",
Expand All @@ -37,6 +38,7 @@
"figlet": "^1.7.0",
"got": "^13.0.0",
"inquirer": "^9.2.12",
"js-base64": "^3.7.6",
"listr2": "^7.0.2",
"tar": "^6.2.0",
"uuid": "^9.0.1",
Expand Down
40 changes: 39 additions & 1 deletion solo/src/core/account_manager.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
* limitations under the License.
*
*/
import * as HashgraphProto from '@hashgraph/proto'
import * as Base64 from 'js-base64'
import * as constants from './constants.mjs'
import {
AccountCreateTransaction,
AccountId,
AccountInfoQuery,
AccountUpdateTransaction,
Client,
Client, FileContentsQuery, FileId,
Hbar,
HbarUnit,
KeyList,
Expand Down Expand Up @@ -515,4 +517,40 @@ export class AccountManager {
throw new FullstackTestingError(errorMessage, e)
}
}

/**
* Fetch and prepare address book as a base64 string
* @param nodeClient node client
* @return {Promise<string>}
*/
async prepareAddressBookBase64 (nodeClient) {
// fetch AddressBook
const fileQuery = new FileContentsQuery().setFileId(FileId.ADDRESS_BOOK)
let addressBookBytes = await fileQuery.execute(nodeClient)

// ensure serviceEndpoint.ipAddressV4 value for all nodes in the addressBook is a 4 bytes array instead of string
// See: https://github.com/hashgraph/hedera-protobufs/blob/main/services/basic_types.proto#L1309
const addressBook = HashgraphProto.proto.NodeAddressBook.decode(addressBookBytes)
let modified = false
for (const nodeAddress of addressBook.nodeAddress) {
// overwrite ipAddressV4 as 4 bytes array if required
if (nodeAddress.serviceEndpoint[0].ipAddressV4.byteLength !== 4) {
const ipAddress = nodeAddress.serviceEndpoint[0].ipAddressV4.toString()
const parts = ipAddress.split('.')
if (parts.length !== 4) {
throw new FullstackTestingError(`expected node IP address to have 4 parts, found ${parts.length}: ${ipAddress}`)
}

nodeAddress.serviceEndpoint[0].ipAddressV4 = Uint8Array.from(parts)
modified = true
}
}

if (modified) {
addressBookBytes = HashgraphProto.proto.NodeAddressBook.encode(addressBook).finish()
}

// convert addressBook into base64
return Base64.encode(addressBookBytes)
}
}
57 changes: 57 additions & 0 deletions solo/src/core/k8.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,63 @@ export class K8 {
return this.filterItem(resp.body.items, { name })
}

/**
* Get pods by labels
* @param labels list of labels
* @return {Promise<Array<V1Pod>>}
*/
async getPodsByLabel (labels = []) {
const ns = this._getNamespace()
const labelSelector = labels.join(',')
const result = await this.kubeClient.listNamespacedPod(
ns,
undefined,
undefined,
undefined,
undefined,
labelSelector
)

return result.body.items
}

/**
* Get secrets by labels
* @param labels list of labels
* @return {Promise<Array<V1Secret>>}
*/
async getSecretsByLabel (labels = []) {
const ns = this._getNamespace()
const labelSelector = labels.join(',')
const result = await this.kubeClient.listNamespacedSecret(
ns,
undefined,
undefined,
undefined,
undefined,
labelSelector
)

return result.body.items
}

/**
* Updates a kubernetes secrets
* @param secretObject
* @return {Promise<void>}
*/
async updateSecret (secretObject) {
const ns = this._getNamespace()
try {
// patch is broke, need to use delete/create: https://github.com/kubernetes-client/javascript/issues/893
// await k8.kubeClient.patchNamespacedSecret(secret.name, ctx.config.namespace, secret.data)
await this.kubeClient.deleteNamespacedSecret(secretObject.metadata.name, ns)
await this.kubeClient.createNamespacedSecret(ns, secretObject)
} catch (e) {
throw new FullstackTestingError(`failed to update secret ${secretObject.metadata.name}: ${e.message}`, e)
}
}

/**
* Get host IP of a podName
* @param podNameName name of the podName
Expand Down
4 changes: 2 additions & 2 deletions solo/src/core/platform_installer.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ export class PlatformInstaller {
try {
// reset data directory
// Note: we cannot delete the data/stats and data/saved as those are volume mounted
const reset_paths = [
const resetPaths = [
`${constants.HEDERA_HAPI_PATH}/data/apps`,
`${constants.HEDERA_HAPI_PATH}/data/config`,
`${constants.HEDERA_HAPI_PATH}/data/keys`,
`${constants.HEDERA_HAPI_PATH}/data/lib`,
`${constants.HEDERA_HAPI_PATH}/data/upgrade`
]

for (const p of reset_paths) {
for (const p of resetPaths) {
await this.k8.execContainer(podName, containerName, `rm -rf ${p}`)
await this.k8.execContainer(podName, containerName, `mkdir ${p}`)
}
Expand Down
40 changes: 40 additions & 0 deletions solo/test/e2e/commands/02_account.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { AccountManager } from '../../../src/core/account_manager.mjs'
import { AccountCommand } from '../../../src/commands/account.mjs'
import { flags } from '../../../src/commands/index.mjs'
import { sleep } from '../../../src/core/helpers.mjs'
import * as HashgraphProto from '@hashgraph/proto'

describe('account commands should work correctly', () => {
const defaultTimeout = 20000
Expand Down Expand Up @@ -207,4 +208,43 @@ describe('account commands should work correctly', () => {
await accountCmd.closeConnections()
}
}, defaultTimeout)

it('update addressBook and restart importer', async () => {
try {
const ctx = {
config: {}
}
ctx.config.namespace = configManager.getFlag(flags.namespace)
await accountCmd.loadTreasuryAccount(ctx)
await accountCmd.loadNodeClient(ctx)

// Retrieve the AddressBook as base64
const base64NodeAddressBook = await accountManager.prepareAddressBookBase64(ctx.nodeClient)

// update kubernetes secrets
const secrets = await k8.getSecretsByLabel(['app.kubernetes.io/component=importer'])
for (const secretObject of secrets) {
delete secretObject.metadata.creationTimestamp
delete secretObject.metadata.managedFields
delete secretObject.metadata.resourceVersion
delete secretObject.metadata.uid
secretObject.data['addressbook.bin'] = base64NodeAddressBook

await k8.updateSecret(secretObject, ctx.config.namespace)
}

// restart the importer pod
const pods = await k8.getPodsByLabel(['app.kubernetes.io/component=importer'])
expect(pods.length).toBeGreaterThan(0)
for (const pod of pods) {
const resp = await k8.kubeClient.deleteNamespacedPod(pod.metadata.name, pod.metadata.namespace)
expect(resp.response.statusCode).toEqual(200)
}
} catch (e) {
testLogger.showUserError(e)
expect(e).toBeNull()
} finally {
await accountCmd.closeConnections()
}
}, defaultTimeout)
})
5 changes: 4 additions & 1 deletion solo/test/e2e/setup-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ kind delete cluster -n "${SOLO_CLUSTER_NAME}" || true
kind create cluster -n "${SOLO_CLUSTER_NAME}" || exit 1
kubectl create ns "${SOLO_NAMESPACE}" || exit 1
kubectl create ns "${SOLO_CLUSTER_SETUP_NAMESPACE}" || exit 1
solo init -d ../charts --namespace "${SOLO_NAMESPACE}" -i node0,node1,node2 -t v0.42.5 -s "${SOLO_CLUSTER_SETUP_NAMESPACE}" || exit 1 # cache args for subsequent commands
solo init -d ../charts --namespace "${SOLO_NAMESPACE}" -i node0,node1,node2 -t v0.47.0-alpha.0 -s "${SOLO_CLUSTER_SETUP_NAMESPACE}" || exit 1 # cache args for subsequent commands
solo node keys --gossip-keys --tls-keys --key-format pem || exit 1
solo cluster setup || exit 1
solo network deploy || exit 1
solo node setup || exit 1
solo node start --no-update-account-keys || exit 1
Loading