diff options
20 files changed, 574 insertions, 247 deletions
diff --git a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py index 2d233150..ab31fb39 100644 --- a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py +++ b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py @@ -39,6 +39,7 @@ import threading import time import urllib import signal + from opengnsys import REST from opengnsys import operations from opengnsys.log import logger @@ -46,6 +47,25 @@ from opengnsys.workers import ServerWorker from six.moves.urllib import parse +# Check authorization header decorator +def check_secret(fnc): + """ + Decorator to check for received secret key and raise exception if it isn't valid. + """ + def wrapper(*args, **kwargs): + try: + this, path, get_params, post_params, server = args # @UnusedVariable + if this.random == server.headers['Authorization']: + fnc(*args, **kwargs) + else: + raise Exception('Unauthorized operation') + except Exception as e: + logger.error(e) + raise Exception(e) + + return wrapper + + # Error handler decorator. def catch_background_error(fnc): def wrapper(*args, **kwargs): @@ -92,7 +112,6 @@ class OpenGnSysWorker(ServerWorker): interface = None # Bound interface for OpenGnsys REST = None # REST object loggedin = False # User session flag - locked = {} # Locked partitions browser = {} # Browser info commands = [] # Running commands random = None # Random string for secure connections @@ -100,30 +119,24 @@ class OpenGnSysWorker(ServerWorker): access_token = refresh_token = None # Server authorization tokens grant_type = 'http://opengnsys.es/grants/og_client' - def _check_secret(self, server): - """ - Checks for received secret key and raise exception if it isn't valid. - """ - try: - if self.random != server.headers['Authorization']: - raise Exception('Unauthorized operation') - except Exception as e: - logger.error(e) - raise Exception(e) - def _launch_browser(self, url): """ Launchs the Browser with specified URL :param url: URL to show """ logger.debug('Launching browser with URL: {}'.format(url)) - if hasattr(self.browser, 'process'): - self.browser['process'].kill() - os.kill(self.browser['process'].pid, signal.SIGINT) + # Trying to kill an old browser + try: + os.kill(self.browser['process'].pid, signal.SIGKILL) + except OSError: + logger.warn('Cannot kill the old browser process') + except KeyError: + # There is no previous browser + pass self.browser['url'] = url self.browser['process'] = subprocess.Popen(['browser', '-qws', url]) - def _task_command(self, route, code, op_id): + def _task_command(self, route, code, op_id, send_config=False): """ Task to execute a command and return results to a server URI :param route: server callback REST route to return results @@ -136,20 +149,25 @@ class OpenGnSysWorker(ServerWorker): if os_type == 'oglive': menu_url = self.browser['url'] self._launch_browser('http://localhost/cgi-bin/httpd-log.sh') - # Executing command + # Execute the code (stat, out, err) = operations.exec_command(code) - # Removing command from the list + # Remove command from the list for c in self.commands: if c.getName() == op_id: self.commands.remove(c) - # Removing the REST API prefix, if needed + # Remove the REST API prefix, if needed if route.startswith(self.REST.endpoint): route = route[len(self.REST.endpoint):] - # Sending results + # Send back exit status and outputs (base64-encoded) self.REST.sendMessage(route, {'mac': self.interface.mac, 'ip': self.interface.ip, 'trace': op_id, - 'status': stat, 'output': out.encode('base64'), 'error': err.encode('base64')}) + 'status': stat, 'output': out.encode('utf8').encode('base64'), + 'error': err.encode('utf8').encode('base64')}) # Show latest menu, if OGAgent runs on ogLive if os_type == 'oglive': + # Send configuration data, if needed + if send_config: + self.REST.sendMessage('clients/configs', {'mac': self.interface.mac, 'ip': self.interface.ip, + 'config': operations.get_configuration()}) self._launch_browser(menu_url) def onActivation(self): @@ -231,7 +249,7 @@ class OpenGnSysWorker(ServerWorker): <html> <head></head> <body> -<h1>Initializing...</h1> +<h1 style="margin: 5em; font-size: xx-large;">OpenGnsys 3</h1> </body> </html>""" f = open('/tmp/init.html', 'w') @@ -312,7 +330,12 @@ class OpenGnSysWorker(ServerWorker): def process_status(self, path, get_params, post_params, server): """ - Returns client status (OS type and login status). + Returns client status (OS type or execution status) and login status. + :param path: + :param get_params: + :param post_params: + :param server: + :return: JSON object {"status": "status_code", "loggedin": boolean} """ res = {'loggedin': self.loggedin} try: @@ -320,32 +343,42 @@ class OpenGnSysWorker(ServerWorker): except KeyError: res['status'] = '' # Check if OpenGnsys Client is busy - if res['status'] == 'oglive' and self.locked: + if res['status'] == 'oglive' and len(self.commands) > 0: res['status'] = 'busy' return res + @check_secret def process_reboot(self, path, get_params, post_params, server): """ Launches a system reboot operation. + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} """ logger.debug('Received reboot operation') - self._check_secret(server) - # Rebooting thread. + # Rebooting thread def rebt(): operations.reboot() threading.Thread(target=rebt).start() return {'op': 'launched'} + @check_secret def process_poweroff(self, path, get_params, post_params, server): """ Launches a system power off operation. + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} """ logger.debug('Received poweroff operation') - self._check_secret(server) - # Powering off thread. + # Powering off thread def pwoff(): time.sleep(2) operations.poweroff() @@ -353,24 +386,30 @@ class OpenGnSysWorker(ServerWorker): threading.Thread(target=pwoff).start() return {'op': 'launched'} + @check_secret def process_script(self, path, get_params, post_params, server): """ Processes an script execution (script should be encoded in base64) + :param path: + :param get_params: + :param post_params: JSON object {"redirect_uri, "uri", "script": "commands", "id": trace_id} + :param server: authorization header + :return: JSON object {"op": "launched"} or {"error": "message"} """ logger.debug('Processing script request') - self._check_secret(server) # Processing data try: script = urllib.unquote(post_params.get('script').decode('base64')).decode('utf8') op_id = post_params.get('id') - route = post_params.get('redirect_uri') - # Checking if the thread id. exists + route = post_params.get('redirectUri') + send_config = (post_params.get('sendConfig', 'false') == 'true') + # Check if the thread id. exists for c in self.commands: if c.getName() == str(op_id): raise Exception('Task id. already exists: {}'.format(op_id)) if post_params.get('client', 'false') == 'false': # Launching a new thread - thr = threading.Thread(name=op_id, target=self._task_command, args=(route, script, op_id)) + thr = threading.Thread(name=op_id, target=self._task_command, args=(route, script, op_id, send_config)) thr.start() self.commands.append(thr) else: @@ -381,43 +420,43 @@ class OpenGnSysWorker(ServerWorker): return {'error': e} return {'op': 'launched'} + @check_secret def process_logoff(self, path, get_params, post_params, server): """ Closes user session. """ logger.debug('Received logoff operation') - self._check_secret(server) - # Sending log off message to OGAgent client. + # Send log off message to OGAgent client. self.sendClientMessage('logoff', {}) return {'op': 'sent to client'} + @check_secret def process_popup(self, path, get_params, post_params, server): """ Shows a message popup on the user's session. """ logger.debug('Received message operation') - self._check_secret(server) - # Sending popup message to OGAgent client. + # Send popup message to OGAgent client. self.sendClientMessage('popup', post_params) return {'op': 'launched'} def process_client_popup(self, params): self.REST.sendMessage('popup_done', params) + @check_secret def process_config(self, path, get_params, post_params, server): """ Returns client configuration :param path: :param get_params: :param post_params: - :param server: - :return: object + :param server: authorization header + :return: JSON object """ serialno = '' # Serial number storage = [] # Storage configuration warnings = 0 # Number of warnings logger.debug('Received getconfig operation') - # self._check_secret(server) # Processing data for row in operations.get_configuration().split(';'): cols = row.split(':') @@ -443,65 +482,42 @@ class OpenGnSysWorker(ServerWorker): logger.warn('Configuration parameter error: {}'.format(cols)) warnings += 1 else: - # Logging warnings + # Log warnings logger.warn('Configuration data error: {}'.format(cols)) warnings += 1 - # Returning configuration data and count of warnings + # Return configuration data and count of warnings return {'serialno': serialno, 'storage': storage, 'warnings': warnings} - def process_command(self, path, get_params, post_params, server): - """ - Launches a thread to executing a command - :param path: ignored - :param get_params: ignored - :param post_params: object with format: - id: operation id. - script: command code - redirect_url: callback REST route - :param server: headers data - :rtype: object with launching status - """ - logger.debug('Received command operation with params: {}'.format(post_params)) - self._check_secret(server) - # Processing data - try: - script = post_params.get('script') - op_id = post_params.get('id') - route = post_params.get('redirect_url') - # Checking if the thread id. exists - for c in self.commands: - if c.getName() == str(op_id): - raise Exception('Task id. already exists: {}'.format(op_id)) - # Launching a new thread - thr = threading.Thread(name=op_id, target=self.task_command, args=(script, route, op_id)) - thr.start() - self.commands.append(thr) - except Exception as e: - logger.error('Got exception {}'.format(e)) - return {'error': e} - return {'op': 'launched'} - + @check_secret def process_execinfo(self, path, get_params, post_params, server): """ Returns running commands information :param path: :param get_params: :param post_params: - :param server: - :return: object + :param server: authorization header + :return: JSON array: [["callback_url", "commands", trace_id], ...] """ data = [] logger.debug('Received execinfo operation') - self._check_secret(server) - # Returning the arguments of all running threads + # Return the arguments of all running threads for c in self.commands: if c.is_alive(): data.append(c.__dict__['_Thread__args']) return data + @check_secret def process_stopcmd(self, path, get_params, post_params, server): + """ + Stops a running process identified by its trace id. + :param path: + :param get_params: + :param post_params: JSON object {"trace": trace_id} + :param server: authorization header + :return: JSON object: {"stopped": trace_id} + """ logger.debug('Received stopcmd operation with params {}:'.format(post_params)) - self._check_secret(server) + # Find operation id. and stop the thread op_id = post_params.get('trace') for c in self.commands: if c.is_alive() and c.getName() == str(op_id): diff --git a/admin/WebConsole3/frontend/src/app/api/repository.service.ts b/admin/WebConsole3/frontend/src/app/api/repository.service.ts index 1561f41a..55fd88a0 100644 --- a/admin/WebConsole3/frontend/src/app/api/repository.service.ts +++ b/admin/WebConsole3/frontend/src/app/api/repository.service.ts @@ -1,27 +1,27 @@ -import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { Repository } from '../model/repository';
-import { RepositorySerializer } from '../serializer/repository.serializer';
-
-import {ResourceService} from 'globunet-angular/core/providers/api/resource.service';
-import {Observable} from 'rxjs';
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class RepositoryService extends ResourceService<Repository> {
-
- constructor(http: HttpClient) {
- super(http, environment.API_URL, 'repositories', new RepositorySerializer());
- }
-
- getInfo(repository: Repository) {
- const url = 'https://' + repository.ip + '/' + environment.BASE_DIR + environment.API_BASE_URL;
- return this.httpClient.get(url, {headers: {
- Authorization: repository.password
- }});
- }
-}
+import { Injectable } from '@angular/core'; +import { HttpClient} from '@angular/common/http'; + +import { environment } from '../../environments/environment'; +import { Repository } from '../model/repository'; +import { RepositorySerializer } from '../serializer/repository.serializer'; + +import {ResourceService} from 'globunet-angular/core/providers/api/resource.service'; +import {Observable} from 'rxjs'; + + +@Injectable({ + providedIn: 'root' +}) +export class RepositoryService extends ResourceService<Repository> { + + constructor(http: HttpClient) { + super(http, environment.API_URL, 'repositories', new RepositorySerializer()); + } + + getInfo(repository: Repository) { + const url = 'https://' + repository.ip + '/' + environment.BASE_DIR + environment.API_BASE_URL; + return this.httpClient.get(url, {headers: { + Authorization: repository.randomId + }}); + } +} diff --git a/admin/WebConsole3/frontend/src/app/api/software-component.service.ts b/admin/WebConsole3/frontend/src/app/api/software-component.service.ts index b154d41a..515f1cb4 100644 --- a/admin/WebConsole3/frontend/src/app/api/software-component.service.ts +++ b/admin/WebConsole3/frontend/src/app/api/software-component.service.ts @@ -14,7 +14,7 @@ import {ResourceService} from "globunet-angular/core/providers/api/resource.serv export class SoftwareComponentService extends ResourceService<SoftwareComponent> { constructor(http: HttpClient){ - super(http, environment.API_URL,"softwarecomponents", new SoftwareComponentSerializer()); + super(http, environment.API_URL,"softwares", new SoftwareComponentSerializer()); } } diff --git a/admin/WebConsole3/frontend/src/app/api/software-type.service.ts b/admin/WebConsole3/frontend/src/app/api/software-type.service.ts index ccc6eb8f..1c250b91 100644 --- a/admin/WebConsole3/frontend/src/app/api/software-type.service.ts +++ b/admin/WebConsole3/frontend/src/app/api/software-type.service.ts @@ -1,20 +1,36 @@ -import { Injectable } from '@angular/core'; -import { HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; -import { environment } from '../../environments/environment'; -import { SoftwareType } from "../model/software-type"; -import { SoftwareTypeSerializer } from "../serializer/software-type.serializer"; +import {environment} from '../../environments/environment'; +import {SoftwareType} from '../model/software-type'; +import {SoftwareTypeSerializer} from '../serializer/software-type.serializer'; -import {ResourceService} from "globunet-angular/core/providers/api/resource.service"; +import {ResourceService} from 'globunet-angular/core/providers/api/resource.service'; +import {QueryOptions} from 'globunet-angular/core/providers/api/query-options'; +import {Observable} from 'rxjs'; +import {OgCommonService} from '../service/og-common.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root' }) export class SoftwareTypeService extends ResourceService<SoftwareType> { - constructor(http: HttpClient){ - super(http, environment.API_URL,"softwaretypes", new SoftwareTypeSerializer()); - } + constructor(http: HttpClient, private ogCommonService: OgCommonService) { + super(http, environment.API_URL, 'softwaretypes', new SoftwareTypeSerializer()); + } + + list(queryOptions?: QueryOptions): Observable<SoftwareType[]> { + return new Observable<SoftwareType[]>((observer) => { + this.ogCommonService.loadEngineConfig().subscribe( + data => { + observer.next(data.constants.sofwaretypes); + }, + error => { + observer.error(error); + } + ); + }); + } } diff --git a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html index 31b4286d..23cdb7e0 100644 --- a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html +++ b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html @@ -9,7 +9,7 @@ </mk-dropdown-toggle> <mk-dropdown-menu> <li class="header" *ngIf="executionTasks.length > 0"> - <span translate="you_have_x_exectution_taks" translate-values="{values: executionTasks.length}"></span> + <span translate="you_have_x_exectution_taks" [translateParams]="{values: executionTasks.length}"></span> </li> <li *ngIf="executionTasks.length > 0"> <!-- inner menu: contains the actual data --> @@ -21,7 +21,7 @@ </a> <a href="javascript:void(0)" (click)="relaunchExecutionTask(task)" class="btn btn-sm pull-right small-box-footer"> <i class="fa fa-refresh"></i> - </a>A + </a> </div> <a href="javascript:void(0)" (click)="ogCommandsService.execute('REALTIME_LOG', {clientIp: task.client.ip})"> <i class="fa fa-warning text-yellow"></i> {{task.client.name}} ({{task.client.ip}})<br>{{task.commandType|translate}} diff --git a/admin/WebConsole3/frontend/src/app/form-type/software-profile.form-type.ts b/admin/WebConsole3/frontend/src/app/form-type/software-profile.form-type.ts new file mode 100644 index 00000000..baa16afe --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/form-type/software-profile.form-type.ts @@ -0,0 +1,12 @@ +import {GlobunetFormType} from './globunet.form-type'; +import {SoftwareProfile} from '../model/software-profile'; + + +export class SoftwareProfileFormType extends GlobunetFormType { + getForm() { + const formType = GlobunetFormType.getForm(new SoftwareProfile()); + this.setFieldType(formType, 'description', 'textarea'); + this.removeField(formType, 'softwares'); + return formType; + } +} diff --git a/admin/WebConsole3/frontend/src/app/model/command.ts b/admin/WebConsole3/frontend/src/app/model/command.ts index 2c5697aa..5fc44734 100644 --- a/admin/WebConsole3/frontend/src/app/model/command.ts +++ b/admin/WebConsole3/frontend/src/app/model/command.ts @@ -1,9 +1,10 @@ import { Resource } from 'globunet-angular/core/models/api/resource'; -export class Excecution { +export class Execution { script = ''; clients = ''; type = ''; + sendConfig = false; } export class Command extends Resource { diff --git a/admin/WebConsole3/frontend/src/app/model/software-profile.ts b/admin/WebConsole3/frontend/src/app/model/software-profile.ts index 5b3ba732..6d411f20 100644 --- a/admin/WebConsole3/frontend/src/app/model/software-profile.ts +++ b/admin/WebConsole3/frontend/src/app/model/software-profile.ts @@ -1,6 +1,8 @@ -import { Resource } from 'globunet-angular/core/models/api/resource';
-
-export class SoftwareProfile extends Resource {
- description: string;
- comments: string;
-}
+import { Resource } from 'globunet-angular/core/models/api/resource'; +import {SoftwareComponent} from './software-component'; + +export class SoftwareProfile extends Resource { + description = ''; + comments = ''; + public softwares: SoftwareComponent[] = []; +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts index 8f018e33..e97d20fa 100644 --- a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts @@ -10,7 +10,7 @@ import {User} from '../../../model/user'; import {OGCommandsService} from '../../../service/og-commands.service'; import {CommandService} from '../../../api/command.service'; import {Image} from '../../../model/image'; -import {Command, Excecution} from '../../../model/command'; +import {Command, Execution} from '../../../model/command'; import {Client, Partition} from '../../../model/client'; import {Repository} from '../../../model/repository'; import {RepositoryService} from '../../../api/repository.service'; @@ -26,7 +26,7 @@ export class CreateImageCommandComponent implements OnInit { private readonly user: User; private constants: any; public repositories: Repository[]; - public execution = new Excecution(); + public execution = new Execution(); public commands: Command[] = []; public client: Client; public images = []; diff --git a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts index efc14d6d..fb238868 100644 --- a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts @@ -10,7 +10,7 @@ import {User} from '../../../model/user'; import {OGCommandsService} from '../../../service/og-commands.service'; import {CommandService} from '../../../api/command.service'; import {Image} from '../../../model/image'; -import {Command, Excecution} from '../../../model/command'; +import {Command, Execution} from '../../../model/command'; import {Client} from '../../../model/client'; import {Repository} from '../../../model/repository'; import {RepositoryService} from '../../../api/repository.service'; @@ -25,7 +25,7 @@ export class DeleteCacheImageCommandComponent implements OnInit { private readonly user: User; private constants: any; public repositories: Repository[]; - public execution = new Excecution(); + public execution = new Execution(); public commands: Command[] = []; public client: Client; public cacheImages = []; @@ -102,9 +102,9 @@ export class DeleteCacheImageCommandComponent implements OnInit { this.execution.script += '\n'; } } - this.execution.script += this.constants.commands.REFRESH_INFO + '\n'; this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$'); this.execution.type = 'RUN_SCRIPT'; + this.execution.sendConfig = true; this.commandService.execute(this.execution).subscribe( (response) => { diff --git a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts index 62b733b8..05b3ebfe 100644 --- a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts @@ -11,6 +11,7 @@ import {OGCommandsService} from '../../../service/og-commands.service'; import {Client, Partition} from '../../../model/client'; import {CommandService} from '../../../api/command.service'; import {forkJoin} from 'rxjs'; +import {Execution} from '../../../model/command'; @Component({ selector: 'app-format-command', @@ -18,7 +19,7 @@ import {forkJoin} from 'rxjs'; styleUrls: [ './format-command.component.scss' ] }) export class FormatCommandComponent implements OnInit { - execution = {clients: '', script: '', type: ''}; + execution = new Execution(); command = {}; user: User; clientGroups = {}; @@ -85,10 +86,7 @@ export class FormatCommandComponent implements OnInit { const groups = Object.keys(this.clientGroups); for (let g = 0; g < groups.length; g++) { if (!executions[g]) { - executions[g] = { - clients: '', - script: '' - }; + executions[g] = new Execution(); } // Recorrer las particiones del primer cliente de la lista y ver si hay alguna seleccionada const found = false; @@ -101,7 +99,7 @@ export class FormatCommandComponent implements OnInit { while (!found && index < client.partitions.length) { const partition = client.partitions[index]; if (partition.selected === true) { - if(executions[g].script === '') { + if (executions[g].script === '') { executions[g].script = 'ogUnmountAll ' + partition.numDisk + '\n'; } // Si la particion es cache @@ -122,7 +120,8 @@ export class FormatCommandComponent implements OnInit { const execution = { type: 'RUN_SCRIPT', script: executions[index].script, - clients: executions[index].clients.substring(0, executions[index].clients.length - 1) // Quitar la ultima "," + clients: executions[index].clients.substring(0, executions[index].clients.length - 1), // Quitar la ultima "," + sendConfig: true }; promises.push(this.commandService.execute(execution)); } diff --git a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss index 97d2231d..ec120f1f 100644 --- a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss +++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss @@ -12,11 +12,13 @@ right: 0; margin: 0; background-color: black; - width: 2px; + width: 4px; height: 100%; padding: 0 !important; cursor: col-resize; border: 1px solid transparent; } - + table.disk-partitions td:last-child span.resizer:last-child { + display: none; + } } diff --git a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts index 8c75fa2e..eb36930a 100644 --- a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts @@ -12,6 +12,7 @@ import {CommandService} from '../../../api/command.service'; import {DomSanitizer} from '@angular/platform-browser'; import {ChartOptions} from 'chart.js'; import {Client} from '../../../model/client'; +import {Execution} from '../../../model/command'; @Component({ selector: 'app-partition-format-command', @@ -19,7 +20,7 @@ import {Client} from '../../../model/client'; styleUrls: [ './partition-format-command.component.scss' ] }) export class PartitionFormatCommandComponent implements OnInit { - execution = {clients: '', script: '', type: ''}; + execution = new Execution(); command = {}; user: User; constants: any; diff --git a/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.html b/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.html index 4cb0f6e5..0a9abe16 100644 --- a/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.html @@ -1 +1,83 @@ -<div>Html template for class SoftwareProfile</div>
\ No newline at end of file +<section class="content-header"> + <h1 translate="software"> + </h1> + <ol class="breadcrumb"> + <li><a href="#/app/dashboard"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li> + <li><a href="#/app/software"><i class="fa fa-server"></i> {{'software'|translate}}</a></li> + <li class="active" translate="software_profile"></li> + </ol> +</section> +<section fixed-toolboxbar class="toolboxbar"> + <div> + <div class="col-md-12"> + <div class="box-tools pull-right"> + <button class="btn btn-primary" translate="save" (click)="save(Form)"></button> + </div> + </div> + </div> +</section> +<section class="content"> + <div class="row"> + <div class="col-md-6"> + <div class="box box-primary"> + <div class="box-header with-border"> + <h3 *ngIf="!softwareProfile.id" class="box-title" translate="new_software_profile"></h3> + <h3 *ngIf="softwareProfile.id" class="box-title" translate="software_profile"></h3> + </div> + <div class="box-body"> + <form role="form" name="Form"> + <app-form-input [cols]="1" [model]="softwareProfile" [formType]="formType"></app-form-input> + </form> + </div> + <div class="box-footer"> + </div> + </div> + </div> + <div class="col-md-6"> + <div class="box box-primary"> + <div class="box-header with-border"> + <h4 translate="software_profile_components"></h4> + <div class="input-group"> + <input type="text" name="q" class="form-control" placeholder="Search..." + [(ngModel)]="searchText"> + <span class="input-group-btn"> + <button type="button" name="search" id="search-btn" class="btn btn-flat"><i + class="fa fa-search"></i> + </button> + </span> + </div> + </div> + <div class="box-body"> + <table class="table table-hover"> + <tbody> + <tr> + <th translate="select"></th> + <th translate="description"></th> + <th translate="type"></th> + </tr> + <tr *ngFor="let softwareComponent of softwareComponents; let index = index" + class="(index%2 == 0)?'odd':'even'"> + <td> + <input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" + type="checkbox" class="selection-checkbox" + [(ngModel)]="softwareComponent.$$selected" + (change)="ogCommonService.checkUnchekComponent(softwareProfile, softwareComponent)"/> + </td> + <td> + <span> + {{softwareComponent.description}} + </span> + </td> + <td> + <span> + {{softwareComponent.type ? softwareComponent.type.name : '-'}} + </span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </div> +</section> diff --git a/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.ts b/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.ts index bff05a1c..b34cfb77 100644 --- a/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/software-profile/software-profile.component.ts @@ -1,17 +1,100 @@ -import { Component } from '@angular/core';
-
-import { SoftwareProfileService } from 'src/app/api/software-profile.service';
-import { SoftwareProfile } from 'src/app/model/software-profile';
-
-@Component({
- selector: 'software-profile',
- templateUrl: './software-profile.component.html',
- styleUrls: [ './software-profile.component.scss' ]
-})
-export class SoftwareProfileComponent {
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public softwareProfileService: SoftwareProfileService) {
- }
-
-}
+import {Component, OnInit} from '@angular/core'; + +import { SoftwareProfileService } from 'src/app/api/software-profile.service'; +import {ParamMap, ActivatedRoute, Router} from '@angular/router'; +import {SoftwareProfile} from '../../model/software-profile'; +import {ToasterService} from '../../service/toaster.service'; +import {SoftwareComponentService} from '../../api/software-component.service'; +import {SoftwareComponent} from '../../model/software-component'; +import {SoftwareProfileFormType} from '../../form-type/software-profile.form-type'; +import {OgCommonService} from '../../service/og-common.service'; + +@Component({ + selector: 'app-software-profile', + templateUrl: './software-profile.component.html', + styleUrls: [ './software-profile.component.scss' ] +}) +export class SoftwareProfileComponent implements OnInit { + public softwareProfile: SoftwareProfile = new SoftwareProfile(); + public softwareComponents: SoftwareComponent[]; + formType: any; + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(public ogCommonService: OgCommonService, public softwareProfileService: SoftwareProfileService, + public softwareComponentsService: SoftwareComponentService, private routerCtrl: Router, + private router: ActivatedRoute, private toaster: ToasterService) { + this.formType = new SoftwareProfileFormType().getForm(); + } + + ngOnInit(): void { + this.softwareComponentsService.list().subscribe( + components => { + this.softwareComponents = components; + this.router.paramMap.subscribe( + (params: ParamMap) => { + if(params.get('id')) { + this.softwareProfileService.read(Number(params.get('id'))).subscribe( + data => { + this.softwareProfile = data; + const self = this; + // Seleccionar los componentes adecuados + this.softwareComponents.forEach(function(component, index, array) { + if ( self.softwareProfile.softwares.find((value) => value.id === component.id)) { + // @ts-ignore + component.$$selected = true; + } + }); + }, + error => { + this.toaster.pop({type: 'error', body: 'error_loading_software_profile', title: 'error'}); + } + ); + } else { + this.softwareProfile = new SoftwareProfile(); + } + } + ); + }, + error => { + this.toaster.pop({type: 'error', body: 'error_loading_software_components', title: 'error'}); + } + ); + + } + + save() { + this.softwareProfile.softwares = []; + const self = this; + this.softwareComponents.forEach(function(component, index, array) { + // @ts-ignore + if (component.$$selected === true) { + // @ts-ignore + self.softwareProfile.softwares.push(component.id); + } + }); + // Actualizar o guardar + let request; + if(this.softwareProfile.id !== 0){ + request = this.softwareProfileService.update(this.softwareProfile); + } + else{ + request = this.softwareProfileService.create(this.softwareProfile); + } + request.subscribe( + (response) => { + this.toaster.pop({type: 'success', title: 'success', body: 'successfully_saved'}); + this.routerCtrl.navigate(['/app/software']).then( + success => { + console.log(success); + }, + error => { + console.log(error); + } + ); + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } +} diff --git a/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts b/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts index 1ea33faa..6b54a896 100644 --- a/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts +++ b/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts @@ -39,9 +39,16 @@ export class OGCommandsService { this.commandService.execute(this.execution).subscribe( (response: any[]) => { // Buscar en la respuesta si hay algún statuscode diferente de 200 - const errors = response.filter(function(value) { - return (value.statusCode && value.statusCode !== '!200'); - } ); + const errors = []; + const keys = Object.keys(response); + keys.forEach((index) => { + const elemKeys = Object.keys(response[index]); + elemKeys.forEach((elemKey) => { + if (elemKey === 'statusCode' && response[index][elemKey] !== 200) { + errors.push(response[index]); + } + }); + }); let errorStr = ''; let toasterOpts = {type: 'success', title: 'success', body: this.translate.instant('successfully_executed')}; if (errors.length > 0) { @@ -116,7 +123,7 @@ export class OGCommandsService { // Crear como nombre para mostrar, el disco y partición del sistema const obj = Object.assign({}, client.partitions[index]); const str = 'disco: ' + obj.numDisk + ', part: ' + obj.numPartition + ', SO: ' + client.partitions[index].osName; - clonablePartitions.push(obj.numDisk + ' ' + obj.numPartition) + clonablePartitions.push(obj.numDisk + ' ' + obj.numPartition); options.scope.partitions.push(str); } } diff --git a/admin/WebConsole3/frontend/src/app/service/og-common.service.ts b/admin/WebConsole3/frontend/src/app/service/og-common.service.ts index b529199d..3de25304 100644 --- a/admin/WebConsole3/frontend/src/app/service/og-common.service.ts +++ b/admin/WebConsole3/frontend/src/app/service/og-common.service.ts @@ -198,15 +198,13 @@ export class OgCommonService { } saveSelection() { - if (Object.keys(this.selectedClients).length > 0) { - localStorage.setItem('selectedClients', JSON.stringify(this.selectedClients, function (key, value) { - let result = value; - if (key === 'parent' && typeof value === 'object') { - result = value.id; - } - return result; - })); - } + localStorage.setItem('selectedClients', JSON.stringify(this.selectedClients, function (key, value) { + let result = value; + if (key === 'parent' && typeof value === 'object') { + result = value.id; + } + return result; + })); } getSelectionSize() { diff --git a/admin/WebConsole3/frontend/src/environments/environment.ts b/admin/WebConsole3/frontend/src/environments/environment.ts index 16b61e25..ef17e26d 100644 --- a/admin/WebConsole3/frontend/src/environments/environment.ts +++ b/admin/WebConsole3/frontend/src/environments/environment.ts @@ -1,7 +1,7 @@ // This file can be replaced during build by using the `fileReplacements` array. // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. // The list of file replacements can be found in `angular.json`. -const url = 'https://172.16.140.210/opengnsys3'; +const url = 'https://SERVERIP/opengnsys3'; export const environment = { production: false, BASE_URL: url, @@ -9,8 +9,8 @@ export const environment = { API_PUBLIC_URL: url + '/api', API_BASE_URL: '/backend/web/app_dev.php/api', OAUTH_DOMAIN: '/backend/web/app_dev.php/oauth/v2/token', - OAUTH_CLIENT_ID: '1_23amzbdp4kskg80444oscko4w0w8wokocs88k0g8w88o4oggs4', - OAUTH_CLIENT_SECRET: '46rttt2trwo4gocgoc4w80k4s8ok48sg8s84kk0cw48csks8o8', + OAUTH_CLIENT_ID: 'CLIENTID', + OAUTH_CLIENT_SECRET: 'CLIENTSECRET', BASE_DIR: 'opengnsys3', clientstatus: ['off', 'initializing', 'oglive', 'busy', 'linux', 'linux_session', 'macos', 'windows', 'windows_session'], windowsboots: ['reboot', 'directo (kexec)'], diff --git a/installer/vagrant/Vagrantfile-webconsole3-vbox b/installer/vagrant/Vagrantfile-webconsole3-vbox new file mode 100644 index 00000000..6cf4f037 --- /dev/null +++ b/installer/vagrant/Vagrantfile-webconsole3-vbox @@ -0,0 +1,171 @@ +# Vagrantfile to prepare virtual environment using VirtualBox provider to develop new AngularJS-based web interface. + +VAGRANTFILE_API_VERSION = "2" +ENV['VAGRANT_DEFAULT_PROVIDER'] = "virtualbox" +LANGUAGE = "es_ES" +ENV['LC_ALL'] = LANGUAGE + ".UTF-8" +SERVERMEM = 2048 +SERVERCPUS = 2 +CLIENTMEM = 512 +NCLIENTS = 4 +REPODISK = "repo.vdi" +REPOSIZE = 50 +MACPREFIX = "08:00:27:0e:65" +NETPREFIX = "192.168.2" +SERVERIP = "#{NETPREFIX}.10" +LOCALWEBPORT = 8443 + + +# OpenGnsys Server provisioning script. +SCRIPT = <<EOT +# Set language. +export LANG="#{LANGUAGE}.UTF-8" +echo "LANG=\"$LANG\"" > /etc/default/locale +echo "LANG=\"$LANG\"" >> /etc/environment +echo "LANGUAGE=\"$LANG\"" >> /etc/environment +echo "LC_ALL=\"$LANG\"" >> /etc/environment +echo "LC_CTYPE=\"$LANG\"" >> /etc/environment +locale-gen --lang #{LANGUAGE} +sed -i "s/XKBLAYOUT=.*/XKBLAYOUT=\"${LANG%_*}\"/" /etc/default/keyboard +dpkg-reconfigure -fnoninteractive console-setup +# Exit if OpenGnsys is installed. +[ -f /opt/opengnsys/doc/VERSION.json ] && echo "Cannot provision, OpenGnsys is alread +y installed." && exit 1 +# Create repository disk using LVM, if necesary. +if [ -z "$(blkid /dev/mapper/og-images | grep ext4)" ]; then + pvcreate /dev/sdb + vgcreate og /dev/sdb + vgchange -ay + lvcreate -ay -n images -l 100%VG og + mkfs -t ext4 /dev/mapper/og-images + mkdir -p /opt/opengnsys/images + echo "/dev/mapper/og-images /opt/opengnsys/images ext4 defaults 0 0" >> /etc/fstab + mount -a +fi +# Update repositories. +add-apt-repository -y ppa:webupd8team/atom +apt-get update +# Install main dependencies. +apt-get install -y xfce4 gnome-icon-theme-full tango-icon-theme linux-headers-$(uname -r) firefox atom virtualbox-guest-dkms virtualbox-guest-utils virtualbox-guest-x11 +echo "allowed_users=anybody" > /etc/X11/Xwrapper.config +# Install OpenGnsys Server +tar xpvzf /vagrant/opengnsys3.tar.gz -C /tmp +/tmp/opengnsys/installer/opengnsys_installer.sh +echo y | /opt/opengnsys/bin/setserveraddr eth1 +# Configure the virtual lab. +read -e APIID APISECRET <<<$(/opt/opengnsys/www3/backend/app/console doctrine:query:sql "SELECT random_id, secret FROM og_core__clients WHERE id=1;" | awk -F\\" '$2~/^(random_id|secret)$/ {getline; printf("%s ", $2)}') +rm -fr /opt/opengnsys/www3/backend/var/cache/* +REQ=$(curl -sk 'https://localhost/opengnsys3/backend/web/app_dev.php/oauth/v2/token?client_id=1_'"$APIID"'&client_secret='"$APISECRET"'&grant_type=password&username=admin&password=admin') +TOKEN="$(echo $REQ | jq -r .access_token)" +REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"Repositorio virtual", "ip":"#{SERVERIP}", "password":"'$(php -r 'echo md5(uniqid(rand(), true));')'", "configurationpath":"/", "adminpath":"/", "pxepath":"/", "port":0 }' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/repositories) +REPOID=$(echo $REQ | jq -r .id) +REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"Aula virtual", "description":"Despliegue virtual con Vagrant.", "networkSettings":{"mcastMode":"full-duplex", "mcastIp":"239.194.2.11", "mcastPort":9000, "mcastPort":9000, "mcastSpeed":100, "netmask":"#{NETPREFIX}.0", "router":"#{NETPREFIX}.1", "p2pMode":"peer", "p2pTime":60} }' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/organizationalunits) +OUID=$(echo $REQ | jq -r .id) +for ((i=11; i<=10+#{NCLIENTS}; i++)); do + sed -i "/^}$/ i host pc${i} { hardware ethernet #{MACPREFIX}:${i}; fixed-address #{NETPREFIX}.${i}; }" /etc/dhcp/dhcpd.conf + [ $i == 11 ] && BOOTID=5 || BOOTID=6 + REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"pc'$i'", "ip":"#{NETPREFIX}.'$i'", "mac":"#{MACPREFIX}:'$i'", "serialno":"", "netiface":"eth0", "netdriver":"generic", "netboot":'"$BOOTID"', "organizationalUnit":'"$OUID"', "repository":'"$REPOID"'}' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/clients) +done +systemctl restart isc-dhcp-server +#/opt/opengnsys/bin/setclientmode ogLiveAdmin pc11 PERM +#for ((i=12; i<=#{NCLIENTS+10}; i++)); do +# /opt/opengnsys/bin/setclientmode ogLive pc$i PERM +#done +sed -i "s,\(url = 'https://\)[^/]*,\1localhost:#{LOCALWEBPORT}," /opt/opengnsys/www3/frontend/main.js +sed -i "s,\(url = 'https://\)[^/]*,\1localhost:#{LOCALWEBPORT}," /opt/opengnsys/www3/frontend/main.js.map +echo "Notes:" +echo "- New OpenGnsys Server URL: https://localhost:#{LOCALWEBPORT}/opengnsys3/frontend/" +EOT + +# Client 1 OS provisioning script. +OGAGENTPKG = "ogagent_1.1.1_all.deb" +MODELSCRIPT = <<EOT +# Comment out next lines to install and configure OGAgent for Ubuntu. +apt-get update -y +apt-get install -y curl +curl -ks https://#{SERVERIP}/opengnsys/descargas/#{OGAGENTPKG} -o /tmp/#{OGAGENTPKG} +if [ -f /tmp/#{OGAGENTPKG} ]; then + apt-get install -y /tmp/#{OGAGENTPKG} || exit $? + sed -i "0,/remote=/ s,remote=.*,remote=https://#{SERVERIP}/opengnsys/rest/," /usr/share/OGAgent/cfg/ogagent.cfg + rm -f /tmp/#{OGAGENTPKG} +else + echo "Warning: cannot install OGAgent package #{OGAGENTPKG}" +fi +# Remove network configuration added by Vagrant. +sed -i "/eth1/ d" /etc/network/interfaces +echo "Notes:" +echo "- After now, use VirtualBox GUI to disable network interface 1 and restart this VM." +# Leave VM halted. +sleep 2 +poweroff & +EOT + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + + # OpenGnsys AngularJS VM definition. + config.vm.define "ogAngular", primary: true do |ag| + # Specific VirtualBox configuration. + ag.vm.provider "virtualbox" do |vb| + # VM name, memory and CPUs. + vb.name = "ogAngular" + vb.memory = SERVERMEM + vb.cpus = SERVERCPUS + # 2nd virtual disk path (current dir on Windows, VM dir on other OSes) + if Vagrant::Util::Platform.windows? then + second_disk = File.join(".", REPODISK) + else + line = `VBoxManage list systemproperties`.match("Default machine folder.*")[0] + vb_machine_folder = line.split(':')[1].strip() + second_disk = File.join(vb_machine_folder, vb.name, REPODISK) + end + # Create repo virtual disk, if needed. + unless File.exist?(second_disk) + vb.customize ['createhd', '--filename', second_disk, '--size', REPOSIZE * 1024] + end + # Attach repo virtual disk. + vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', second_disk] + end + # VM base and host name. + ag.vm.box = "bento/ubuntu-18.04" + ag.vm.hostname = "ogAngular" + # Network settings. + ag.vm.network "forwarded_port", guest: 443, host: LOCALWEBPORT, host_ip: "127.0.0.1" + ag.vm.network "private_network", mac: "#{MACPREFIX}10".tr(":",""), ip: "#{SERVERIP}", virtualbox__intnet: true + # Launch provisioning script. + ag.vm.provision "shell", inline: SCRIPT + end + + # Client 1 VM definition. + config.vm.define "pc11", autostart: false do |v1| + v1.vm.box = "bento/ubuntu-18.04" + v1.vm.hostname = "pc11" + v1.vm.network "private_network", mac: "#{MACPREFIX}11".tr(":",""), type: "dhcp", virtualbox__intnet: true + v1.vm.provider "virtualbox" do |vb| + vb.name = "pc11" + vb.memory = CLIENTMEM + vb.cpus = 1 + vb.customize ['modifyvm', :id, '--boot1', 'net', '--boot2', 'disk'] + end + v1.vm.synced_folder ".", "/vagrant", disabled: true + v1.vm.provision "shell", inline: MODELSCRIPT + end + + # Clonable clients definition. + (2..NCLIENTS).each do |i| + config.vm.define "pc#{i+10}", autostart: false do |cl| + cl.vm.box = "clink15/pxe" + cl.ssh.insert_key = false + cl.vm.boot_timeout = 5 + cl.vm.network "private_network", mac: "#{MACPREFIX}#{i+10}".tr(":",""), type: "dhcp", virtualbox__intnet: true + cl.vm.provider "virtualbox" do |vb| + vb.name = "pc#{i+10}" + vb.memory = CLIENTMEM + vb.cpus = 1 + vb.customize ['modifyvm', :id, '--boot1', 'net', '--boot2', 'disk'] + vb.customize ["modifyvm", :id, "--nic1", "none"] + end + end + end + +end + diff --git a/server/bin/setserveraddr b/server/bin/setserveraddr index eb52d64d..a979595f 100755 --- a/server/bin/setserveraddr +++ b/server/bin/setserveraddr @@ -22,7 +22,7 @@ PROG="$(basename "$0")" OPENGNSYS=/opt/opengnsys PXEDIR=$OPENGNSYS/tftpboot/menu.lst -DEFAULTFILE=/etc/default/opengnsys +CONFIGFILE=$OPENGNSYS/etc/opengnsys.json # Checking parameters. if [ $# -ne 1 ]; then @@ -56,8 +56,7 @@ done if [ -n "$SERVERIP" ]; then # Temporary files. tmpfile=$(mktemp /tmp/og.XXXXX) - MYCNF=$(mktemp /tmp/.my.cnf.XXXXX) - trap "rm -f $tmpfile $MYCNF" 1 2 3 6 9 15 + trap "rm -f $tmpfile" 1 2 3 6 9 15 # Checking whether the DHCP settings need to be changed. CHANGE=0 @@ -85,73 +84,12 @@ if [ -n "$SERVERIP" ]; then echo "DHCP configuration has not changed." fi - # Saving old IP address. - source $OPENGNSYS/etc/ogAdmRepo.cfg - OLDSERVERIP=$IPlocal - - # Checking if configuration files need to be modified. - CHANGE=0 - for f in $OPENGNSYS/{etc/{ogAdmServer,ogAdmRepo,ogAdmAgent}.cfg,www/controlacceso.php,client/etc/ogAdmClient.cfg}; do - # Error if configuration file cannot be found. - if [ ! -f $f ]; then - echo "$PROG: File $file does not exist." >&2 - exit 2 - fi - # Updating configuration variables (if URLs does not contain "localhost"). - sed -e "s,ServidorAdm=.*,ServidorAdm=$SERVERIP," \ - -e "s,IPlocal=.*,IPlocal=$SERVERIP," \ - -e "s,UrlMenu=https?://\([^/]*\)/\(.*\),UrlMenu=https://$SERVERIP/\2," \ - -e '/localhost/!s,https\?://[^/]*/\(.*\),https://'$SERVERIP'/\1,' $f >$tmpfile - file="${f/./-$SERVERDEV.}" - # Copying updated file, if needed. - if [ ! $f -ef $file ] || ! diff -q $tmpfile $file &>/dev/null; then - cp $tmpfile $file - ln -f $file $f - CHANGE=1 - fi - done - - # Processing when something has changed. - if [ $CHANGE == 1 ]; then - # Restart OpenGnsys services. - /etc/init.d/opengnsys restart - # If Repository is active, generating a new API token. - source $DEFAULTFILE - if [ "$RUN_OGADMREPO" == "yes" ]; then - REPOKEY=$(php -r 'echo md5(uniqid(rand(), true));') - sed -i -e "s/ApiToken=.*/ApiToken=$REPOKEY/" $OPENGNSYS/etc/ogAdmRepo.cfg - fi - # If OpenGnsys Server is active, updating the database. - if [ "$RUN_OGADMSERVER" == "yes" ]; then - source $OPENGNSYS/etc/ogAdmServer.cfg - # Creating credentials file. - cat << EOT > $MYCNF -[client] -user=$USUARIO -password=$PASSWORD -EOT - # Updating OpenGnsys Server IP address. - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE entornos - SET ipserveradm='$SERVERIP' - WHERE identorno=1" - # If OpenGnsys Repository is active, updating IP address and API token. - if [ "$RUN_OGADMREPO" == "yes" ]; then - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE repositorios - SET ip='$SERVERIP', apikey='$REPOKEY' - WHERE ip='$OLDSERVERIP'" - unset REPOKEY - fi - # Updating all menu URLs. - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE menus - SET htmlmenupub = REPLACE(htmlmenupub, '$OLDSERVERIP', '$SERVERIP'), - htmlmenupri = REPLACE(htmlmenupri, '$OLDSERVERIP', '$SERVERIP');" - # Updating all PXE files. - find $PXEDIR -name "01-*" -exec sed -i -e "s/$OLDSERVERIP/$SERVERIP/g" {} \; - fi - + OLDSERVERIP=$(jq -r .server.ip $CONFIGFILE) + if [ "$SERVERIP" != "$OLDSERVERIP" ]; then + # Updating configuration file. + jq ".server.ip=\"$SERVERIP\"" $CONFIGFILE | sponge $CONFIGFILE + # Updating all PXE files. + find $PXEDIR -name "01-*" -exec sed -i -e "s/$OLDSERVERIP/$SERVERIP/g" {} \; # Showing manual task to do after execution. cat << EOT Default server interface set to: $SERVERDEV ($SERVERIP) @@ -161,7 +99,6 @@ Manual tasks: - Check PXE files. - Log-in as Web Console user: - Check menu URLs. -${REPOKEY:+" - Update repository API token"} EOT else # Showing message if nothing changes. @@ -173,6 +110,6 @@ else exit 1 fi -# Removing temporary files. -rm -f $tmpfile $MYCNF +# Removing temporary file. +rm -f $tmpfile |