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(); - } -}
