You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by mr...@apache.org on 2017/11/27 23:29:29 UTC
[17/30] ambari git commit: Merge trunk with feature branch and fix
some UT compilation issues (mradhakrishnan)
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
index e187b00..a715adc 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/logs-container.service.ts
@@ -17,9 +17,17 @@
*/
import {Injectable} from '@angular/core';
+import {FormGroup, FormControl} from '@angular/forms';
import {Response} from '@angular/http';
+import {Subject} from 'rxjs/Subject';
+import {Observable} from 'rxjs/Observable';
+import 'rxjs/add/observable/timer';
+import 'rxjs/add/observable/combineLatest';
+import 'rxjs/add/operator/first';
+import 'rxjs/add/operator/map';
+import 'rxjs/add/operator/takeUntil';
+import * as moment from 'moment-timezone';
import {HttpClientService} from '@app/services/http-client.service';
-import {FilteringService} from '@app/services/filtering.service';
import {AuditLogsService} from '@app/services/storage/audit-logs.service';
import {AuditLogsFieldsService} from '@app/services/storage/audit-logs-fields.service';
import {ServiceLogsService} from '@app/services/storage/service-logs.service';
@@ -27,30 +35,437 @@ import {ServiceLogsFieldsService} from '@app/services/storage/service-logs-field
import {ServiceLogsHistogramDataService} from '@app/services/storage/service-logs-histogram-data.service';
import {ServiceLogsTruncatedService} from '@app/services/storage/service-logs-truncated.service';
import {AppStateService} from '@app/services/storage/app-state.service';
+import {AppSettingsService} from '@app/services/storage/app-settings.service';
import {TabsService} from '@app/services/storage/tabs.service';
+import {ClustersService} from '@app/services/storage/clusters.service';
+import {ComponentsService} from '@app/services/storage/components.service';
+import {HostsService} from '@app/services/storage/hosts.service';
import {ActiveServiceLogEntry} from '@app/classes/active-service-log-entry';
+import {FilterCondition, TimeUnitListItem, SortingListItem} from '@app/classes/filtering';
+import {ListItem} from '@app/classes/list-item';
import {Tab} from '@app/classes/models/tab';
+import {LogField} from '@app/classes/models/log-field';
+import {AuditLog} from '@app/classes/models/audit-log';
import {AuditLogField} from '@app/classes/models/audit-log-field';
+import {ServiceLog} from '@app/classes/models/service-log';
import {ServiceLogField} from '@app/classes/models/service-log-field';
import {BarGraph} from '@app/classes/models/bar-graph';
+import {NodeItem} from '@app/classes/models/node-item';
@Injectable()
export class LogsContainerService {
- constructor(private httpClient: HttpClientService, private auditLogsStorage: AuditLogsService, private auditLogsFieldsStorage: AuditLogsFieldsService, private serviceLogsStorage: ServiceLogsService, private serviceLogsFieldsStorage: ServiceLogsFieldsService, private serviceLogsHistogramStorage: ServiceLogsHistogramDataService, private serviceLogsTruncatedStorage: ServiceLogsTruncatedService, private appState: AppStateService, private tabsStorage: TabsService, private filtering: FilteringService) {
+ constructor(
+ private httpClient: HttpClientService, private auditLogsStorage: AuditLogsService,
+ private auditLogsFieldsStorage: AuditLogsFieldsService, private serviceLogsStorage: ServiceLogsService,
+ private serviceLogsFieldsStorage: ServiceLogsFieldsService,
+ private serviceLogsHistogramStorage: ServiceLogsHistogramDataService,
+ private serviceLogsTruncatedStorage: ServiceLogsTruncatedService, private appState: AppStateService,
+ private appSettings: AppSettingsService, private tabsStorage: TabsService, private clustersStorage: ClustersService,
+ private componentsStorage: ComponentsService, private hostsStorage: HostsService
+ ) {
+ const formItems = Object.keys(this.filters).reduce((currentObject: any, key: string): {[key: string]: FormControl} => {
+ let formControl = new FormControl(),
+ item = {
+ [key]: formControl
+ };
+ formControl.setValue(this.filters[key].defaultSelection);
+ return Object.assign(currentObject, item);
+ }, {});
+ this.filtersForm = new FormGroup(formItems);
+ this.loadClusters();
+ this.loadComponents();
+ this.loadHosts();
appState.getParameter('activeLog').subscribe((value: ActiveServiceLogEntry | null) => this.activeLog = value);
- appState.getParameter('isServiceLogsFileView').subscribe((value: boolean): void => {
- const activeLog = this.activeLog,
- filtersForm = this.filtering.activeFiltersForm;
- if (value && activeLog) {
- filtersForm.controls.hosts.setValue(activeLog.host_name);
- filtersForm.controls.components.setValue(activeLog.component_name);
- }
- this.isServiceLogsFileView = value;
- });
+ appState.getParameter('isServiceLogsFileView').subscribe((value: boolean) => this.isServiceLogsFileView = value);
appState.getParameter('activeLogsType').subscribe((value: string) => this.activeLogsType = value);
+ appSettings.getParameter('timeZone').subscribe((value: string) => this.timeZone = value || this.defaultTimeZone);
+ tabsStorage.mapCollection((tab: Tab): Tab => {
+ let currentAppState = tab.appState || {};
+ const appState = Object.assign({}, currentAppState, {
+ activeFilters: this.getFiltersData(tab.type)
+ });
+ return Object.assign({}, tab, {
+ appState
+ });
+ });
+ appState.getParameter('activeFilters').subscribe((filters: object): void => {
+ this.filtersFormChange.next();
+ if (filters) {
+ const controls = this.filtersForm.controls;
+ Object.keys(controls).forEach((key: string): void => {
+ controls[key].setValue(filters.hasOwnProperty(key) ? filters[key] : null);
+ });
+ }
+ this.loadLogs();
+ this.filtersForm.valueChanges.takeUntil(this.filtersFormChange).subscribe((value: object): void => {
+ this.tabsStorage.mapCollection((tab: Tab): Tab => {
+ const currentAppState = tab.appState || {},
+ appState = Object.assign({}, currentAppState, tab.isActive ? {
+ activeFilters: value
+ } : null);
+ return Object.assign({}, tab, {
+ appState
+ });
+ });
+ this.loadLogs();
+ });
+ });
}
+ private readonly paginationOptions: string[] = ['10', '25', '50', '100'];
+
+ filters: {[key: string]: FilterCondition} = {
+ clusters: {
+ label: 'filter.clusters',
+ options: [],
+ defaultSelection: []
+ },
+ timeRange: {
+ options: [
+ [
+ {
+ label: 'filter.timeRange.7d',
+ value: {
+ type: 'LAST',
+ unit: 'd',
+ interval: 7
+ }
+ },
+ {
+ label: 'filter.timeRange.30d',
+ value: {
+ type: 'LAST',
+ unit: 'd',
+ interval: 30
+ }
+ },
+ {
+ label: 'filter.timeRange.60d',
+ value: {
+ type: 'LAST',
+ unit: 'd',
+ interval: 60
+ }
+ },
+ {
+ label: 'filter.timeRange.90d',
+ value: {
+ type: 'LAST',
+ unit: 'd',
+ interval: 90
+ }
+ },
+ {
+ label: 'filter.timeRange.6m',
+ value: {
+ type: 'LAST',
+ unit: 'M',
+ interval: 6
+ }
+ },
+ {
+ label: 'filter.timeRange.1y',
+ value: {
+ type: 'LAST',
+ unit: 'y',
+ interval: 1
+ }
+ },
+ {
+ label: 'filter.timeRange.2y',
+ value: {
+ type: 'LAST',
+ unit: 'y',
+ interval: 2
+ }
+ },
+ {
+ label: 'filter.timeRange.5y',
+ value: {
+ type: 'LAST',
+ unit: 'y',
+ interval: 5
+ }
+ }
+ ],
+ [
+ {
+ label: 'filter.timeRange.yesterday',
+ value: {
+ type: 'PAST',
+ unit: 'd'
+ }
+ },
+ // TODO implement time range calculation
+ /*
+ {
+ label: 'filter.timeRange.beforeYesterday',
+ value: {
+ type: 'PAST',
+ unit: 'd'
+ }
+ },
+ {
+ label: 'filter.timeRange.thisDayLastWeek',
+ value: {
+ type: 'PAST',
+ unit: 'd'
+ }
+ },
+ */
+ {
+ label: 'filter.timeRange.previousWeek',
+ value: {
+ type: 'PAST',
+ unit: 'w'
+ }
+ },
+ {
+ label: 'filter.timeRange.previousMonth',
+ value: {
+ type: 'PAST',
+ unit: 'M'
+ }
+ },
+ {
+ label: 'filter.timeRange.previousYear',
+ value: {
+ type: 'PAST',
+ unit: 'y'
+ }
+ }
+ ],
+ [
+ {
+ label: 'filter.timeRange.today',
+ value: {
+ type: 'CURRENT',
+ unit: 'd'
+ }
+ },
+ {
+ label: 'filter.timeRange.thisWeek',
+ value: {
+ type: 'CURRENT',
+ unit: 'w'
+ }
+ },
+ {
+ label: 'filter.timeRange.thisMonth',
+ value: {
+ type: 'CURRENT',
+ unit: 'M'
+ }
+ },
+ {
+ label: 'filter.timeRange.thisYear',
+ value: {
+ type: 'CURRENT',
+ unit: 'y'
+ }
+ }
+ ],
+ [
+ {
+ label: 'filter.timeRange.5min',
+ value: {
+ type: 'LAST',
+ unit: 'm',
+ interval: 5
+ }
+ },
+ {
+ label: 'filter.timeRange.15min',
+ value: {
+ type: 'LAST',
+ unit: 'm',
+ interval: 15
+ }
+ },
+ {
+ label: 'filter.timeRange.30min',
+ value: {
+ type: 'LAST',
+ unit: 'm',
+ interval: 30
+ }
+ },
+ {
+ label: 'filter.timeRange.1hr',
+ value: {
+ type: 'LAST',
+ unit: 'h',
+ interval: 1
+ }
+ },
+ {
+ label: 'filter.timeRange.3hr',
+ value: {
+ type: 'LAST',
+ unit: 'h',
+ interval: 3
+ }
+ },
+ {
+ label: 'filter.timeRange.6hr',
+ value: {
+ type: 'LAST',
+ unit: 'h',
+ interval: 6
+ }
+ },
+ {
+ label: 'filter.timeRange.12hr',
+ value: {
+ type: 'LAST',
+ unit: 'h',
+ interval: 12
+ }
+ },
+ {
+ label: 'filter.timeRange.24hr',
+ value: {
+ type: 'LAST',
+ unit: 'h',
+ interval: 24
+ }
+ },
+ ]
+ ],
+ defaultSelection: {
+ value: {
+ type: 'LAST',
+ unit: 'h',
+ interval: 1
+ },
+ label: 'filter.timeRange.1hr'
+ }
+ },
+ components: {
+ label: 'filter.components',
+ iconClass: 'fa fa-cubes',
+ options: [],
+ defaultSelection: []
+ },
+ levels: {
+ label: 'filter.levels',
+ iconClass: 'fa fa-sort-amount-asc',
+ options: [
+ {
+ label: 'levels.fatal',
+ value: 'FATAL'
+ },
+ {
+ label: 'levels.error',
+ value: 'ERROR'
+ },
+ {
+ label: 'levels.warn',
+ value: 'WARN'
+ },
+ {
+ label: 'levels.info',
+ value: 'INFO'
+ },
+ {
+ label: 'levels.debug',
+ value: 'DEBUG'
+ },
+ {
+ label: 'levels.trace',
+ value: 'TRACE'
+ },
+ {
+ label: 'levels.unknown',
+ value: 'UNKNOWN'
+ }
+ ],
+ defaultSelection: []
+ },
+ hosts: {
+ label: 'filter.hosts',
+ iconClass: 'fa fa-server',
+ options: [],
+ defaultSelection: []
+ },
+ auditLogsSorting: {
+ label: 'sorting.title',
+ options: [
+ {
+ label: 'sorting.time.asc',
+ value: {
+ key: 'evtTime',
+ type: 'asc'
+ }
+ },
+ {
+ label: 'sorting.time.desc',
+ value: {
+ key: 'evtTime',
+ type: 'desc'
+ }
+ }
+ ],
+ defaultSelection: [
+ {
+ label: 'sorting.time.desc',
+ value: {
+ key: 'evtTime',
+ type: 'desc'
+ }
+ }
+ ]
+ },
+ serviceLogsSorting: {
+ label: 'sorting.title',
+ options: [
+ {
+ label: 'sorting.time.asc',
+ value: {
+ key: 'logtime',
+ type: 'asc'
+ }
+ },
+ {
+ label: 'sorting.time.desc',
+ value: {
+ key: 'logtime',
+ type: 'desc'
+ }
+ }
+ ],
+ defaultSelection: [
+ {
+ label: 'sorting.time.desc',
+ value: {
+ key: 'logtime',
+ type: 'desc'
+ }
+ }
+ ]
+ },
+ pageSize: {
+ label: 'pagination.title',
+ options: this.paginationOptions.map((option: string): ListItem => {
+ return {
+ label: option,
+ value: option
+ }
+ }),
+ defaultSelection: [
+ {
+ label: '10',
+ value: '10'
+ }
+ ]
+ },
+ page: {
+ defaultSelection: 0
+ },
+ query: {}
+ };
+
readonly colors = {
WARN: '#FF8916',
ERROR: '#E81D1D',
@@ -61,13 +476,14 @@ export class LogsContainerService {
UNKNOWN: '#BDBDBD'
};
- private readonly listFilters = {
+ private readonly filtersMapping = {
clusters: ['clusters'],
timeRange: ['to', 'from'],
components: ['mustBe'],
levels: ['level'],
hosts: ['hostList'],
- sorting: ['sortType', 'sortBy'],
+ auditLogsSorting: ['sortType', 'sortBy'],
+ serviceLogsSorting: ['sortType', 'sortBy'],
pageSize: ['pageSize'],
page: ['page'],
query: ['includeQuery', 'excludeQuery']
@@ -85,22 +501,116 @@ export class LogsContainerService {
readonly logsTypeMap = {
auditLogs: {
logsModel: this.auditLogsStorage,
- fieldsModel: this.auditLogsFieldsStorage
+ fieldsModel: this.auditLogsFieldsStorage,
+ // TODO add all the required fields
+ listFilters: ['clusters', 'timeRange', 'auditLogsSorting', 'pageSize', 'page', 'query'],
+ histogramFilters: ['clusters', 'timeRange', 'query']
},
serviceLogs: {
logsModel: this.serviceLogsStorage,
- fieldsModel: this.serviceLogsFieldsStorage
+ fieldsModel: this.serviceLogsFieldsStorage,
+ listFilters: ['clusters', 'timeRange', 'components', 'levels', 'hosts', 'serviceLogsSorting', 'pageSize', 'page', 'query'],
+ histogramFilters: ['clusters', 'timeRange', 'components', 'levels', 'hosts', 'query']
}
};
+ private readonly defaultTimeZone = moment.tz.guess();
+
+ timeZone: string = this.defaultTimeZone;
+
totalCount: number = 0;
+ /**
+ * A configurable property to indicate the maximum capture time in milliseconds.
+ * @type {number}
+ * @default 600000 (10 minutes)
+ */
+ private readonly maximumCaptureTimeLimit: number = 600000;
+
isServiceLogsFileView: boolean = false;
+ filtersForm: FormGroup;
+
activeLog: ActiveServiceLogEntry | null = null;
activeLogsType: string;
+ private filtersFormChange: Subject<any> = new Subject();
+
+ private columnsMapper<FieldT extends LogField>(fields: FieldT[]): ListItem[] {
+ return fields.filter((field: FieldT): boolean => field.isAvailable).map((field: FieldT): ListItem => {
+ return {
+ value: field.name,
+ label: field.displayName || field.name,
+ isChecked: field.isDisplayed
+ };
+ });
+ }
+
+ private logsMapper<LogT extends AuditLog & ServiceLog>(result: [LogT[], ListItem[]]): LogT[] {
+ const [logs, fields] = result;
+ if (fields.length) {
+ const names = fields.map((field: ListItem): string => field.value);
+ return logs.map((log: LogT): LogT => {
+ return names.reduce((currentObject: object, key: string) => Object.assign(currentObject, {
+ [key]: log[key]
+ }), {}) as LogT;
+ });
+ } else {
+ return [];
+ }
+ }
+
+ auditLogsColumns: Observable<ListItem[]> = this.auditLogsFieldsStorage.getAll().map(this.columnsMapper);
+
+ serviceLogsColumns: Observable<ListItem[]> = this.serviceLogsFieldsStorage.getAll().map(this.columnsMapper);
+
+ serviceLogs: Observable<ServiceLog[]> = Observable.combineLatest(this.serviceLogsStorage.getAll(), this.serviceLogsColumns).map(this.logsMapper);
+
+ auditLogs: Observable<AuditLog[]> = Observable.combineLatest(this.auditLogsStorage.getAll(), this.auditLogsColumns).map(this.logsMapper);
+
+ /**
+ * Get instance for dropdown list from string
+ * @param name {string}
+ * @returns {ListItem}
+ */
+ private getListItemFromString(name: string): ListItem {
+ return {
+ label: name,
+ value: name
+ };
+ }
+
+ /**
+ * Get instance for dropdown list from NodeItem object
+ * @param node {NodeItem}
+ * @returns {ListItem}
+ */
+ private getListItemFromNode(node: NodeItem): ListItem {
+ return {
+ label: `${node.name} (${node.value})`,
+ value: node.name
+ };
+ }
+
+ queryParameterNameChange: Subject<any> = new Subject();
+
+ queryParameterAdd: Subject<any> = new Subject();
+
+ private stopTimer: Subject<any> = new Subject();
+
+ private stopAutoRefreshCountdown: Subject<any> = new Subject();
+
+ captureSeconds: number = 0;
+
+ private readonly autoRefreshInterval: number = 30000;
+
+ autoRefreshRemainingSeconds: number = 0;
+
+ private startCaptureTime: number;
+
+ private stopCaptureTime: number;
+
loadLogs = (logsType: string = this.activeLogsType): void => {
this.httpClient.get(logsType, this.getParams('listFilters')).subscribe((response: Response): void => {
const jsonResponse = response.json(),
@@ -128,7 +638,7 @@ export class LogsContainerService {
}
});
}
- }
+ };
loadLogContext(id: string, hostName: string, componentName: string, scrollType: 'before' | 'after' | '' = ''): void {
const params = {
@@ -161,22 +671,18 @@ export class LogsContainerService {
});
}
- private getParams(filtersMapName: string): any {
+ private getParams(filtersMapName: string, logsType: string = this.activeLogsType): {[key: string]: string} {
let params = {};
- Object.keys(this[filtersMapName]).forEach((key: string): void => {
- const inputValue = this.filtering.activeFiltersForm.getRawValue()[key],
- paramNames = this[filtersMapName][key];
- paramNames.forEach(paramName => {
+ this.logsTypeMap[logsType][filtersMapName].forEach((key: string): void => {
+ const inputValue = this.filtersForm.getRawValue()[key],
+ paramNames = this.filtersMapping[key];
+ paramNames.forEach((paramName: string): void => {
let value;
- const valueGetter = this.filtering.valueGetters[paramName];
- if (valueGetter) {
- if (paramName === 'from') {
- value = valueGetter(inputValue, params['to']);
- } else {
- value = valueGetter(inputValue);
- }
+ const valueGetter = this.valueGetters[paramName] || this.defaultValueGetter;
+ if (paramName === 'from') {
+ value = valueGetter(inputValue, params['to']);
} else {
- value = inputValue;
+ value = valueGetter(inputValue);
}
if (value != null && value !== '') {
params[paramName] = value;
@@ -222,12 +728,207 @@ export class LogsContainerService {
return Object.keys(keysObject).map((key: string): {fieldClass} => new fieldClass(key));
}
+ getStartTimeMoment = (selection: TimeUnitListItem, end: moment.Moment): moment.Moment | undefined => {
+ let time;
+ const value = selection && selection.value;
+ if (value) {
+ const endTime = end.clone();
+ switch (value.type) {
+ case 'LAST':
+ time = endTime.subtract(value.interval, value.unit);
+ break;
+ case 'CURRENT':
+ time = moment().tz(this.timeZone).startOf(value.unit);
+ break;
+ case 'PAST':
+ time = endTime.startOf(value.unit);
+ break;
+ case 'CUSTOM':
+ time = value.start;
+ break;
+ default:
+ break;
+ }
+ }
+ return time;
+ };
+
+ private getStartTime = (selection: TimeUnitListItem, current: string): string => {
+ const startMoment = this.getStartTimeMoment(selection, moment(moment(current).valueOf()));
+ return startMoment ? startMoment.toISOString() : '';
+ };
+
+ getEndTimeMoment = (selection: TimeUnitListItem): moment.Moment | undefined => {
+ let time;
+ const value = selection && selection.value;
+ if (value) {
+ switch (value.type) {
+ case 'LAST':
+ time = moment();
+ break;
+ case 'CURRENT':
+ time = moment().tz(this.timeZone).endOf(value.unit);
+ break;
+ case 'PAST':
+ time = moment().tz(this.timeZone).startOf(value.unit).millisecond(-1);
+ break;
+ case 'CUSTOM':
+ time = value.end;
+ break;
+ default:
+ break;
+ }
+ }
+ return time;
+ };
+
+ private getEndTime = (selection: TimeUnitListItem): string => {
+ const endMoment = this.getEndTimeMoment(selection);
+ return endMoment ? endMoment.toISOString() : '';
+ };
+
+ private getQuery(isExclude: boolean): (value: any[]) => string {
+ return (value: any[]): string => {
+ let parameters;
+ if (value && value.length) {
+ parameters = value.filter(item => item.isExclude === isExclude).map(parameter => {
+ return {
+ [parameter.name]: parameter.value.replace(/\s/g, '+')
+ };
+ });
+ }
+ return parameters && parameters.length ? JSON.stringify(parameters) : '';
+ }
+ }
+
+ private getSortType(selection: SortingListItem[] = []): 'asc' | 'desc' {
+ return selection[0] && selection[0].value ? selection[0].value.type : 'desc';
+ }
+
+ private getSortKey(selection: SortingListItem[] = []): string {
+ return selection[0] && selection[0].value ? selection[0].value.key : '';
+ }
+
+ private getPage(value: number | undefined): string | undefined {
+ return typeof value === 'undefined' ? value : value.toString();
+ }
+
+ private defaultValueGetter(selection: ListItem | ListItem[] | null): string {
+ if (Array.isArray(selection)) {
+ return selection.map((item: ListItem): any => item.value).join(',');
+ } else if (selection) {
+ return selection.value;
+ } else {
+ return '';
+ }
+ }
+
+ private readonly valueGetters = {
+ to: this.getEndTime,
+ from: this.getStartTime,
+ sortType: this.getSortType,
+ sortBy: this.getSortKey,
+ page: this.getPage,
+ includeQuery: this.getQuery(false),
+ excludeQuery: this.getQuery(true)
+ };
+
switchTab(activeTab: Tab): void {
+ this.tabsStorage.mapCollection((tab: Tab): Tab => {
+ return Object.assign({}, tab, {
+ isActive: tab.id === activeTab.id
+ });
+ });
this.appState.setParameters(activeTab.appState);
- this.tabsStorage.mapCollection((tab: Tab): Tab => Object.assign({}, tab, {
- isActive: tab.id === activeTab.id
- }));
- this.loadLogs();
+ }
+
+ startCaptureTimer(): void {
+ this.startCaptureTime = new Date().valueOf();
+ const maxCaptureTimeInSeconds = this.maximumCaptureTimeLimit / 1000;
+ Observable.timer(0, 1000).takeUntil(this.stopTimer).subscribe((seconds: number): void => {
+ this.captureSeconds = seconds;
+ if (this.captureSeconds >= maxCaptureTimeInSeconds) {
+ this.stopCaptureTimer();
+ }
+ });
+ }
+
+ stopCaptureTimer(): void {
+ const autoRefreshIntervalSeconds = this.autoRefreshInterval / 1000;
+ this.stopCaptureTime = new Date().valueOf();
+ this.captureSeconds = 0;
+ this.stopTimer.next();
+ this.setCustomTimeRange(this.startCaptureTime, this.stopCaptureTime);
+ Observable.timer(0, 1000).takeUntil(this.stopAutoRefreshCountdown).subscribe((seconds: number): void => {
+ this.autoRefreshRemainingSeconds = autoRefreshIntervalSeconds - seconds;
+ if (!this.autoRefreshRemainingSeconds) {
+ this.stopAutoRefreshCountdown.next();
+ this.setCustomTimeRange(this.startCaptureTime, this.stopCaptureTime);
+ }
+ });
+ }
+
+ loadClusters(): Observable<Response> {
+ const request = this.httpClient.get('clusters');
+ request.subscribe((response: Response): void => {
+ const clusterNames = response.json();
+ if (clusterNames) {
+ this.filters.clusters.options.push(...clusterNames.map(this.getListItemFromString));
+ this.clustersStorage.addInstances(clusterNames);
+ }
+ });
+ return request;
+ }
+
+ loadComponents(): Observable<Response> {
+ const request = this.httpClient.get('components');
+ request.subscribe((response: Response): void => {
+ const jsonResponse = response.json(),
+ components = jsonResponse && jsonResponse.vNodeList.map((item): NodeItem => Object.assign(item, {
+ value: item.logLevelCount.reduce((currentValue: number, currentItem): number => {
+ return currentValue + Number(currentItem.value);
+ }, 0)
+ }));
+ if (components) {
+ this.filters.components.options.push(...components.map(this.getListItemFromNode));
+ this.componentsStorage.addInstances(components);
+ }
+ });
+ return request;
+ }
+
+ loadHosts(): Observable<Response> {
+ const request = this.httpClient.get('hosts');
+ request.subscribe((response: Response): void => {
+ const jsonResponse = response.json(),
+ hosts = jsonResponse && jsonResponse.vNodeList;
+ if (hosts) {
+ this.filters.hosts.options.push(...hosts.map(this.getListItemFromNode));
+ this.hostsStorage.addInstances(hosts);
+ }
+ });
+ return request;
+ }
+
+ setCustomTimeRange(startTime: number, endTime: number): void {
+ this.filtersForm.controls.timeRange.setValue({
+ label: 'filter.timeRange.custom',
+ value: {
+ type: 'CUSTOM',
+ start: moment(startTime),
+ end: moment(endTime)
+ }
+ });
+ }
+
+ getFiltersData(listType: string): object {
+ const itemsList = this.logsTypeMap[listType].listFilters,
+ keys = Object.keys(this.filters).filter((key: string): boolean => itemsList.indexOf(key) > -1);
+ return keys.reduce((currentObject: object, key: string): object => {
+ return Object.assign(currentObject, {
+ [key]: this.filters[key].defaultSelection
+ });
+ }, {});
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
index 8b157df..985b52f 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/mock-api-data.service.ts
@@ -65,6 +65,28 @@ export class mockApiDataService implements InMemoryDbService {
isValuesList: true
}
}
+ },
+ 'api/v1/audit/logs': {
+ pathToCollection: 'logList',
+ totalCountKey: 'totalCount',
+ filters: {
+ clusters: {
+ key: 'cluster',
+ isValuesList: true
+ },
+ iMessage: {
+ key: 'log_message',
+ filterFunction: (value, filterValue) => value.toLowerCase().indexOf(filterValue.toLowerCase()) > -1
+ },
+ from: {
+ key: 'evtTime',
+ filterFunction: (value, filterValue) => value >= moment(filterValue).valueOf()
+ },
+ to: {
+ key: 'evtTime',
+ filterFunction: (value, filterValue) => value < moment(filterValue).valueOf()
+ }
+ }
}
};
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
index a4a0cf8..23d3726 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.spec.ts
@@ -31,56 +31,273 @@ describe('UtilsService', () => {
expect(service).toBeTruthy();
}));
- describe('#updateMultiSelectValue()', () => {
+ describe('#isEqual()', () => {
const cases = [
{
- currentValue: '',
- value: 'v0',
- isChecked: true,
- result: 'v0',
- title: 'check; no checked items before'
+ valueA: 1,
+ valueB: 1,
+ result: true,
+ title: 'same numbers'
},
{
- currentValue: 'v1,v2',
- value: 'v3',
- isChecked: true,
- result: 'v1,v2,v3',
- title: 'check'
+ valueA: 1,
+ valueB: 2,
+ result: false,
+ title: 'different numbers'
},
{
- currentValue: 'v4,v5',
- value: 'v4',
- isChecked: false,
- result: 'v5',
- title: 'uncheck'
+ valueA: 'a',
+ valueB: 'a',
+ result: true,
+ title: 'same strings'
},
{
- currentValue: 'v6,v7',
- value: 'v6',
- isChecked: true,
- result: 'v6,v7',
- title: 'avoid repeating check action'
+ valueA: 'a',
+ valueB: 'b',
+ result: false,
+ title: 'different strings'
},
{
- currentValue: 'v8,v9',
- value: 'v10',
- isChecked: false,
- result: 'v8,v9',
- title: 'avoid repeating uncheck action'
+ valueA: '1',
+ valueB: 1,
+ result: false,
+ title: 'different types'
},
{
- currentValue: 'v11',
- value: 'v11',
- isChecked: false,
- result: '',
- title: 'uncheck last item'
+ valueA: true,
+ valueB: true,
+ result: true,
+ title: 'same booleans'
+ },
+ {
+ valueA: false,
+ valueB: true,
+ result: false,
+ title: 'different booleans'
+ },
+ {
+ valueA: {},
+ valueB: {},
+ result: true,
+ title: 'empty objects'
+ },
+ {
+ valueA: {
+ p0: 'v0'
+ },
+ valueB: {
+ p0: 'v0'
+ },
+ result: true,
+ title: 'same objects'
+ },
+ {
+ valueA: {
+ p0: 'v0'
+ },
+ valueB: {
+ p0: 'v1'
+ },
+ result: false,
+ title: 'different objects'
+ },
+ {
+ valueA: {
+ p0: {
+ p1: 'v1'
+ }
+ },
+ valueB: {
+ p0: {
+ p1: 'v1'
+ }
+ },
+ result: true,
+ title: 'same objects in depth'
+ },
+ {
+ valueA: {
+ p0: {
+ p1: 'v1'
+ }
+ },
+ valueB: {
+ p0: {
+ p1: 'v2'
+ }
+ },
+ result: false,
+ title: 'different objects in depth'
+ },
+ {
+ valueA: [],
+ valueB: [],
+ result: true,
+ title: 'empty arrays'
+ },
+ {
+ valueA: [1, 'a'],
+ valueB: [1, 'a'],
+ result: true,
+ title: 'same arrays'
+ },
+ {
+ valueA: [1, 'a'],
+ valueB: [1, 'b'],
+ result: false,
+ title: 'different arrays'
+ },
+ {
+ valueA: [1, 1],
+ valueB: [1, 1, 1],
+ result: false,
+ title: 'arrays of different length'
+ },
+ {
+ valueA: [{}],
+ valueB: [{}],
+ result: true,
+ title: 'arrays of empty objects'
+ },
+ {
+ valueA: [
+ {
+ p0: 'v0'
+ }
+ ],
+ valueB: [
+ {
+ p0: 'v0'
+ }
+ ],
+ result: true,
+ title: 'arrays of same objects'
+ },
+ {
+ valueA: [
+ {
+ p0: 'v0'
+ }
+ ],
+ valueB: [
+ {
+ p0: 'v1'
+ }
+ ],
+ result: false,
+ title: 'arrays of different objects'
+ },
+ {
+ valueA: function() {},
+ valueB: function() {},
+ result: true,
+ title: 'same functions'
+ },
+ {
+ valueA: function(a) {
+ return a;
+ },
+ valueB: function(b) {
+ return !b;
+ },
+ result: false,
+ title: 'different functions'
+ },
+ {
+ valueA: new Date(1),
+ valueB: new Date(1),
+ result: true,
+ title: 'same dates'
+ },
+ {
+ valueA: new Date(1),
+ valueB: new Date(2),
+ result: false,
+ title: 'different dates'
+ },
+ {
+ valueA: new RegExp('a'),
+ valueB: new RegExp('a'),
+ result: true,
+ title: 'same regexps'
+ },
+ {
+ valueA: new RegExp('a', 'i'),
+ valueB: new RegExp('a', 'g'),
+ result: false,
+ title: 'same regexps with different flags'
+ },
+ {
+ valueA: new RegExp('a'),
+ valueB: new RegExp('b'),
+ result: false,
+ title: 'different regexps'
+ },
+ {
+ valueA: new Number(1),
+ valueB: new Number(1),
+ result: true,
+ title: 'same number objects'
+ },
+ {
+ valueA: new Number(1),
+ valueB: new Number(2),
+ result: false,
+ title: 'different number objects'
+ },
+ {
+ valueA: new String('a'),
+ valueB: new String('a'),
+ result: true,
+ title: 'same string objects'
+ },
+ {
+ valueA: new String('a'),
+ valueB: new String('b'),
+ result: false,
+ title: 'different string objects'
+ },
+ {
+ valueA: new Boolean(true),
+ valueB: new Boolean(true),
+ result: true,
+ title: 'same boolean objects'
+ },
+ {
+ valueA: new Boolean(true),
+ valueB: new Boolean(false),
+ result: false,
+ title: 'different boolean objects'
+ },
+ {
+ valueA: null,
+ valueB: null,
+ result: true,
+ title: 'null values'
+ },
+ {
+ valueA: undefined,
+ valueB: undefined,
+ result: true,
+ title: 'undefined values'
+ },
+ {
+ valueA: undefined,
+ valueB: null,
+ result: false,
+ title: 'undefined vs null'
}
];
cases.forEach(test => {
- it(test.title, inject([UtilsService], (service: UtilsService) => {
- expect(service.updateMultiSelectValue(test.currentValue, test.value, test.isChecked)).toEqual(test.result);
- }));
+ describe(test.title, () => {
+ it('equality', inject([UtilsService], (service: UtilsService) => {
+ expect(service.isEqual(test.valueA, test.valueB)).toEqual(test.result);
+ }));
+ it('symmetry', inject([UtilsService], (service: UtilsService) => {
+ expect(service.isEqual(test.valueA, test.valueB)).toEqual(service.isEqual(test.valueB, test.valueA));
+ }));
+ });
});
});
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
index 3448dd4..175b585 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
+++ b/ambari-logsearch/ambari-logsearch-web/src/app/services/utils.service.ts
@@ -22,27 +22,56 @@ import * as moment from 'moment-timezone';
@Injectable()
export class UtilsService {
- valueHasChanged(currentValue: any, newValue: any): boolean {
- if (newValue == null) {
+ /**
+ * Comparison of two instances of any data type be value instead of reference
+ * @param valueA
+ * @param valueB
+ * @returns {boolean}
+ */
+ isEqual = (valueA: any, valueB: any): boolean => {
+ if (valueA === valueB) {
+ return true;
+ }
+ if (valueA instanceof Date && valueB instanceof Date) {
+ return valueA.valueOf() === valueB.valueOf();
+ }
+ if ((typeof valueA === 'function' && typeof valueB === 'function') ||
+ (valueA instanceof RegExp && valueB instanceof RegExp) ||
+ (valueA instanceof String && valueB instanceof String) ||
+ (valueA instanceof Number && valueB instanceof Number) ||
+ (valueA instanceof Boolean && valueB instanceof Boolean)) {
+ return valueA.toString() === valueB.toString();
+ }
+ if (!(valueA instanceof Object) || !(valueB instanceof Object)) {
return false;
}
- if (typeof newValue === 'object') {
- return JSON.stringify(currentValue) !== JSON.stringify(newValue);
- } else {
- return currentValue !== newValue;
+ if (valueA.constructor !== valueB.constructor) {
+ return false;
}
- }
-
- updateMultiSelectValue(currentValue: string, value: string, isChecked: boolean): string {
- let valuesArray = currentValue ? currentValue.split(',') : [],
- valuePosition = valuesArray.indexOf(value);
- if (isChecked && valuePosition === -1) {
- valuesArray.push(value);
- } else if (!isChecked && valuePosition > -1) {
- valuesArray.splice(valuePosition, 1);
- }
- return valuesArray.join(',');
- }
+ if (valueA.isPrototypeOf(valueB) || valueB.isPrototypeOf(valueA)) {
+ return false;
+ }
+ for (const key in valueA) {
+ if (!valueA.hasOwnProperty(key)) {
+ continue;
+ }
+ if (!valueB.hasOwnProperty(key)) {
+ return false;
+ }
+ if (valueA[key] === valueB[key]) {
+ continue;
+ }
+ if (typeof valueA[key] !== 'object' || !this.isEqual(valueA[key], valueB[key])) {
+ return false;
+ }
+ }
+ for (const key in valueB) {
+ if (valueB.hasOwnProperty(key) && !valueA.hasOwnProperty(key)) {
+ return false;
+ }
+ }
+ return true;
+ };
isEnterPressed(event: KeyboardEvent): boolean {
return event.keyCode === 13;
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
index 16b4b32..98b9e29 100644
--- a/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
+++ b/ambari-logsearch/ambari-logsearch-web/src/assets/i18n/en.json
@@ -10,6 +10,7 @@
"modal.apply": "Apply",
"modal.close": "Close",
+ "authorization.logout": "Logout",
"authorization.name": "Username",
"authorization.password": "Password",
"authorization.signIn": "Sign In",
@@ -61,7 +62,9 @@
"filter.timeRange.6hr": "Last 6 hours",
"filter.timeRange.12hr": "Last 12 hours",
"filter.timeRange.24hr": "Last 24 hours",
- "filter.timeRange.custom": "Custom time range",
+ "filter.timeRange.custom": "Custom",
+ "filter.timeRange.from": "from",
+ "filter.timeRange.to": "to",
"levels.fatal": "Fatal",
"levels.error": "Error",
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-logsearch/ambari-logsearch-web/webpack.config.js
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web/webpack.config.js b/ambari-logsearch/ambari-logsearch-web/webpack.config.js
index 7a60df2..75d6aee 100644
--- a/ambari-logsearch/ambari-logsearch-web/webpack.config.js
+++ b/ambari-logsearch/ambari-logsearch-web/webpack.config.js
@@ -81,18 +81,17 @@ module.exports = {
"resolve": {
"extensions": [
".ts",
- ".js"
+ ".js",
+ ".less"
],
"modules": [
- "./node_modules",
- "./node_modules"
+ "node_modules"
],
"symlinks": true
},
"resolveLoader": {
"modules": [
- "./node_modules",
- "./node_modules"
+ "node_modules"
]
},
"entry": {
@@ -229,7 +228,9 @@ module.exports = {
"loader": "less-loader",
"options": {
"sourceMap": false,
- "paths": []
+ "paths": [
+ "./node_modules"
+ ]
}
}
]
@@ -359,7 +360,7 @@ module.exports = {
"loader": "less-loader",
"options": {
"sourceMap": false,
- "paths": []
+ "paths": ["./node_modules"]
}
}
]
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-metrics/ambari-metrics-assembly/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-assembly/pom.xml b/ambari-metrics/ambari-metrics-assembly/pom.xml
index 9925947..43ff285 100644
--- a/ambari-metrics/ambari-metrics-assembly/pom.xml
+++ b/ambari-metrics/ambari-metrics-assembly/pom.xml
@@ -226,7 +226,6 @@
<description>Maven Recipe: RPM Package.</description>
<autoRequires>false</autoRequires>
<requires>
- <require>snappy</require>
<require>${python.ver}</require>
</requires>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml b/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
index 23f9ba9..a9d342f 100644
--- a/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
+++ b/ambari-metrics/ambari-metrics-hadoop-sink/pom.xml
@@ -31,6 +31,7 @@ limitations under the License.
<packaging>jar</packaging>
<properties>
<sinkJarName>${project.artifactId}-with-common-${project.version}.jar</sinkJarName>
+ <hadoop.version>3.0.0-beta1</hadoop.version>
</properties>
@@ -141,7 +142,7 @@ limitations under the License.
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
- <version>2.4.0</version>
+ <version>${hadoop.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java b/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
index a290ced..bbc9617 100644
--- a/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
+++ b/ambari-metrics/ambari-metrics-hadoop-sink/src/main/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSink.java
@@ -17,7 +17,8 @@
*/
package org.apache.hadoop.metrics2.sink.timeline;
-import org.apache.commons.configuration.SubsetConfiguration;
+import org.apache.commons.configuration2.SubsetConfiguration;
+import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
@@ -34,7 +35,6 @@ import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -143,7 +143,7 @@ public class HadoopTimelineMetricsSink extends AbstractTimelineMetricsSink imple
metricsCache = new TimelineMetricsCache(maxRowCacheSize,
metricsSendInterval, conf.getBoolean(SKIP_COUNTER_TRANSFROMATION, true));
- conf.setListDelimiter(',');
+ conf.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
Iterator<String> it = (Iterator<String>) conf.getKeys();
while (it.hasNext()) {
String propertyName = it.next();
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
----------------------------------------------------------------------
diff --git a/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java b/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
index 30c5c23..6bb6454 100644
--- a/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
+++ b/ambari-metrics/ambari-metrics-hadoop-sink/src/test/java/org/apache/hadoop/metrics2/sink/timeline/HadoopTimelineMetricsSinkTest.java
@@ -19,7 +19,8 @@
package org.apache.hadoop.metrics2.sink.timeline;
import com.google.gson.Gson;
-import org.apache.commons.configuration.SubsetConfiguration;
+import org.apache.commons.configuration2.SubsetConfiguration;
+import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.metrics2.AbstractMetric;
import org.apache.hadoop.metrics2.MetricType;
@@ -74,7 +75,7 @@ import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.verifyAll;
@RunWith(PowerMockRunner.class)
-@PrepareForTest({AbstractTimelineMetricsSink.class, HttpURLConnection.class})
+@PrepareForTest({AbstractTimelineMetricsSink.class, HttpURLConnection.class, SubsetConfiguration.class})
public class HadoopTimelineMetricsSinkTest {
Gson gson = new Gson();
@@ -84,7 +85,7 @@ public class HadoopTimelineMetricsSinkTest {
}
@Test
- @PrepareForTest({URL.class, OutputStream.class, AbstractTimelineMetricsSink.class, HttpURLConnection.class, TimelineMetric.class, HadoopTimelineMetricsSink.class})
+ @PrepareForTest({URL.class, OutputStream.class, AbstractTimelineMetricsSink.class, HttpURLConnection.class, TimelineMetric.class, HadoopTimelineMetricsSink.class, SubsetConfiguration.class})
public void testPutMetrics() throws Exception {
HadoopTimelineMetricsSink sink = new HadoopTimelineMetricsSink();
@@ -102,7 +103,7 @@ public class HadoopTimelineMetricsSinkTest {
OutputStream os = PowerMock.createNiceMock(OutputStream.class);
expect(connection.getOutputStream()).andReturn(os).anyTimes();
- SubsetConfiguration conf = createNiceMock(SubsetConfiguration.class);
+ SubsetConfiguration conf = PowerMock.createNiceMock(SubsetConfiguration.class);
expect(conf.getString("slave.host.name")).andReturn("localhost").anyTimes();
expect(conf.getParent()).andReturn(null).anyTimes();
expect(conf.getPrefix()).andReturn("service").anyTimes();
@@ -116,7 +117,7 @@ public class HadoopTimelineMetricsSinkTest {
expect(conf.getBoolean(eq(SET_INSTANCE_ID_PROPERTY), eq(false))).andReturn(true).anyTimes();
expect(conf.getString(eq(INSTANCE_ID_PROPERTY), anyString())).andReturn("instanceId").anyTimes();
- conf.setListDelimiter(eq(','));
+ conf.setListDelimiterHandler(new DefaultListDelimiterHandler(eq(',')));
expectLastCall().anyTimes();
expect(conf.getKeys()).andReturn(new Iterator() {
@@ -157,7 +158,7 @@ public class HadoopTimelineMetricsSinkTest {
timelineMetric.setInstanceId(eq("instanceId"));
EasyMock.expectLastCall();
- replay(conf, record, metric);
+ replay(record, metric);
replayAll();
sink.init(conf);
@@ -179,7 +180,7 @@ public class HadoopTimelineMetricsSinkTest {
.addMockedMethod("findLiveCollectorHostsFromKnownCollector")
.addMockedMethod("emitMetrics").createNiceMock();
- SubsetConfiguration conf = createNiceMock(SubsetConfiguration.class);
+ SubsetConfiguration conf = PowerMock.createNiceMock(SubsetConfiguration.class);
expect(conf.getString("slave.host.name")).andReturn("localhost").anyTimes();
expect(conf.getParent()).andReturn(null).anyTimes();
expect(conf.getPrefix()).andReturn("service").anyTimes();
@@ -198,7 +199,7 @@ public class HadoopTimelineMetricsSinkTest {
expect(sink.findLiveCollectorHostsFromKnownCollector("localhost2", "6188"))
.andReturn(Collections.singletonList("localhost2")).anyTimes();
- conf.setListDelimiter(eq(','));
+ conf.setListDelimiterHandler(new DefaultListDelimiterHandler(eq(',')));
expectLastCall().anyTimes();
expect(conf.getKeys()).andReturn(new Iterator() {
@@ -309,7 +310,7 @@ public class HadoopTimelineMetricsSinkTest {
.addMockedMethod("findLiveCollectorHostsFromKnownCollector")
.addMockedMethod("emitMetrics").createNiceMock();
- SubsetConfiguration conf = createNiceMock(SubsetConfiguration.class);
+ SubsetConfiguration conf = PowerMock.createNiceMock(SubsetConfiguration.class);
expect(conf.getString("slave.host.name")).andReturn("localhost").anyTimes();
expect(conf.getParent()).andReturn(null).anyTimes();
expect(conf.getPrefix()).andReturn("service").anyTimes();
@@ -326,7 +327,7 @@ public class HadoopTimelineMetricsSinkTest {
expect(conf.getInt(eq(MAX_METRIC_ROW_CACHE_SIZE), anyInt())).andReturn(10).anyTimes();
expect(conf.getInt(eq(METRICS_SEND_INTERVAL), anyInt())).andReturn(10).anyTimes();
- conf.setListDelimiter(eq(','));
+ conf.setListDelimiterHandler(new DefaultListDelimiterHandler(eq(',')));
expectLastCall().anyTimes();
Set<String> rpcPortSuffixes = new HashSet<String>() {{
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/docs/security/kerberos/kerberos_service.md
----------------------------------------------------------------------
diff --git a/ambari-server/docs/security/kerberos/kerberos_service.md b/ambari-server/docs/security/kerberos/kerberos_service.md
index 65e312b..c9cbd49 100644
--- a/ambari-server/docs/security/kerberos/kerberos_service.md
+++ b/ambari-server/docs/security/kerberos/kerberos_service.md
@@ -231,32 +231,12 @@ _Example:_ `-requires_preauth max_renew_life=7d`
This property is optional and only used if the `kdc_type` is `mit-kdc`
-##### group
+##### ipa_user_group
The group in IPA user principals should be member of
This property is mandatory and only used if the `kdc_type` is `ipa`
-##### set_password_expiry
-
-Indicates whether Ambari should set the password expiry for the principals it creates. By default
-IPA does not allow this. It requires write permission of the admin principal to the krbPasswordExpiry
-attribute. If set IPA principal password expiry is not true it is assumed that a suitable password
-policy is in place for the IPA Group principals are added to.
-
-_Possible values:_ `true`, `false`
-
-_Default value:_ `false`
-
-This property is mandatory and only used if the `kdc_type` is `ipa`
-
-##### password_chat_timeout
-
-Indicates the timeout in seconds that Ambari should wait for a response during a password chat. This is
-because it can take some time due to lookups before a response is there.
-
-This property is mandatory and only used if the `kdc_type` is `ipa`
-
<a name="krb5-conf"></a>
#### krb5-conf
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 5e07b3c..7172ed6 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -199,6 +199,18 @@
</target>
</configuration>
</execution>
+ <execution>
+ <id>generate-test-oozie2-server-actions-dir</id>
+ <phase>process-test-classes</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <target>
+ <mkdir dir="target/test-classes/extensions/EXT/0.1/services/OOZIE2/server_actions/tmp"/>
+ </target>
+ </configuration>
+ </execution>
</executions>
</plugin>
<plugin>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
index ed2819a..649f44d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java
@@ -20,7 +20,6 @@ package org.apache.ambari.server.actionmanager;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.VERSION;
-import static org.apache.ambari.server.stack.StackManager.DEFAULT_HOOKS_FOLDER;
import java.util.HashMap;
import java.util.Map;
@@ -31,15 +30,20 @@ import org.apache.ambari.server.ClusterNotFoundException;
import org.apache.ambari.server.RoleCommand;
import org.apache.ambari.server.ServiceNotFoundException;
import org.apache.ambari.server.agent.AgentCommand.AgentCommandType;
+import org.apache.ambari.server.agent.CommandRepository;
import org.apache.ambari.server.agent.ExecutionCommand;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.orm.entities.UpgradeEntity;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.Service;
import org.apache.ambari.server.state.ServiceComponent;
import org.apache.ambari.server.state.ServiceInfo;
@@ -48,6 +52,7 @@ import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.UpgradeContext;
import org.apache.ambari.server.state.UpgradeContext.UpgradeSummary;
import org.apache.ambari.server.state.UpgradeContextFactory;
+import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
@@ -79,12 +84,18 @@ public class ExecutionCommandWrapper {
@Inject
private UpgradeContextFactory upgradeContextFactory;
+ @Inject
+ private RepositoryVersionHelper repoVersionHelper;
+
/**
* Used for injecting hooks and common-services into the command.
*/
@Inject
private AmbariMetaInfo ambariMetaInfo;
+ @Inject
+ private Configuration configuration;
+
@AssistedInject
public ExecutionCommandWrapper(@Assisted String jsonExecutionCommand) {
this.jsonExecutionCommand = jsonExecutionCommand;
@@ -215,9 +226,36 @@ public class ExecutionCommandWrapper {
if (null != upgrade) {
UpgradeContext upgradeContext = upgradeContextFactory.create(cluster, upgrade);
UpgradeSummary upgradeSummary = upgradeContext.getUpgradeSummary();
+
executionCommand.setUpgradeSummary(upgradeSummary);
}
+ // setting repositoryFile
+ final Host host = cluster.getHost(executionCommand.getHostname()); // can be null on internal commands
+ final String serviceName = executionCommand.getServiceName(); // can be null on executing special RU tasks
+
+ if (null == executionCommand.getRepositoryFile() && null != host && null != serviceName) {
+ final CommandRepository commandRepository;
+ final Service service = cluster.getService(serviceName);
+ final String componentName = executionCommand.getComponentName();
+
+ try {
+
+ if (null != componentName) {
+ ServiceComponent serviceComponent = service.getServiceComponent(componentName);
+ commandRepository = repoVersionHelper.getCommandRepository(null, serviceComponent, host);
+ } else {
+ RepositoryVersionEntity repoVersion = service.getDesiredRepositoryVersion();
+ OperatingSystemEntity osEntity = repoVersionHelper.getOSEntityForHost(host, repoVersion);
+ commandRepository = repoVersionHelper.getCommandRepository(repoVersion, osEntity);
+ }
+ executionCommand.setRepositoryFile(commandRepository);
+
+ } catch (SystemException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
} catch (ClusterNotFoundException cnfe) {
// it's possible that there are commands without clusters; in such cases,
// just return the de-serialized command and don't try to read configs
@@ -271,7 +309,7 @@ public class ExecutionCommandWrapper {
stackId.getStackVersion());
if (!commandParams.containsKey(HOOKS_FOLDER)) {
- commandParams.put(HOOKS_FOLDER, DEFAULT_HOOKS_FOLDER);
+ commandParams.put(HOOKS_FOLDER,configuration.getProperty(Configuration.HOOKS_FOLDER));
}
if (!commandParams.containsKey(SERVICE_PACKAGE_FOLDER)) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
index a70326e..449d2d5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/CommandRepository.java
@@ -51,7 +51,7 @@ public class CommandRepository {
private String m_repoFileName;
@SerializedName("feature")
- private CommandRepositoryFeature feature = new CommandRepositoryFeature();
+ private final CommandRepositoryFeature feature = new CommandRepositoryFeature();
/**
* Provides {@link CommandRepository} feature
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
index 9198164..5ee4bf6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/ExecutionCommand.java
@@ -160,6 +160,9 @@ public class ExecutionCommand extends AgentCommand {
@SerializedName("upgradeSummary")
private UpgradeSummary upgradeSummary;
+ @SerializedName("roleParameters")
+ private Map<String, Object> roleParameters;
+
public void setConfigurationCredentials(Map<String, Map<String, String>> configurationCredentials) {
this.configurationCredentials = configurationCredentials;
}
@@ -235,6 +238,10 @@ public class ExecutionCommand extends AgentCommand {
return roleParams;
}
+ /**
+ * Sets the roleParams for the command. Consider instead using {@link #setRoleParameters}
+ * @param roleParams
+ */
public void setRoleParams(Map<String, String> roleParams) {
this.roleParams = roleParams;
}
@@ -332,11 +339,11 @@ public class ExecutionCommand extends AgentCommand {
}
public String getServiceType() {
- return serviceType;
+ return serviceType;
}
public void setServiceType(String serviceType) {
- this.serviceType = serviceType;
+ this.serviceType = serviceType;
}
/**
@@ -413,6 +420,23 @@ public class ExecutionCommand extends AgentCommand {
}
/**
+ * Gets the object-based role parameters for the command.
+ */
+ public Map<String, Object> getRoleParameters() {
+ return roleParameters;
+ }
+
+ /**
+ * Sets the role parameters for the command. This is preferred over {@link #setRoleParams(Map)},
+ * as this form will pass values as structured data, as opposed to unstructured, escaped json.
+ *
+ * @param params
+ */
+ public void setRoleParameters(Map<String, Object> params) {
+ roleParameters = params;
+ }
+
+ /**
* Contains key name strings. These strings are used inside maps
* incapsulated inside command.
*/
@@ -432,6 +456,7 @@ public class ExecutionCommand extends AgentCommand {
String PACKAGE_LIST = "package_list";
String JDK_LOCATION = "jdk_location";
String JAVA_HOME = "java_home";
+ String GPL_LICENSE_ACCEPTED = "gpl_license_accepted";
String AMBARI_JAVA_HOME = "ambari_java_home";
String AMBARI_JDK_NAME = "ambari_jdk_name";
String AMBARI_JCE_NAME = "ambari_jce_name";
@@ -512,6 +537,12 @@ public class ExecutionCommand extends AgentCommand {
feature = ExperimentalFeature.PATCH_UPGRADES,
comment = "Change this to reflect the component version")
String VERSION = "version";
+
+
+ /**
+ * When installing packages, includes what services will be included in the upgrade
+ */
+ String CLUSTER_VERSION_SUMMARY = "cluster_version_summary";
}
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
index 4be62cb..4ca34c4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatMonitor.java
@@ -25,7 +25,6 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TY
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
-import static org.apache.ambari.server.stack.StackManager.DEFAULT_HOOKS_FOLDER;
import java.util.ArrayList;
import java.util.Collection;
@@ -343,7 +342,7 @@ public class HeartbeatMonitor implements Runnable {
commandParams.put(COMMAND_TIMEOUT, commandTimeout);
commandParams.put(SERVICE_PACKAGE_FOLDER,
serviceInfo.getServicePackageFolder());
- commandParams.put(HOOKS_FOLDER, DEFAULT_HOOKS_FOLDER);
+ commandParams.put(HOOKS_FOLDER, configuration.getProperty(Configuration.HOOKS_FOLDER));
// Fill host level params
Map<String, String> hostLevelParams = statusCmd.getHostLevelParams();
hostLevelParams.put(JDK_LOCATION, ambariManagementController.getJdkResourceUrl());
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
index 3dae84b..9eefda2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java
@@ -52,7 +52,9 @@ import org.apache.ambari.server.events.publishers.AlertEventPublisher;
import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
import org.apache.ambari.server.events.publishers.VersionEventPublisher;
import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.dao.KerberosKeytabDAO;
import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
+import org.apache.ambari.server.orm.entities.KerberosPrincipalHostEntity;
import org.apache.ambari.server.state.Alert;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
@@ -88,7 +90,6 @@ import com.google.inject.Injector;
/**
* HeartbeatProcessor class is used for bulk processing data retrieved from agents in background
- *
*/
public class HeartbeatProcessor extends AbstractService{
private static final Logger LOG = LoggerFactory.getLogger(HeartbeatProcessor.class);
@@ -135,6 +136,9 @@ public class HeartbeatProcessor extends AbstractService{
KerberosPrincipalHostDAO kerberosPrincipalHostDAO;
@Inject
+ KerberosKeytabDAO kerberosKeytabDao;
+
+ @Inject
Gson gson;
@Inject
@@ -153,7 +157,7 @@ public class HeartbeatProcessor extends AbstractService{
@Override
protected void doStart() {
LOG.info("**** Starting heartbeats processing threads ****");
- for (int i=0; i< poolSize; i++) {
+ for (int i = 0; i < poolSize; i++) {
executor.scheduleAtFixedRate(new HeartbeatProcessingTask(), delay, period, TimeUnit.MILLISECONDS);
}
}
@@ -201,6 +205,7 @@ public class HeartbeatProcessor extends AbstractService{
/**
* Incapsulates logic for processing data from agent heartbeat
+ *
* @param heartbeat Agent heartbeat object
* @throws AmbariException
*/
@@ -217,14 +222,12 @@ public class HeartbeatProcessor extends AbstractService{
}
-
/**
* Extracts all of the {@link Alert}s from the heartbeat and fires
* {@link AlertEvent}s for each one. If there is a problem looking up the
* cluster, then alerts will not be processed.
*
- * @param heartbeat
- * the heartbeat to process.
+ * @param heartbeat the heartbeat to process.
*/
protected void processAlerts(HeartBeat heartbeat) {
if (heartbeat == null) {
@@ -247,6 +250,7 @@ public class HeartbeatProcessor extends AbstractService{
/**
* Update host status basing on components statuses
+ *
* @param heartbeat heartbeat to process
* @throws AmbariException
*/
@@ -349,8 +353,9 @@ public class HeartbeatProcessor extends AbstractService{
/**
* Process reports of tasks executed on agents
+ *
* @param heartbeat heartbeat to process
- * @param now cached current time
+ * @param now cached current time
* @throws AmbariException
*/
protected void processCommandReports(
@@ -424,8 +429,7 @@ public class HeartbeatProcessor extends AbstractService{
String customCommand = report.getCustomCommand();
- boolean adding = SET_KEYTAB.equalsIgnoreCase(customCommand);
- if (adding || REMOVE_KEYTAB.equalsIgnoreCase(customCommand)) {
+ if (SET_KEYTAB.equalsIgnoreCase(customCommand) || REMOVE_KEYTAB.equalsIgnoreCase(customCommand)) {
WriteKeytabsStructuredOut writeKeytabsStructuredOut;
try {
writeKeytabsStructuredOut = gson.fromJson(report.getStructuredOut(), WriteKeytabsStructuredOut.class);
@@ -435,25 +439,35 @@ public class HeartbeatProcessor extends AbstractService{
}
if (writeKeytabsStructuredOut != null) {
- Map<String, String> keytabs = writeKeytabsStructuredOut.getKeytabs();
- if (keytabs != null) {
- for (Map.Entry<String, String> entry : keytabs.entrySet()) {
- String principal = entry.getKey();
- if (!kerberosPrincipalHostDAO.exists(principal, host.getHostId())) {
- if (adding) {
- kerberosPrincipalHostDAO.create(principal, host.getHostId());
- } else if ("_REMOVED_".equalsIgnoreCase(entry.getValue())) {
- kerberosPrincipalHostDAO.remove(principal, host.getHostId());
- }
+ if (SET_KEYTAB.equalsIgnoreCase(customCommand)) {
+ Map<String, String> keytabs = writeKeytabsStructuredOut.getKeytabs();
+ if (keytabs != null) {
+ for (Map.Entry<String, String> entry : keytabs.entrySet()) {
+ String principal = entry.getKey();
+ String keytabPath = entry.getValue();
+ KerberosPrincipalHostEntity kphe = kerberosPrincipalHostDAO.find(principal, host.getHostId(), keytabPath);
+ kphe.setDistributed(true);
+ kerberosPrincipalHostDAO.merge(kphe);
+ }
+ }
+ } else if (REMOVE_KEYTAB.equalsIgnoreCase(customCommand)) {
+ Map<String, String> deletedKeytabs = writeKeytabsStructuredOut.getRemovedKeytabs();
+ if (deletedKeytabs != null) {
+ for (Map.Entry<String, String> entry : deletedKeytabs.entrySet()) {
+ String keytabPath = entry.getValue();
+ kerberosPrincipalHostDAO.removeByKeytabPath(keytabPath);
+ kerberosKeytabDao.remove(keytabPath);
}
}
}
}
} else if (CHECK_KEYTABS.equalsIgnoreCase(customCommand)) {
ListKeytabsStructuredOut structuredOut = gson.fromJson(report.getStructuredOut(), ListKeytabsStructuredOut.class);
- for (MissingKeytab each : structuredOut.missingKeytabs){
- LOG.info("Missing keytab: {} on host: {} principal: {}", each.keytabFilePath, hostname, each.principal);
- kerberosPrincipalHostDAO.remove(each.principal, host.getHostId());
+ for (MissingKeytab each : structuredOut.missingKeytabs) {
+ LOG.info("Missing principal: {} for keytab: {} on host: {}", each.principal, each.keytabFilePath, hostname);
+ KerberosPrincipalHostEntity kphe = kerberosPrincipalHostDAO.find(each.principal, host.getHostId(), each.keytabFilePath);
+ kphe.setDistributed(false);
+ kerberosPrincipalHostDAO.merge(kphe);
}
}
}
@@ -518,7 +532,7 @@ public class HeartbeatProcessor extends AbstractService{
// Necessary for resetting clients stale configs after starting service
if ((RoleCommand.INSTALL.toString().equals(report.getRoleCommand()) ||
(RoleCommand.CUSTOM_COMMAND.toString().equals(report.getRoleCommand()) &&
- "INSTALL".equals(report.getCustomCommand()))) && svcComp.isClientComponent()){
+ "INSTALL".equals(report.getCustomCommand()))) && svcComp.isClientComponent()) {
scHost.updateActualConfigs(report.getConfigurationTags());
scHost.setRestartRequired(false);
}
@@ -589,6 +603,7 @@ public class HeartbeatProcessor extends AbstractService{
/**
* Process reports of status commands
+ *
* @param heartbeat heartbeat to process
* @throws AmbariException
*/
@@ -702,7 +717,10 @@ public class HeartbeatProcessor extends AbstractService{
*/
private static class WriteKeytabsStructuredOut {
@SerializedName("keytabs")
- private Map<String,String> keytabs;
+ private Map<String, String> keytabs;
+
+ @SerializedName("removedKeytabs")
+ private Map<String, String> removedKeytabs;
public Map<String, String> getKeytabs() {
return keytabs;
@@ -711,6 +729,14 @@ public class HeartbeatProcessor extends AbstractService{
public void setKeytabs(Map<String, String> keytabs) {
this.keytabs = keytabs;
}
+
+ public Map<String, String> getRemovedKeytabs() {
+ return removedKeytabs;
+ }
+
+ public void setRemovedKeytabs(Map<String, String> removedKeytabs) {
+ this.removedKeytabs = removedKeytabs;
+ }
}
private static class ListKeytabsStructuredOut {
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java
index d0bd5d3..1fa55eb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java
@@ -36,20 +36,12 @@ import org.apache.ambari.server.controller.spi.RequestStatus;
import org.apache.ambari.server.controller.spi.RequestStatusMetaData;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Base handler for operations that persist state to the back-end.
*/
public abstract class BaseManagementHandler implements RequestHandler {
- /**
- * Logger instance.
- */
- protected final static Logger LOG =
- LoggerFactory.getLogger(BaseManagementHandler.class);
-
public static final String RESOURCES_NODE_NAME = "resources";
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
index 549da76..b614c5e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
@@ -31,6 +31,8 @@ import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.security.authorization.AuthorizationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
@@ -38,6 +40,8 @@ import org.apache.ambari.server.security.authorization.AuthorizationException;
*/
public class CreateHandler extends BaseManagementHandler {
+ private final static Logger LOG = LoggerFactory.getLogger(CreateHandler.class);
+
@Override
protected Result persist(ResourceInstance resource, RequestBody body) {
Result result;
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index 2d2e75e..85ba768 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -289,6 +289,11 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
resourceDefinition = new RootServiceComponentResourceDefinition();
break;
+ case RootServiceComponentConfiguration:
+ resourceDefinition = new SimpleResourceDefinition(Resource.Type.RootServiceComponentConfiguration,
+ "configuration", "configurations");
+ break;
+
case RootServiceHostComponent:
resourceDefinition = new RootServiceHostComponentResourceDefinition();
break;
@@ -523,10 +528,6 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
case RemoteCluster:
resourceDefinition = new RemoteClusterResourceDefinition();
break;
- case AmbariConfiguration:
- resourceDefinition = new SimpleResourceDefinition(Resource.Type.AmbariConfiguration, "ambariconfiguration", "ambariconfigurations");
-
- break;
default:
throw new IllegalArgumentException("Unsupported resource type: " + type);
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootServiceComponentResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootServiceComponentResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootServiceComponentResourceDefinition.java
index e8cb570..1c036e4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootServiceComponentResourceDefinition.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/RootServiceComponentResourceDefinition.java
@@ -19,6 +19,7 @@
package org.apache.ambari.server.api.resources;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Set;
import org.apache.ambari.server.controller.spi.Resource;
@@ -44,10 +45,12 @@ public class RootServiceComponentResourceDefinition extends
public String getSingularName() {
return "component";
}
-
+
@Override
public Set<SubResourceDefinition> getSubResourceDefinitions() {
- return Collections.singleton(new SubResourceDefinition(
- Resource.Type.RootServiceHostComponent, Collections.singleton(Resource.Type.Host), true));
+ Set<SubResourceDefinition> definitions = new HashSet<>();
+ definitions.add(new SubResourceDefinition(Resource.Type.RootServiceHostComponent, Collections.singleton(Resource.Type.Host), true));
+ definitions.add(new SubResourceDefinition(Resource.Type.RootServiceComponentConfiguration));
+ return definitions;
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java
deleted file mode 100644
index 5e8094e..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationRequestSwagger.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.api.services;
-
-import java.util.Map;
-
-import org.apache.ambari.server.controller.ApiModel;
-
-import io.swagger.annotations.ApiModelProperty;
-
-/**
- * Request data model for {@link org.apache.ambari.server.api.services.AmbariConfigurationService}
- */
-public interface AmbariConfigurationRequestSwagger extends ApiModel {
-
- @ApiModelProperty(name = "AmbariConfiguration")
- AmbariConfigurationRequestInfo getAmbariConfiguration();
-
- interface AmbariConfigurationRequestInfo {
- @ApiModelProperty
- Long getId();
-
- @ApiModelProperty
- Map<String, Object> getData();
-
- @ApiModelProperty
- String getType();
-
- @ApiModelProperty
- Long getVersion();
-
- @ApiModelProperty(name = "version_tag")
- String getVersionTag();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java
deleted file mode 100644
index c55ac1d..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationResponseSwagger.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.server.api.services;
-
-import java.util.Map;
-
-import org.apache.ambari.server.controller.ApiModel;
-
-import io.swagger.annotations.ApiModelProperty;
-
-/**
- * Response data model for {@link org.apache.ambari.server.api.services.AmbariConfigurationService}
- */
-public interface AmbariConfigurationResponseSwagger extends ApiModel {
-
- @ApiModelProperty(name = "AmbariConfiguration")
- AmbariConfigurationResponseInfo getAmbariConfigurationResponse();
-
- interface AmbariConfigurationResponseInfo {
- @ApiModelProperty
- Long getId();
-
- @ApiModelProperty
- Map<String, Object> getData();
-
- @ApiModelProperty
- String getType();
- }
-}