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

FEAT: Custom Installation (Delete and ADD) in JS Backend #824

Merged
merged 6 commits into from
Oct 20, 2022
Merged
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
8 changes: 5 additions & 3 deletions controls/roles/delete-service/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
keep_volumes: no
become: yes

- name: Remove Docker Image
- name: Remove Docker Image
community.docker.docker_image:
state: absent
name: "{{ service_configuration.image | split(':') | first }}"
tag: "{{ service_configuration.image | split(':') | last }}"
force_absent: yes

- name: Remove Service Config File
ansible.builtin.file:
Expand All @@ -30,8 +31,9 @@

- name: Remove Service Files
ansible.builtin.file:
path: "{{ item | first | regex_search('.*' + service) }}"
path: "{{ service_configuration.volumes | select('search', service) | first | split(':') | first | regex_search('^.*' + service) }}"
state: absent
with_items: "{{ service_configuration.volumes | select('search', service) }}"
force: true
when: "{{ service_configuration.volumes | length }}"

# EOF
2 changes: 1 addition & 1 deletion controls/roles/update-changes/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- include_tasks: "2.0-rc6/updates-20-rc3.yaml"
- include_tasks: "2.0-rc3/updates-20-rc3.yaml"
ignore_errors: yes

- include_tasks: "2.0-rc6/updates-20-rc6.yaml"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions launcher/src/backend/Monitoring.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class Monitoring {
ports: config.ports,
volumes: config.volumes,
network: config.network,
dependencies : config.dependencies,
},
};
});
Expand Down
321 changes: 296 additions & 25 deletions launcher/src/backend/ServiceManager.js

Large diffs are not rendered by default.

102 changes: 102 additions & 0 deletions launcher/src/backend/ServiceManager.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,105 @@ test('readServiceConfigurations success empty', async () => {

expect(serviceConfigs.length).toBe(0)
})

test('removeConnection String', () => {
const command = `/app/cmd/validator/validator --accept-terms-of-use=true
--beacon-rpc-provider="stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:4000"
--beacon-rpc-gateway-provider=stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:3500
--web --prater=true --datadir=/opt/app/data/db
--wallet-dir=/opt/app/data/wallets
--wallet-password-file=/opt/app/data/passwords/wallet-password
--monitoring-host=0.0.0.0 --grpc-gateway-port=7500 --grpc-gateway-host=0.0.0.0
--grpc-gateway-corsdomain="*" --monitoring-host=0.0.0.0
--monitoring-port=8081
--suggested-fee-recipient=0x0000000000000000000000000000000000000000
--graffiti-file=/opt/app/graffitis/graffitis.yaml`
const id = '42d9f0b4-257f-f71e-10fe-66c342dd4995'

const sm = new ServiceManager()
const result = sm.removeCommandConnection(command, id)

expect(result).not.toMatch(/--beacon-rpc-provider="stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:4000"/)
expect(result).not.toMatch(/--beacon-rpc-gateway-provider=stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:3500/)
expect(result).toMatch(/--beacon-rpc-provider=""/)
expect(result).toMatch(/--beacon-rpc-gateway-provider=/)
})

test('removeConnection String multiple endpoints', () => {
const command = `/app/cmd/validator/validator --accept-terms-of-use=true
--beacon-rpc-provider="stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:4000,stereum-foo:3000,stereum-bar:2000"
--beacon-rpc-gateway-provider=stereum-foo:3000,stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:3500
--web --prater=true --datadir=/opt/app/data/db
--wallet-dir=/opt/app/data/wallets
--wallet-password-file=/opt/app/data/passwords/wallet-password
--monitoring-host=0.0.0.0 --grpc-gateway-port=7500 --grpc-gateway-host=0.0.0.0
--grpc-gateway-corsdomain="*" --monitoring-host=0.0.0.0
--monitoring-port=8081
--suggested-fee-recipient=0x0000000000000000000000000000000000000000
--graffiti-file=/opt/app/graffitis/graffitis.yaml`
const id = '42d9f0b4-257f-f71e-10fe-66c342dd4995'

const sm = new ServiceManager()
const result = sm.removeCommandConnection(command, id)

expect(result).not.toMatch(/--beacon-rpc-provider="stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:4000,stereum-foo:3000,stereum-bar:2000"/)
expect(result).not.toMatch(/--beacon-rpc-gateway-provider=stereum-foo:3000,stereum-42d9f0b4-257f-f71e-10fe-66c342dd4995:3500/)
expect(result).toMatch(/--beacon-rpc-provider="stereum-foo:3000,stereum-bar:2000"/)
expect(result).toMatch(/--beacon-rpc-gateway-provider=stereum-foo:3000/)
})

test('removeConnection array single endpoint', () => {
const command = [
'--network=prater',
'--logging=INFO',
'--p2p-enabled=true',
'--p2p-port=9001',
'--validators-keystore-locking-enabled=false',
'--validators-graffiti-file=/opt/app/graffitis/graffitis.yaml',
'--ee-endpoint=http://stereum-9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d:8551',
'--ee-jwt-secret-file=/engine.jwt',
'--validators-proposer-default-fee-recipient=0x0000000000000000000000000000000000000000',
'--data-path=/opt/app/data',
'--data-storage-mode=prune',
'--rest-api-port=5051',
'--rest-api-host-allowlist=*',
'--rest-api-interface=0.0.0.0',
'--rest-api-docs-enabled=true',
'--rest-api-enabled=true',
]
const id = '9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d'

const sm = new ServiceManager()
const result = sm.removeCommandConnection(command, id)

expect(result).not.toContain('--ee-endpoint=http://stereum-9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d:8551')
expect(result).toContain('--ee-endpoint=')
})

test('removeConnection array multiple endpoints', () => {
const command = [
'--network=prater',
'--logging=INFO',
'--p2p-enabled=true',
'--p2p-port=9001',
'--validators-keystore-locking-enabled=false',
'--validators-graffiti-file=/opt/app/graffitis/graffitis.yaml',
'--ee-endpoint="http://stereum-9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d:8551,foo:3000,bar:2000"',
'--ee-jwt-secret-file=/engine.jwt',
'--validators-proposer-default-fee-recipient=0x0000000000000000000000000000000000000000',
'--data-path=/opt/app/data',
'--data-storage-mode=prune',
'--rest-api-port=5051',
'--rest-api-host-allowlist=*',
'--rest-api-interface=0.0.0.0',
'--rest-api-docs-enabled=true',
'--rest-api-enabled=true',
]
const id = '9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d'

const sm = new ServiceManager()
const result = sm.removeCommandConnection(command, id)

expect(result).not.toContain('--ee-endpoint="http://stereum-9adfdb2e-9f5b-aba4-cfde-f3483d7aac8d:8551,foo:3000,bar:2000"')
expect(result).toContain('--ee-endpoint="foo:3000,bar:2000"')
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { HetznerServer } from '../HetznerServer.js'
import { NodeConnection } from '../NodeConnection.js'
import { ServicePort, servicePortProtocol } from './ServicePort.js'
import { ServiceManager } from '../ServiceManager.js'
import { MevboostService } from './MevboostService.js'
import { FlashbotsMevBoostService } from './FlashbotsMevBoostService.js'
const log = require('electron-log')

jest.setTimeout(600000)
Expand Down Expand Up @@ -50,7 +50,7 @@ test('mevboost installation', async () => {
await nodeConnection.findStereumSettings()
await nodeConnection.prepareStereumNode(nodeConnection.settings.stereum.settings.controls_install_path);

const mevboost = MevboostService.buildByUserInput('goerli', nodeConnection.settings.stereum.settings.controls_install_path + '/mevboost')
const mevboost = FlashbotsMevBoostService.buildByUserInput('goerli', nodeConnection.settings.stereum.settings.controls_install_path + '/mevboost')
await nodeConnection.writeServiceConfiguration(mevboost.buildConfiguration())
await serviceManager.manageServiceState(mevboost.id, 'started')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { NodeService } from './NodeService'
import { ServicePortDefinition } from './SerivcePortDefinition'
import { ServiceVolume } from './ServiceVolume'

export class MevboostService extends NodeService {
export class FlashbotsMevBoostService extends NodeService {
static buildByUserInput (network) {
const image = 'flashbots/mev-boost'
const service = new MevboostService()
const service = new FlashbotsMevBoostService()
let relay_link = 'https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net' // default for mainnet
if ( network === "goerli" )
relay_link = 'https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net'
service.init(
'MevboostService',
'FlashbotsMevBoostService',
null, // id
1, // configVersion
image, // image
Expand All @@ -32,13 +32,13 @@ export class MevboostService extends NodeService {
network // network
// executionClients
// consensusClients
// MevboostService
// FlashbotsMevBoostService
)
return service
}

static buildByConfiguration (config) {
const service = new MevboostService()
const service = new FlashbotsMevBoostService()

service.initByConfig(config)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { MevboostService } from './MevboostService.js'
import { FlashbotsMevBoostService } from './FlashbotsMevBoostService.js'

test('buildConfiguration', () => {
const mbService = MevboostService.buildByUserInput().buildConfiguration()
const mbService = FlashbotsMevBoostService.buildByUserInput().buildConfiguration()

expect(mbService.image).toMatch(/flashbots\/mev-boost/)
})

test('buildByConfiguration', () => {
const mb = MevboostService.buildByConfiguration({
const mb = FlashbotsMevBoostService.buildByConfiguration({
id: '124',
service: 'MevboostService',
service: 'FlashbotsMevBoostService',
configVersion: 655,
image: 'flashbots/mev-boost:v0.8.2',
volumes: ['/opt/stereum/foo:/opt/app/data']
})

expect(mb.id).toBe('124')
expect(mb.service).toBe('MevboostService')
expect(mb.service).toBe('FlashbotsMevBoostService')
expect(mb.configVersion).toBe(655)
expect(mb.image).toBe('flashbots/mev-boost')
expect(mb.imageVersion).toBe('v0.8.2')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export class LighthouseBeaconService extends NodeService {
const service = new LighthouseBeaconService()
service.setId()
const workingDir = service.buildWorkingDir(dir)
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath

const image = 'sigp/lighthouse'

Expand All @@ -19,8 +18,11 @@ export class LighthouseBeaconService extends NodeService {
const volumes = [
new ServiceVolume(workingDir + '/beacon', dataDir),
new ServiceVolume(workingDir + '/slasher', slasherDir),
new ServiceVolume(elJWTDir, JWTDir)
]
if(executionClients && executionClients.length > 0){
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath
volumes.push(new ServiceVolume(elJWTDir, JWTDir))
}

// eth1 nodes
const eth1Nodes = (executionClients.map(client => { return client.buildExecutionClientEngineRPCHttpEndpointUrl() })).join()
Expand Down
7 changes: 5 additions & 2 deletions launcher/src/backend/ethereum-services/NimbusBeaconService.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export class NimbusBeaconService extends NodeService {
const service = new NimbusBeaconService()
service.setId()
const workingDir = service.buildWorkingDir(dir)
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath

const image = 'statusim/nimbus-eth2'

Expand All @@ -21,9 +20,13 @@ export class NimbusBeaconService extends NodeService {
new ServiceVolume(workingDir + '/beacon', dataDir),
new ServiceVolume(workingDir + '/validator/validators', validatorsDir),
new ServiceVolume(workingDir + '/validator/secrets', secretsDir),
new ServiceVolume(elJWTDir, JWTDir),
]

if(executionClients && executionClients.length > 0){
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath
volumes.push(new ServiceVolume(elJWTDir, JWTDir))
}

service.init(
'NimbusBeaconService', //service
service.id, // id,
Expand Down
2 changes: 1 addition & 1 deletion launcher/src/backend/ethereum-services/NodeService.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class NodeService {
this.imageVersion = imageVersion
this.command = (command === undefined || command === null) ? [] : command
this.entrypoint = (entrypoint === undefined || entrypoint === null) ? [] : entrypoint
this.env = (env === undefined || env === null) ? { STEREUM_DUMMY: 'foobar' } : env
this.env = (env === undefined || env === null) ? {} : env
this.ports = (ports === undefined || ports === null) ? [] : ports
this.volumes = (volumes === undefined || volumes === null) ? [] : volumes
this.user = (user === undefined || user === null) ? '2000' : user
Expand Down
7 changes: 5 additions & 2 deletions launcher/src/backend/ethereum-services/PrysmBeaconService.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export class PrysmBeaconService extends NodeService {
const service = new PrysmBeaconService()
service.setId()
const workingDir = service.buildWorkingDir(dir)
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath


const image = 'prysmaticlabs/prysm-beacon-chain'
Expand All @@ -20,9 +19,13 @@ export class PrysmBeaconService extends NodeService {
const volumes = [
new ServiceVolume(workingDir + '/beacon', dataDir),
new ServiceVolume(workingDir + '/genesis', genesisDir),
new ServiceVolume(elJWTDir, JWTDir)
]

if(executionClients && executionClients.length > 0){
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath
volumes.push(new ServiceVolume(elJWTDir, JWTDir))
}

let genesisFile = ' --genesis-state=/opt/app/genesis/prysm-prater-genesis.ssz'
if(network === "mainnet"){
genesisFile = ''
Expand Down
7 changes: 5 additions & 2 deletions launcher/src/backend/ethereum-services/TekuBeaconService.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export class TekuBeaconService extends NodeService {
const service = new TekuBeaconService()
service.setId()
const workingDir = service.buildWorkingDir(dir)
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath

const image = 'consensys/teku'

Expand All @@ -19,10 +18,14 @@ export class TekuBeaconService extends NodeService {

const volumes = [
new ServiceVolume(workingDir + '/data', dataDir),
new ServiceVolume(elJWTDir, JWTDir),
new ServiceVolume(workingDir + '/graffitis', graffitiDir)
]

if(executionClients && executionClients.length > 0){
const elJWTDir = (executionClients[0].volumes.find(vol => vol.servicePath === '/engine.jwt')).destinationPath
volumes.push(new ServiceVolume(elJWTDir, JWTDir))
}

service.init(
'TekuBeaconService', // service
service.id, // id
Expand Down
27 changes: 18 additions & 9 deletions launcher/src/components/UI/node-header/MainNavbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export default {
},
methods: {
refreshServiceStates: async function () {
const allServices = JSON.parse(JSON.stringify(this.allServices));
if (await this.checkConnection()) {
if (this.refresh) {
let services = await ControlService.refreshServiceInfos();
Expand All @@ -77,7 +78,7 @@ export default {
s.config.serviceID === service.config.serviceID
);
} else {
oldService = this.allServices.find(
oldService = allServices.find(
(s) => s.service === service.service
);
needForTunnel.push(oldService);
Expand All @@ -92,21 +93,25 @@ export default {
}
oldService.state = service.state;
if (oldService.name === "Teku" || oldService.name === "Nimbus") {
let vs = this.allServices.find(
(element) =>
element.service === oldService.name + "ValidatorService"
);
let existing = this.installedServices.find(s => s.config.serviceID === oldService.config.serviceID && s.service === oldService.name + "ValidatorService")
let vs
if(existing){
vs = existing
}else{
vs = allServices.find(
(element) =>
element.service === oldService.name + "ValidatorService"
);
}
vs.config = oldService.config;
vs.state = oldService.state;
otherServices.push(vs);
}
return oldService;
});
this.installedServices = newServices.concat(otherServices).map((e,i) => {e.id = i;return e});
let beaconService = this.installedServices.find(
(s) => s.category === "consensus"
);
if (beaconService && beaconService.config.network === "mainnet") {
let networks = this.installedServices.map(s => s.config.network);
if (networks && networks.includes("mainnet") ) {
this.network = "mainnet";
this.currentNetwork = this.networkList.find(item => item.network === "mainnet")
} else {
Expand Down Expand Up @@ -185,6 +190,9 @@ export default {
this.isUpdateAvailable = false;
if (response && services && services.length > 0) {
services.forEach((service) => {
if(!response[service.network][service.service])
service.network = "prater"
if(response[service.network][service.service]){
if (
service.imageVersion !=
response[service.network][service.service][
Expand All @@ -205,6 +213,7 @@ export default {
});
console.log("Service Update Available!");
}
}
});
}

Expand Down
Loading