From d3a9f366fb52e0fbee464eeb49812a196dc1ba3c Mon Sep 17 00:00:00 2001 From: Eduard Schander <66794307+EddeCCC@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:38:32 +0100 Subject: [PATCH] Update git staging (#1622) * show agent_mapppings.yml in promotion list * enable promotion of agent mappings to live branch * add sourceBranch to AgentMappingSerializer * add configuration reload, when agent mapping source branch changed * add check if agent mapping exit on newly set source branch * include agent_mappings.yaml into initial staging * refactor and add AgentMapping tests * change initial source branch * include versioning to AgentMappingController * add dropdown menu to change mappings source branch * show current source branch in dropdown menu * add Versioning sidebar and apply selected version * add notice, if not latest version is selected * add data-tip to dropdown menu * refactor agent mapping css * generalise promotion namings * add dialog before changeing source branch * fix formatting * update documentation * add configurable initial source branch --- .../src/components/editor/EditorView.js | 2 +- .../configuration/ConfigurationSidebar.js | 4 +- .../views/configuration/ConfigurationView.js | 4 +- .../views/configuration/FileToolbar.js | 2 +- ...oryView.js => ConfigurationHistoryView.js} | 8 +- .../views/mappings/AgentMappingsView.js | 65 ++++++- .../views/mappings/MappingSidebar.js | 66 +++++++ .../views/mappings/MappingToolbar.js | 102 +++++++++-- .../views/mappings/MappingsTable.js | 136 +++++++------- .../components/views/mappings/SidebarTypes.js | 6 + .../dialogs/ChangeSourceBranchDialog.js | 50 ++++++ .../mappings/history/MappingsHistoryView.js | 94 ++++++++++ .../views/promotion/PromotionFileApproval.js | 2 +- .../views/promotion/PromotionFileView.js | 4 +- .../views/promotion/PromotionSidebar.js | 4 +- .../views/promotion/PromotionToolbar.js | 4 +- .../views/promotion/PromotionView.js | 12 +- .../dialogs/PromotionConflictDialog.js | 4 +- .../views/status/dialogs/ClearDialog.js | 6 +- .../src/data/side-navigation-items.json | 2 +- .../src/redux/ducks/configuration/actions.js | 10 +- .../src/redux/ducks/initial-states.js | 10 +- .../src/redux/ducks/mappings/actions.js | 109 +++++++++++- .../src/redux/ducks/mappings/reducers.js | 113 +++++++++--- .../src/redux/ducks/mappings/selectors.js | 20 +++ .../src/redux/ducks/mappings/types.js | 14 ++ .../AgentConfigurationManager.java | 5 +- .../AgentConfigurationReloadTask.java | 8 +- .../config/model/InspectitServerSettings.java | 5 + ...AgentMappingsSourceBranchChangedEvent.java | 18 ++ ...romotionEvent.java => PromotionEvent.java} | 6 +- .../inspectit/ocelot/file/FileManager.java | 12 +- .../file/accessor/git/RevisionAccess.java | 36 +++- .../versioning/ExternalChangeDetector.java | 6 +- .../file/versioning/VersioningManager.java | 166 ++++++++++++++---- ...igurationPromotion.java => Promotion.java} | 4 +- .../versioning/model/SimpleDiffEntry.java | 3 + .../ocelot/mappings/AgentMappingManager.java | 58 +++++- .../mappings/AgentMappingSerializer.java | 68 +++++++ .../ocelot/rest/file/DirectoryController.java | 2 +- .../rest/mappings/AgentMappingController.java | 39 +++- .../PromotionController.java | 14 +- .../src/main/resources/application.yml | 2 + .../AgentConfigurationManagerTest.java | 1 + .../AgentConfigurationReloadTaskTest.java | 68 +++++-- .../ExternalChangeDetectorTest.java | 8 +- .../versioning/VersioningManagerTest.java | 112 ++++++++---- .../mappings/AgentMappingManagerTest.java | 45 ++++- .../mappings/AgentMappingSerializerTest.java | 64 +++++-- .../mappings/AgentMappingControllerTest.java | 8 +- .../PromotionControllerIntTest.java | 42 ++--- .../VersioningControllerIntTest.java | 10 +- .../assets/agent_mappings_source_branch.png | Bin 0 -> 226287 bytes .../docs/config-server/agent-mappings.md | 39 +++- ...figuration-staging.md => files-staging.md} | 12 +- ...ng-configurations.md => managing-files.md} | 41 +++-- .../website/sidebars.json | 4 +- 57 files changed, 1424 insertions(+), 335 deletions(-) rename components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/history/{HistoryView.js => ConfigurationHistoryView.js} (92%) create mode 100644 components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingSidebar.js create mode 100644 components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/SidebarTypes.js create mode 100644 components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/dialogs/ChangeSourceBranchDialog.js create mode 100644 components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/history/MappingsHistoryView.js create mode 100644 components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/AgentMappingsSourceBranchChangedEvent.java rename components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/{ConfigurationPromotionEvent.java => PromotionEvent.java} (73%) rename components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/{ConfigurationPromotion.java => Promotion.java} (92%) rename components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/{configuration => promotion}/PromotionController.java (84%) rename components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/{configuration => promotion}/PromotionControllerIntTest.java (76%) create mode 100644 inspectit-ocelot-documentation/docs/assets/agent_mappings_source_branch.png rename inspectit-ocelot-documentation/docs/config-server/{configuration-staging.md => files-staging.md} (95%) rename inspectit-ocelot-documentation/docs/config-server/{managing-configurations.md => managing-files.md} (64%) diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/editor/EditorView.js b/components/inspectit-ocelot-configurationserver-ui/src/components/editor/EditorView.js index 3358e676ec..c26e29a027 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/editor/EditorView.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/editor/EditorView.js @@ -56,7 +56,7 @@ const EditorView = ({ const configurationType = getConfigurationType(value); const selectlatestVersion = () => { - dispatch(configurationActions.selectVersion(null)); + dispatch(configurationActions.selectConfigurationVersion(null)); }; let editorContent; diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationSidebar.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationSidebar.js index e9f81a4afd..c2610efa25 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationSidebar.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationSidebar.js @@ -1,6 +1,6 @@ import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; -import HistoryView from './history/HistoryView'; +import ConfigurationHistoryView from './history/ConfigurationHistoryView'; import { configurationActions } from '../../../redux/ducks/configuration'; import DocumentationView from './documentation/DocumentationView'; import SidebarTypes from './SidebarTypes'; @@ -53,7 +53,7 @@ const ConfigurationSidebar = () => {
- {currentSidebar == SidebarTypes.HISTORY && } + {currentSidebar == SidebarTypes.HISTORY && } {currentSidebar == SidebarTypes.CONFIGURATION_DOCS && }
diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationView.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationView.js index 7ad7808beb..1a3498059d 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationView.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/ConfigurationView.js @@ -363,10 +363,10 @@ const mapDispatchToProps = { showWarning: notificationActions.showWarningMessage, writeFile: configurationActions.writeFile, selectedFileContentsChanged: configurationActions.selectedFileContentsChanged, - selectVersion: configurationActions.selectVersion, + selectVersion: configurationActions.selectConfigurationVersion, toggleVisualConfigurationView: configurationActions.toggleVisualConfigurationView, selectFile: configurationActions.selectFile, - fetchVersions: configurationActions.fetchVersions, + fetchVersions: configurationActions.fetchConfigurationVersions, toggleShowHiddenFiles: configurationActions.toggleShowHiddenFiles, }; diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/FileToolbar.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/FileToolbar.js index bc02e89ac9..cb5d442cb0 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/FileToolbar.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/FileToolbar.js @@ -30,7 +30,7 @@ const FileToolbar = ({ const showHiddenFiles = useSelector((state) => state.configuration.showHiddenFiles) || ''; const reloadFiles = () => { - dispatch(configurationActions.selectVersion(null)); + dispatch(configurationActions.selectConfigurationVersion(null)); }; return ( diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/history/HistoryView.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/history/ConfigurationHistoryView.js similarity index 92% rename from components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/history/HistoryView.js rename to components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/history/ConfigurationHistoryView.js index 94cb303886..3b382dda53 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/history/HistoryView.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/configuration/history/ConfigurationHistoryView.js @@ -7,7 +7,7 @@ import { VERSION_LIMIT } from '../../../../data/constants'; /** * The sidebar panel for showing existing versions of the configuration files. */ -const HistoryView = () => { +const ConfigurationHistoryView = () => { const dispatch = useDispatch(); // global state variables @@ -19,12 +19,12 @@ const HistoryView = () => { useEffect(() => { if (versions.length === 0) { - dispatch(configurationActions.fetchVersions()); + dispatch(configurationActions.fetchConfigurationVersions()); } }, []); const selectVersion = (versionId) => { - dispatch(configurationActions.selectVersion(versionId)); + dispatch(configurationActions.selectConfigurationVersion(versionId)); }; const createVersionItem = (item, index) => { @@ -91,4 +91,4 @@ const HistoryView = () => { ); }; -export default HistoryView; +export default ConfigurationHistoryView; diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/AgentMappingsView.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/AgentMappingsView.js index 522e0d199d..10f684c0a7 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/AgentMappingsView.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/AgentMappingsView.js @@ -1,40 +1,74 @@ import React, { useState } from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import MappingsToolbar from './MappingToolbar'; import MappingsTable from './MappingsTable'; import EditDialog from './dialogs/EditDialog'; import DownloadDialog from './dialogs/DownloadDialog'; +import MappingSidebar from './MappingSidebar'; +import { mappingsActions, mappingsSelectors } from '../../../redux/ducks/mappings'; /** View to display and change mappings */ const AgentMappingView = () => { - const readOnly = useSelector((state) => !state.authentication.permissions.write); + const dispatch = useDispatch(); + let isAdmin = useSelector((state) => state.authentication.permissions.admin); + let readOnly = useSelector((state) => !state.authentication.permissions.write && !isAdmin); const [mappingsFilter, setMappingsFilter] = useState(''); const [mappingToEdit, setMappingToEdit] = useState(null); const [isEditDialogShown, setEditDialogShown] = useState(false); const [isDownloadDialogShown, setDownloadDialogShown] = useState(false); + // global state variables + const currentVersion = useSelector((state) => state.mappings.selectedVersion); + const isLatest = useSelector(mappingsSelectors.isLatestVersion); + + // derived variables + const isLiveSelected = currentVersion === 'live'; + + const selectLatestVersion = () => { + dispatch(mappingsActions.selectMappingsVersion(null)); + }; const showEditMappingDialog = (selectedMapping = null) => { setMappingToEdit(selectedMapping); setEditDialogShown(true); }; - const contentHeight = 'calc(100vh - 7rem)'; + const contentHeight = 'calc(100vh - 10rem)'; + // Disable editing, if not latest workspace is selected + readOnly = !isLatest ? true : readOnly; return (
{ onAddNewMapping={showEditMappingDialog} onDownload={() => setDownloadDialogShown(true)} readOnly={readOnly} + isAdmin={isAdmin} />
+ {!isLatest && ( +
+ + {isLiveSelected ? ( +
+ You are viewing the latest live agent mappings. Modifications are only possible on the latest workspace agent + mappings. +
+ ) : ( +
+ You are viewing not the latest workspace agent mappings. Modifications are only possible on the latest workspace agent + mappings. +
+ )} +
+ Go to latest workspace +
+
+ )}
{ onDuplicateMapping={showEditMappingDialog} maxHeight={`calc(${contentHeight} - 2.5em)`} readOnly={readOnly} + sidebar={} />
setEditDialogShown(false)} mapping={mappingToEdit} /> diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingSidebar.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingSidebar.js new file mode 100644 index 0000000000..628a1f4c0a --- /dev/null +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingSidebar.js @@ -0,0 +1,66 @@ +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import MappingsHistoryView from './history/MappingsHistoryView'; +import SidebarTypes from './SidebarTypes'; +import { mappingsActions } from '../../../redux/ducks/mappings'; + +/** + * The sidebar of the configuration view. + */ +const MappingSidebar = () => { + const dispatch = useDispatch(); + + // global state variables + const currentSidebar = useSelector((state) => state.mappings.currentSidebar); + + const toggleHistoryView = () => { + dispatch(mappingsActions.toggleHistoryView()); + }; + + return ( + <> + + +
+
{currentSidebar == SidebarTypes.HISTORY && }
+
+ +
+
+ + ); +}; + +MappingSidebar.propTypes = {}; + +export default MappingSidebar; diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingToolbar.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingToolbar.js index 1d7ad7b9b9..2c581dbb51 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingToolbar.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingToolbar.js @@ -3,22 +3,40 @@ import { connect } from 'react-redux'; import { mappingsActions } from '../../../redux/ducks/mappings'; import { Toolbar } from 'primereact/toolbar'; import { InputText } from 'primereact/inputtext'; +import { Dropdown } from 'primereact/dropdown'; import { Button } from 'primereact/button'; +import PropTypes from 'prop-types'; +import ReactTooltip from 'react-tooltip'; +import ChangeSourceBranchDialog from './dialogs/ChangeSourceBranchDialog'; const searchFieldTooltipText = 'Enter a mapping name, a source or an attribute key/value pair to filter matching mappings. The filter is not case sensitive.'; /** Toolbar for mappingsView for changing mappings filter, downloading config files, reloading & adding mappings */ class MappingToolbar extends React.Component { + state = { + isChangeSourceBranchDialogShown: false, + selectedSourceBranch: '', + }; + onChange = (event) => { + const selectedBranch = event.target.value; + if (selectedBranch) { + this.setState({ isChangeSourceBranchDialogShown: true }); + this.setState({ selectedSourceBranch: selectedBranch }); + } + }; + componentDidMount = () => { + this.props.fetchSourceBranch(); + }; render() { - const { filterValue, onChangeFilter, onAddNewMapping, onDownload, fetchMappings, readOnly } = this.props; + const { filterValue, onChangeFilter, onAddNewMapping, onDownload, fetchMappings, readOnly, isAdmin, sourceBranch } = this.props; return (
-
- -

Agent Mappings

- onChangeFilter(e.target.value)} - tooltip={searchFieldTooltipText} - /> + <> +
+
+ +

Agent Mappings

+ onChangeFilter(e.target.value)} + tooltip={searchFieldTooltipText} + /> +
-
+
+

Source Branch

+
+ this.onChange(e)} options={['WORKSPACE', 'LIVE']} /> +
+ + ? + + +
+ } right={
@@ -57,13 +107,35 @@ class MappingToolbar extends React.Component {
} /> + this.setState({ isChangeSourceBranchDialogShown: false })} + selectedSourceBranch={this.state.selectedSourceBranch} + />
); } } +MappingToolbar.propTypes = { + /** The source branch for the agent mappings file itself */ + sourceBranch: PropTypes.string, + /** Fetch current source branch */ + fetchSourceBranch: PropTypes.func, + /** Update current source branch */ + putSourceBranch: PropTypes.func, +}; + +const mapStateToProps = (state) => { + let sourceBranch = state.mappings.sourceBranch; + return { + sourceBranch: sourceBranch, + }; +}; + const mapDispatchToProps = { fetchMappings: mappingsActions.fetchMappings, + fetchSourceBranch: mappingsActions.fetchMappingsSourceBranch, }; -export default connect(null, mapDispatchToProps)(MappingToolbar); +export default connect(mapStateToProps, mapDispatchToProps)(MappingToolbar); diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingsTable.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingsTable.js index 4fd6763cc9..6ae86c37b3 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingsTable.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/MappingsTable.js @@ -205,7 +205,7 @@ class MappingsTable extends React.Component { hideDeleteMappingDialog = () => this.setState({ isDeleteDialogShown: false, selectedMappingName: null }); render() { - const { readOnly, filterValue, maxHeight, mappings, putMappings } = this.props; + const { readOnly, filterValue, maxHeight, mappings, putMappings, sidebar } = this.props; const mappingValues = mappings.map((mapping) => { //build a dummy string to allow filtering @@ -231,101 +231,109 @@ class MappingsTable extends React.Component { display: flex; text-align: center; } - .cell-text { display: inline-block; white-space: normal; overflow: visible; overflow-wrap: anywhere; } - + .table-and-sidebar { + display: flex; + flex: 1 1 auto; + overflow: auto; + position: inherit; + } + .table { + flex: 1; + } + .versioning-sidebar { + flex: 0; + } .drag-icon-col { width: 10rem; } - .mapping-name-col { width: -moz-available; width: -webkit-fill-available; width: fill-available; } - .source-branch-col { width: 40rem; } - .sources-col { width: -moz-available; width: -webkit-fill-available; width: fill-available; } - .attributes-col { width: -moz-available; width: -webkit-fill-available; width: fill-available; } - .buttons-col { width: 15rem; } `} -
(this.mappingsTable = el)}> - { - putMappings(e.value); - }} - globalFilter={filterValue} - > - {!readOnly && } - - } - /> - } - header="Sources" - /> - } - header="Attributes" - /> - ( - - )} +
+
(this.mappingsTable = el)}> + { + putMappings(e.value); + }} + globalFilter={filterValue} + > + {!readOnly && } + + } + /> + } + header="Sources" + /> + } + header="Attributes" + /> + ( + + )} + /> + + - - - {/** reference is used for calling onDownload within ButtonCell component */} - (this.configDownload = ref)} /> + {/** reference is used for calling onDownload within ButtonCell component */} + (this.configDownload = ref)} /> +
+
{sidebar}
); diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/SidebarTypes.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/SidebarTypes.js new file mode 100644 index 0000000000..cd6d6b3c62 --- /dev/null +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/SidebarTypes.js @@ -0,0 +1,6 @@ +const SidebarTypes = { + NONE: 0, + HISTORY: 1, +}; + +export default SidebarTypes; diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/dialogs/ChangeSourceBranchDialog.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/dialogs/ChangeSourceBranchDialog.js new file mode 100644 index 0000000000..d032897898 --- /dev/null +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/dialogs/ChangeSourceBranchDialog.js @@ -0,0 +1,50 @@ +import React from 'react'; +import { connect } from 'react-redux'; + +import { Button } from 'primereact/button'; +import { Dialog } from 'primereact/dialog'; +import { mappingsActions } from '../../../../redux/ducks/mappings'; + +/** + * Dialog for changing the agent mappings source branch + */ +class ChangeSourceBranchDialog extends React.Component { + changeSourceBranch = (selectedSourceBranch) => { + if (selectedSourceBranch) { + this.props.putSourceBranch(selectedSourceBranch); + } + this.props.onHide(); + }; + render() { + return ( + +
+ } + > + Are you sure that you want to change the source branch for +

the agent mappings configuration to {this.props.selectedSourceBranch}? + + ); + } + + changeAndHide = () => { + const selectedBranch = this.props.selectedSourceBranch; + this.changeSourceBranch(selectedBranch); + this.props.onHide(); + }; +} + +const mapDispatchToProps = { + putSourceBranch: mappingsActions.putMappingsSourceBranch, +}; + +export default connect(null, mapDispatchToProps)(ChangeSourceBranchDialog); diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/history/MappingsHistoryView.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/history/MappingsHistoryView.js new file mode 100644 index 0000000000..2cc78d4df7 --- /dev/null +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/mappings/history/MappingsHistoryView.js @@ -0,0 +1,94 @@ +import React, { useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import VersionItem from '../../configuration/history/VersionItem'; +import { VERSION_LIMIT } from '../../../../data/constants'; +import { mappingsActions } from '../../../../redux/ducks/mappings'; + +/** + * The sidebar panel for showing existing versions of the agent mappings. + */ +const MappingsHistoryView = () => { + const dispatch = useDispatch(); + + // global state variables + const versions = useSelector((state) => state.mappings.versions); + const currentVersion = useSelector((state) => state.mappings.selectedVersion); + + // derived variables + const limitReached = versions.length >= VERSION_LIMIT; + + useEffect(() => { + if (versions.length === 0) { + dispatch(mappingsActions.fetchMappingsVersions()); + } + }, []); + + const selectVersion = (versionId) => { + dispatch(mappingsActions.selectMappingsVersion(versionId)); + }; + + const createVersionItem = (item, index) => { + const { id, author, date } = item; + const isLatest = index === 0; + const isSelected = currentVersion === item.id || (currentVersion === null && isLatest); + return ( + selectVersion(isLatest ? null : item.id)} + isLatest={isLatest} + /> + ); + }; + + return ( + <> + + +
+
Live Agent Mappings
+ selectVersion('live')} isLatest={false} /> + +
Workspace Agent Mappings
+ + {versions.map(createVersionItem)} + + {limitReached &&
Only the last {VERSION_LIMIT} versions are shown.
} +
+ + ); +}; + +export default MappingsHistoryView; diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionFileApproval.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionFileApproval.js index 24cfad7290..c391878a47 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionFileApproval.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionFileApproval.js @@ -47,7 +47,7 @@ const PromotionFileApproval = ({ currentUser, authors, canApprove, approved, onA (!preventApproval ? ( {
{ return ( @@ -117,7 +117,7 @@ const PromotionSidebar = ({ selection, onSelectionChange, promotionFiles, update
-
Modified Configurations
+
Modified Files
-

Configuration Promotion

+

File Promotion

} @@ -58,7 +58,7 @@ const PromotionToolbar = ({ onRefresh, onPromote, loading, enabled, canPromote } icon={'pi pi-refresh' + (loading ? ' pi-spin' : '')} onClick={onRefresh} /> - {canPromote &&
} /> diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionView.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionView.js index 0507a9d69e..f699977f28 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionView.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/PromotionView.js @@ -36,7 +36,7 @@ const PromotionView = () => { const currentUser = useSelector((state) => state.authentication.username); // fetching promotion data - const [{ data, isLoading, lastUpdate }, refreshData] = useFetchData('/configuration/promotions', { 'include-content': 'true' }); + const [{ data, isLoading, lastUpdate }, refreshData] = useFetchData('/promotions', { 'include-content': 'true' }); // derived variables const canSelfApprove = _.get(data, 'canPromoteOwnChanges', false); // whether the user can approve self-made changes @@ -79,7 +79,7 @@ const PromotionView = () => { /** * Promotes the currently approved files. */ - const promoteConfigurations = async (commitMessage) => { + const promoteFiles = async (commitMessage) => { const payload = { files: currentApprovals, workspaceCommitId, @@ -90,16 +90,14 @@ const PromotionView = () => { setIsPromoting(true); try { - const { data } = await axios.post('/configuration/promote', payload); + const { data } = await axios.post('/promote', payload); if (data.result && data.result != 'OK') { setShowWarningDialog(true); setPromotionResult(data.result); } - dispatch( - notificationActions.showSuccessMessage('Configuration Promoted', 'The approved configurations have been successfully promoted.') - ); + dispatch(notificationActions.showSuccessMessage('File Promoted', 'The approved files have been successfully promoted.')); refreshData(); } catch (error) { if (error.response && error.response.status === 409) { @@ -153,7 +151,7 @@ const PromotionView = () => { setShowPromotionDialog(false)} - onPromote={promoteConfigurations} + onPromote={promoteFiles} approvedFiles={currentApprovals} isLoading={isPromoting} /> diff --git a/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/dialogs/PromotionConflictDialog.js b/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/dialogs/PromotionConflictDialog.js index 22ce727d42..5d7d0c07e7 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/dialogs/PromotionConflictDialog.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/components/views/promotion/dialogs/PromotionConflictDialog.js @@ -3,7 +3,7 @@ import { Dialog } from 'primereact/dialog'; import { Button } from 'primereact/button'; /** - * Dialog for showing promotion conflicts. A conflict can occure if the + * Dialog for showing promotion conflicts. A conflict can occur if the * live branch has been modified and the user tries to promote new files. */ const PromotionConflictDialog = ({ visible, onHide, onRefresh }) => { @@ -21,7 +21,7 @@ const PromotionConflictDialog = ({ visible, onHide, onRefresh }) => { return ( { - this.clearButton.current.element.focus(); + if (this.clearButton?.current?.element) { + this.clearButton.current.element.focus(); + } }, 0); } } diff --git a/components/inspectit-ocelot-configurationserver-ui/src/data/side-navigation-items.json b/components/inspectit-ocelot-configurationserver-ui/src/data/side-navigation-items.json index c4f59804f7..8565736c51 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/data/side-navigation-items.json +++ b/components/inspectit-ocelot-configurationserver-ui/src/data/side-navigation-items.json @@ -19,7 +19,7 @@ "alwaysEnabled": true }, { - "name": "Configuration Promotion", + "name": "Promotion", "icon": "pi-cloud-upload", "href": "/promotion", "alwaysEnabled": true diff --git a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/configuration/actions.js b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/configuration/actions.js index d75e520748..9eb4cb749e 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/configuration/actions.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/configuration/actions.js @@ -8,7 +8,7 @@ import { downloadSelection } from '../../../functions/export-selection.function' /** * Fetches all existing versions. */ -export const fetchVersions = () => { +export const fetchConfigurationVersions = () => { return (dispatch) => { dispatch({ type: types.FETCH_VERSIONS_STARTED }); @@ -207,7 +207,7 @@ export const deleteSelection = (fetchFilesOnSuccess, selectedFile = null) => { dispatch({ type: types.DELETE_SELECTION_SUCCESS }); if (fetchFilesOnSuccess) { dispatch(fetchFiles()); - dispatch(fetchVersions()); + dispatch(fetchConfigurationVersions()); } }) .catch(() => { @@ -314,7 +314,7 @@ export const writeFile = (file, content, fetchFilesOnSuccess, selectFileOnSucces dispatch({ type: types.WRITE_FILE_SUCCESS, payload }); dispatch(fetchFiles()); - dispatch(fetchVersions()); + dispatch(fetchConfigurationVersions()); if (fetchFilesOnSuccess) { if (selectFileOnSuccess) { @@ -385,7 +385,7 @@ export const move = (path, targetPath, fetchFilesOnSuccess) => { }); if (fetchFilesOnSuccess) { dispatch(fetchFiles()); - dispatch(fetchVersions()); + dispatch(fetchConfigurationVersions()); } }) .catch(() => { @@ -407,7 +407,7 @@ export const selectedFileContentsChanged = (content) => ({ /** * Selects the version with the given id. */ -export const selectVersion = (version, reloadFiles = true) => { +export const selectConfigurationVersion = (version, reloadFiles = true) => { return (dispatch) => { // changing the selected version dispatch({ diff --git a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/initial-states.js b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/initial-states.js index 52280812d0..0bbe6c572d 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/initial-states.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/initial-states.js @@ -69,12 +69,20 @@ const notification = { }; const mappings = { - /** Specifies how many requests are currently loading in the background */ + /** Specifies how many requests are currently loading in the background. */ pendingRequests: 0, /** The current agent mappings. */ mappings: [], /** The date when the agent mappings have been fetched. */ updateDate: null, + /** The existing versions. */ + versions: [], + /** Specifies the selected git version. The latest version always has the number 0. */ + selectedVersion: null, + /** The source branch for the agent mappings file itself. */ + sourceBranch: '', + /** Defines which sidebar is currently shown */ + currentSidebar: SidebarTypes.NONE, }; const alerting = { diff --git a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/actions.js b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/actions.js index 55858a19e8..b4a1ed0c07 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/actions.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/actions.js @@ -1,16 +1,22 @@ import * as types from './types'; import axios from '../../../lib/axios-api'; import { notificationActions } from '../notification'; +import { VERSION_LIMIT } from '../../../data/constants'; /** * Fetches the agent mappings from the server. */ export const fetchMappings = () => { - return (dispatch) => { - dispatch({ type: types.FETCH_MAPPINGS_STARTED }); + return (dispatch, getState) => { + const { selectedVersion } = getState().mappings; + const params = {}; + if (selectedVersion) { + params.version = selectedVersion; + } + dispatch({ type: types.FETCH_MAPPINGS_STARTED }); axios - .get('/mappings') + .get('/mappings', { params }) .then((response) => { const mappings = response.data; dispatch({ type: types.FETCH_MAPPINGS_SUCCESS, payload: { mappings } }); @@ -101,3 +107,100 @@ export const deleteMapping = (mapping) => { }); }; }; + +/** + * Fetches all existing versions. + */ +export const fetchMappingsVersions = () => { + return (dispatch) => { + dispatch({ type: types.FETCH_VERSIONS_STARTED }); + + const params = { + limit: VERSION_LIMIT, + }; + + axios('/versions', { params }) + .then((res) => { + const versions = res.data; + dispatch({ type: types.FETCH_VERSIONS_SUCCESS, payload: { versions } }); + }) + .catch(() => { + dispatch({ type: types.FETCH_VERSIONS_FAILURE }); + }); + }; +}; + +/** + * Selects the version with the given id. + */ +export const selectMappingsVersion = (version, reloadMappings = true) => { + return (dispatch) => { + // changing the selected version + dispatch({ + type: types.SELECT_VERSION, + payload: { + version, + }, + }); + + if (reloadMappings) { + // fetching the content of the selected version + dispatch(fetchMappings()); + } + }; +}; + +/** + * Send the new source branch for the agent mappings file itself + * @param branch new source branch + */ +export const putMappingsSourceBranch = (branch, onComplete = () => {}) => { + return (dispatch) => { + dispatch({ type: types.PUT_MAPPINGS_SOURCE_BRANCH_STARTED }); + + axios + .put( + `/mappings/source`, + {}, + { + headers: { 'content-type': 'application/json' }, + params: { branch: branch }, + } + ) + .then((response) => { + const sourceBranch = response.data; + dispatch({ type: types.PUT_MAPPINGS_SOURCE_BRANCH_SUCCESS, payload: { sourceBranch } }); + onComplete(true); + }) + .catch(() => { + dispatch({ type: types.PUT_MAPPINGS_SOURCE_BRANCH_FAILURE }); + onComplete(false); + }); + }; +}; + +/** + * Fetches the current source branch for the agent mappings file itself + */ +export const fetchMappingsSourceBranch = () => { + return (dispatch) => { + dispatch({ type: types.FETCH_MAPPINGS_SOURCE_BRANCH_STARTED }); + + axios + .get('/mappings/source') + .then((response) => { + const sourceBranch = response.data; + dispatch({ type: types.FETCH_MAPPINGS_SOURCE_BRANCH_SUCCESS, payload: { sourceBranch } }); + }) + .catch(() => { + dispatch({ type: types.FETCH_MAPPINGS_SOURCE_BRANCH_FAILURE }); + }); + }; +}; + +/** + * Shows or hides the history view. + */ +export const toggleHistoryView = () => ({ + type: types.TOGGLE_HISTORY_VIEW, +}); diff --git a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/reducers.js b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/reducers.js index 8ff925dc85..fdf0a7a6d1 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/reducers.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/reducers.js @@ -1,83 +1,150 @@ import * as types from './types'; import { createReducer } from '../../utils'; import { mappings as initialState } from '../initial-states'; +import SidebarTypes from '../../../components/views/mappings/SidebarTypes'; + +const incrementPendingRequests = (state) => { + return { + ...state, + pendingRequests: state.pendingRequests + 1, + }; +}; + +const decrementPendingRequests = (state) => { + return { + ...state, + pendingRequests: state.pendingRequests - 1, + }; +}; const mappingsReducer = createReducer(initialState)({ [types.FETCH_MAPPINGS_STARTED]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests + 1, + ...incrementPendingRequests(state), }; }, [types.FETCH_MAPPINGS_FAILURE]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests - 1, + ...decrementPendingRequests(state), }; }, [types.FETCH_MAPPINGS_SUCCESS]: (state, action) => { const { mappings } = action.payload; return { - ...state, - pendingRequests: state.pendingRequests - 1, + ...decrementPendingRequests(state), mappings, updateDate: Date.now(), }; }, [types.PUT_MAPPINGS_STARTED]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests + 1, + ...incrementPendingRequests(state), }; }, [types.PUT_MAPPINGS_FAILURE]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests - 1, + ...decrementPendingRequests(state), }; }, [types.PUT_MAPPINGS_SUCCESS]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests - 1, + ...decrementPendingRequests(state), updateDate: Date.now(), }; }, [types.PUT_MAPPING_STARTED]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests + 1, + ...incrementPendingRequests(state), }; }, [types.PUT_MAPPING_FAILURE]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests - 1, + ...decrementPendingRequests(state), }; }, [types.PUT_MAPPING_SUCCESS]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests - 1, + ...decrementPendingRequests(state), updateDate: Date.now(), }; }, [types.DELETE_MAPPING_STARTED]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests + 1, + ...incrementPendingRequests(state), }; }, [types.DELETE_MAPPING_FAILURE]: (state) => { return { - ...state, - pendingRequests: state.pendingRequests - 1, + ...decrementPendingRequests(state), }; }, [types.DELETE_MAPPING_SUCCESS]: (state) => { + return { + ...decrementPendingRequests(state), + }; + }, + [types.FETCH_MAPPINGS_SOURCE_BRANCH_STARTED]: (state) => { + return { + ...incrementPendingRequests(state), + }; + }, + [types.FETCH_MAPPINGS_SOURCE_BRANCH_SUCCESS]: (state, action) => { + const sourceBranch = action.payload.sourceBranch; + return { + ...decrementPendingRequests(state), + sourceBranch, + }; + }, + [types.FETCH_MAPPINGS_SOURCE_BRANCH_FAILURE]: (state) => { + return { + ...decrementPendingRequests(state), + }; + }, + [types.PUT_MAPPINGS_SOURCE_BRANCH_STARTED]: (state) => { + return { + ...incrementPendingRequests(state), + }; + }, + [types.PUT_MAPPINGS_SOURCE_BRANCH_SUCCESS]: (state, action) => { + const sourceBranch = action.payload.sourceBranch; + return { + ...decrementPendingRequests(state), + sourceBranch, + }; + }, + [types.PUT_MAPPINGS_SOURCE_BRANCH_FAILURE]: (state) => { + return { + ...decrementPendingRequests(state), + }; + }, + [types.FETCH_VERSIONS_STARTED]: (state) => { + return { + ...incrementPendingRequests(state), + }; + }, + [types.FETCH_VERSIONS_FAILURE]: (state) => { + return { + ...decrementPendingRequests(state), + }; + }, + [types.FETCH_VERSIONS_SUCCESS]: (state, action) => { + const { versions } = action.payload; + return { + ...decrementPendingRequests(state), + versions, + }; + }, + [types.SELECT_VERSION]: (state, action) => { + const { version } = action.payload; + return { + ...state, + selectedVersion: version, + }; + }, + [types.TOGGLE_HISTORY_VIEW]: (state) => { return { ...state, - pendingRequests: state.pendingRequests - 1, + currentSidebar: state.currentSidebar == SidebarTypes.HISTORY ? SidebarTypes.NONE : SidebarTypes.HISTORY, }; }, }); diff --git a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/selectors.js b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/selectors.js index 8096c0aac9..79a9ff6f22 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/selectors.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/selectors.js @@ -1,6 +1,8 @@ import { createSelector } from 'reselect'; import yaml from 'js-yaml'; +const mappingsSelector = (state) => state.mappings; + /** * Returns the fetched mappigns as YAML. */ @@ -16,3 +18,21 @@ export const getMappingsAsYamlFromMappingsState = createSelector( (state) => state.mappings, (mappings) => (mappings ? yaml.safeDump(mappings) : '') ); + +/** + * Returns whether the currently selected version is the latest one. The front-end assumes, that + * the latest version is on index 0 in the versions array provided by the backend. + */ +export const isLatestVersion = createSelector(mappingsSelector, (configuration) => { + const { versions, selectedVersion } = configuration; + + return _isLatestVersion(versions, selectedVersion); +}); + +/** + * The logic to determine whether the given version is the latest one. The front-end assumes, that + * the latest version is on index 0 in the versions array provided by the backend. + */ +const _isLatestVersion = (versions, selectedVersion) => { + return selectedVersion === null || versions.length === 0 || selectedVersion === versions[0].id; +}; diff --git a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/types.js b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/types.js index 0c85426deb..f85f365b30 100644 --- a/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/types.js +++ b/components/inspectit-ocelot-configurationserver-ui/src/redux/ducks/mappings/types.js @@ -13,3 +13,17 @@ export const PUT_MAPPING_SUCCESS = 'mappings/PUT_MAPPING_SUCCESS'; export const DELETE_MAPPING_STARTED = 'mappings/DELETE_MAPPING_STARTED'; export const DELETE_MAPPING_FAILURE = 'mappings/DELETE_MAPPING_FAILURE'; export const DELETE_MAPPING_SUCCESS = 'mappings/DELETE_MAPPING_SUCCESS'; + +export const FETCH_MAPPINGS_SOURCE_BRANCH_STARTED = 'mappings/FETCH_MAPPINGS_SOURCE_BRANCH_STARTED'; +export const FETCH_MAPPINGS_SOURCE_BRANCH_SUCCESS = 'mappings/FETCH_MAPPINGS_SOURCE_BRANCH_SUCCESS'; +export const FETCH_MAPPINGS_SOURCE_BRANCH_FAILURE = 'mappings/FETCH_MAPPINGS_SOURCE_BRANCH_FAILURE'; +export const PUT_MAPPINGS_SOURCE_BRANCH_STARTED = 'mappings/FETCH_MAPPINGS_SOURCE_BRANCH_STARTED'; +export const PUT_MAPPINGS_SOURCE_BRANCH_SUCCESS = 'mappings/PUT_MAPPINGS_SOURCE_BRANCH_SUCCESS'; +export const PUT_MAPPINGS_SOURCE_BRANCH_FAILURE = 'mappings/PUT_MAPPINGS_SOURCE_BRANCH_FAILURE'; + +export const FETCH_VERSIONS_STARTED = 'mappings/FETCH_VERSIONS_STARTED'; +export const FETCH_VERSIONS_FAILURE = 'mappings/FETCH_VERSIONS_FAILURE'; +export const FETCH_VERSIONS_SUCCESS = 'mappings/FETCH_VERSIONS_SUCCESS'; + +export const SELECT_VERSION = 'mappings/SELECT_VERSION'; +export const TOGGLE_HISTORY_VIEW = 'configuration/TOGGLE_HISTORY_VIEW'; diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManager.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManager.java index 9102db7198..ac5613cb37 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManager.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManager.java @@ -9,7 +9,8 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import rocks.inspectit.ocelot.config.model.InspectitServerSettings; -import rocks.inspectit.ocelot.events.ConfigurationPromotionEvent; +import rocks.inspectit.ocelot.events.AgentMappingsSourceBranchChangedEvent; +import rocks.inspectit.ocelot.events.PromotionEvent; import rocks.inspectit.ocelot.events.WorkspaceChangedEvent; import rocks.inspectit.ocelot.file.FileManager; import rocks.inspectit.ocelot.mappings.AgentMappingSerializer; @@ -72,7 +73,7 @@ void init() { reloadConfigurationAsync(); } - @EventListener({ConfigurationPromotionEvent.class, WorkspaceChangedEvent.class}) + @EventListener({PromotionEvent.class, WorkspaceChangedEvent.class, AgentMappingsSourceBranchChangedEvent.class}) private synchronized void reloadConfigurationAsync() { if (reloadTask != null) { reloadTask.cancel(); diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTask.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTask.java index c0f92987a4..5f9116962e 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTask.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTask.java @@ -16,6 +16,9 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import static rocks.inspectit.ocelot.file.versioning.Branch.LIVE; +import static rocks.inspectit.ocelot.file.versioning.Branch.WORKSPACE; + /** * A task for asynchronously loading the configurations based on a given list of mappings. */ @@ -52,8 +55,11 @@ public AgentConfigurationReloadTask(AgentMappingSerializer mappingsSerializer, F @Override public void run() { log.info("Starting configuration reloading..."); - RevisionAccess fileAccess = fileManager.getWorkspaceRevision(); + RevisionAccess fileAccess = mappingsSerializer.getRevisionAccess(); + if (!fileAccess.agentMappingsExist()) { + log.error("No agent mappings file was found on the current branch! Please add '{}' to the current branch.", + AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME); onTaskSuccess(Collections.emptyList()); return; } diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/config/model/InspectitServerSettings.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/config/model/InspectitServerSettings.java index d73d111481..9e06740d9d 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/config/model/InspectitServerSettings.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/config/model/InspectitServerSettings.java @@ -28,6 +28,11 @@ public class InspectitServerSettings { */ private String workingDirectory; + /** + * Source branch for agent mappings, which should be used during start up + */ + private String initialAgentMappingsSourceBranch; + /** * The mail suffix used for internal users. */ diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/AgentMappingsSourceBranchChangedEvent.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/AgentMappingsSourceBranchChangedEvent.java new file mode 100644 index 0000000000..84f805195f --- /dev/null +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/AgentMappingsSourceBranchChangedEvent.java @@ -0,0 +1,18 @@ +package rocks.inspectit.ocelot.events; + +import org.springframework.context.ApplicationEvent; + +/** + * This event is fired when the source branch for the agent mappings file itself has changed. + */ +public class AgentMappingsSourceBranchChangedEvent extends ApplicationEvent { + + /** + * Create a new ApplicationEvent. + * + * @param source the object on which the event initially occurred (never {@code null}) + */ + public AgentMappingsSourceBranchChangedEvent(Object source) { + super(source); + } +} diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/ConfigurationPromotionEvent.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/PromotionEvent.java similarity index 73% rename from components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/ConfigurationPromotionEvent.java rename to components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/PromotionEvent.java index 18802e0b45..15bf0c42b0 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/ConfigurationPromotionEvent.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/events/PromotionEvent.java @@ -4,9 +4,9 @@ import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; /** - * This event is fired when configurations have been promoted. + * This event is fired when files have been promoted. */ -public class ConfigurationPromotionEvent extends ApplicationEvent { +public class PromotionEvent extends ApplicationEvent { private final RevisionAccess liveRevision; @@ -15,7 +15,7 @@ public class ConfigurationPromotionEvent extends ApplicationEvent { * * @param source the object on which the event initially occurred (never {@code null}) */ - public ConfigurationPromotionEvent(Object source, RevisionAccess liveRevision) { + public PromotionEvent(Object source, RevisionAccess liveRevision) { super(source); this.liveRevision = liveRevision; } diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/FileManager.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/FileManager.java index 64ee6f7d1c..8b6ec541de 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/FileManager.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/FileManager.java @@ -18,7 +18,7 @@ import rocks.inspectit.ocelot.file.accessor.workingdirectory.WorkingDirectoryAccessor; import rocks.inspectit.ocelot.file.versioning.PromotionResult; import rocks.inspectit.ocelot.file.versioning.VersioningManager; -import rocks.inspectit.ocelot.file.versioning.model.ConfigurationPromotion; +import rocks.inspectit.ocelot.file.versioning.model.Promotion; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceDiff; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceVersion; @@ -148,18 +148,18 @@ public WorkspaceDiff getWorkspaceDiff(boolean includeContent) throws IOException } /** - * Executes a file promotion according to the specified {@link ConfigurationPromotion} definition. + * Executes a promotion according to the specified {@link Promotion} definition. * * @param promotion the definition what to promote * @param allowSelfPromotion if true, the current user will be allowed to promote his own changes. * * @return Additional information of the promotion in case the promotion was successful. This might contain additional - * information about warning or errors which did not affected the promotion itself. + * information about warning or errors which did not affect the promotion itself. */ - public PromotionResult promoteConfiguration(ConfigurationPromotion promotion, boolean allowSelfPromotion) throws GitAPIException { + public PromotionResult promote(Promotion promotion, boolean allowSelfPromotion) throws GitAPIException { workingDirectoryLock.writeLock().lock(); try { - return versioningManager.promoteConfiguration(promotion, allowSelfPromotion); + return versioningManager.promote(promotion, allowSelfPromotion); } finally { workingDirectoryLock.writeLock().unlock(); } @@ -169,7 +169,7 @@ public PromotionResult promoteConfiguration(ConfigurationPromotion promotion, bo * Can be called to commit external changes to the working directory. * This will cause the workspace revision to be in sync with the file system. *

- * The changes will be commit as the currently logged in user. + * The changes will be committed as the currently logged-in user. */ public void commitWorkingDirectory() throws GitAPIException { workingDirectoryLock.writeLock().lock(); diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/accessor/git/RevisionAccess.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/accessor/git/RevisionAccess.java index caafd60faf..676c5cd512 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/accessor/git/RevisionAccess.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/accessor/git/RevisionAccess.java @@ -144,7 +144,7 @@ public boolean isConfigurationFileAdded(String path) { /** * Checks if the given file exists in both this revision and the parent revision, - * but it's contents have changed. + * but its contents have changed. * * @param path the path of the file * @@ -180,6 +180,40 @@ public boolean isConfigurationFileDeleted(String path) { return parent.isPresent() && parent.get().configurationFileExists(path); } + /** + * Checks if the agent mappings exist in this revision but not in the parent revision. + * + * @return true, if the agent mappings file were added in this revision. + */ + public boolean isAgentMappingsAdded() { + if (!agentMappingsExist()) { + return false; + } + Optional parent = getPreviousRevision(); + return !parent.isPresent() || !parent.get().agentMappingsExist(); + } + + /** + * Checks, if the agent mappings file exist and if it's content in both this revision and the parent revision + * has changed. + * + * @return true, if the agent mappings file exist both in this and the parent revision but with different contents. + */ + public boolean isAgentMappingsModified() { + if (!agentMappingsExist()) { + return false; + } + Optional parent = getPreviousRevision(); + if (!parent.isPresent() || !parent.get().agentMappingsExist()) { + return false; + } + String currentContent = readAgentMappings().orElseThrow(() -> new IllegalStateException("Expected agent mappings to exist")); + String previousContent = parent.get() + .readAgentMappings() + .orElseThrow(() -> new IllegalStateException("Expected agent mappings to exist")); + return !currentContent.equals(previousContent); + } + @Override protected String verifyPath(String relativeBasePath, String relativePath) throws IllegalArgumentException { if (relativePath.startsWith("/")) { diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetector.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetector.java index 8b2f34fc5a..e03ff0073f 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetector.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetector.java @@ -6,7 +6,7 @@ import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import rocks.inspectit.ocelot.events.ConfigurationPromotionEvent; +import rocks.inspectit.ocelot.events.PromotionEvent; import rocks.inspectit.ocelot.events.WorkspaceChangedEvent; import rocks.inspectit.ocelot.file.FileManager; import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; @@ -56,7 +56,7 @@ void init() { synchronized void checkForUpdates() { RevisionAccess currentLiveRevision = fileManager.getLiveRevision(); if (!currentLiveRevision.getRevisionId().equals(latestLiveId)) { - publisher.publishEvent(new ConfigurationPromotionEvent(this, currentLiveRevision)); + publisher.publishEvent(new PromotionEvent(this, currentLiveRevision)); } RevisionAccess currentWorkspaceRevision = fileManager.getWorkspaceRevision(); @@ -71,7 +71,7 @@ synchronized void checkForUpdates() { * @param event */ @EventListener - synchronized void configurationPromoted(ConfigurationPromotionEvent event) { + synchronized void configurationPromoted(PromotionEvent event) { latestLiveId = event.getLiveRevision().getRevisionId(); } diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/VersioningManager.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/VersioningManager.java index 145637d0f0..37272f043c 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/VersioningManager.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/VersioningManager.java @@ -23,12 +23,12 @@ import rocks.inspectit.ocelot.config.model.RemoteConfigurationsSettings; import rocks.inspectit.ocelot.config.model.RemoteRepositorySettings; import rocks.inspectit.ocelot.error.exceptions.SelfPromotionNotAllowedException; -import rocks.inspectit.ocelot.events.ConfigurationPromotionEvent; +import rocks.inspectit.ocelot.events.PromotionEvent; import rocks.inspectit.ocelot.events.WorkspaceChangedEvent; import rocks.inspectit.ocelot.file.accessor.AbstractFileAccessor; import rocks.inspectit.ocelot.file.accessor.git.CachingRevisionAccess; import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; -import rocks.inspectit.ocelot.file.versioning.model.ConfigurationPromotion; +import rocks.inspectit.ocelot.file.versioning.model.Promotion; import rocks.inspectit.ocelot.file.versioning.model.SimpleDiffEntry; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceDiff; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceVersion; @@ -142,7 +142,7 @@ public synchronized void initialize() throws GitAPIException, IOException { setCurrentBranchToTarget(); } - stageFiles(false); // the agent mapping file should not be committed to the live branch + stageFiles(); commitAllFiles(GIT_SYSTEM_AUTHOR, "Initializing Git repository using existing working directory", false); if (getCommitCount() <= 0) { @@ -157,13 +157,10 @@ public synchronized void initialize() throws GitAPIException, IOException { // create the branches which will be used git.branchRename().setNewName(Branch.WORKSPACE.getBranchName()).call(); git.branchCreate().setName(Branch.LIVE.getBranchName()).call(); - - stageFiles(true); - commitAllFiles(GIT_SYSTEM_AUTHOR, "Staging and committing agent mappings during startup", false); } else if (!isClean()) { log.info("Changes in the configuration or agent mapping files have been detected and will be committed to the repository."); - stageFiles(true); + stageFiles(); commitAllFiles(GIT_SYSTEM_AUTHOR, "Staging and committing of external changes during startup", false); } @@ -265,7 +262,7 @@ public synchronized void commitAsExternalChange() throws GitAPIException { } log.info("Staging and committing of external changes to the configuration files or agent mappings"); - stageFiles(true); + stageFiles(); commitAllFiles(GIT_SYSTEM_AUTHOR, "Staging and committing of external changes", false); } @@ -296,7 +293,7 @@ public void commitAllChanges(String message) throws GitAPIException { PersonIdent author = getCurrentAuthor(); - stageFiles(true); + stageFiles(); if (commitAllFiles(author, message, author != GIT_SYSTEM_AUTHOR)) { eventPublisher.publishEvent(new WorkspaceChangedEvent(this, getWorkspaceRevision())); @@ -344,17 +341,12 @@ private boolean commitAllFiles(PersonIdent author, String message, boolean allow /** * Stage all modified/added/removed configuration files and, if specified, the agent mapping file. - * - * @param includeAgentMappings Flag indicating whether the agent mapping file should be staged as well */ - private void stageFiles(boolean includeAgentMappings) throws GitAPIException { - log.debug("Staging all configuration files{}.", includeAgentMappings ? " and agent mappings" : ""); + private void stageFiles() throws GitAPIException { + log.debug("Staging all configuration files and agent mappings."); AddCommand addCommand = git.add().addFilepattern(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER); - - if (includeAgentMappings) { - addCommand.addFilepattern(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME); - } + addCommand.addFilepattern(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME); addCommand.call(); } @@ -542,7 +534,6 @@ private WorkspaceDiff getWorkspaceDiff(boolean includeFileContent, ObjectId oldC // the diff entries are converted into custom ones List simpleDiffEntries = diffEntries.stream() .map(SimpleDiffEntry::of) - .filter(entry -> entry.getFile().startsWith(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER)) .map(SimpleDiffEntry::shortenName) .collect(Collectors.toList()); @@ -604,8 +595,16 @@ private Collection findModifyingAuthors(String file, RevCommit baseCommi //move "baseRevision" to the last commit where this file was touched (potentially the root commit). baseRevision = findLastChangingRevision(file, baseRevision); + if(file.equals(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME)) + return findModifyingAuthorsForAgentMappings(file, newRevision, baseRevision); + else + return findModifyingAuthorsForConfiguration(file, newRevision, baseRevision); + } + + private Collection findModifyingAuthorsForConfiguration(String file, RevisionAccess newRevision, RevisionAccess baseRevision) { Set authors = new HashSet<>(); String baseContent = baseRevision.readConfigurationFile(file).get(); + //Find all persons who added or modified the file since the last promotion. RevisionAccess commonAncestor = newRevision.getCommonAncestor(baseRevision); while (!newRevision.getRevisionId().equals(commonAncestor.getRevisionId())) { @@ -626,6 +625,30 @@ private Collection findModifyingAuthors(String file, RevCommit baseCommi return authors; } + private Collection findModifyingAuthorsForAgentMappings(String file, RevisionAccess newRevision, RevisionAccess baseRevision) { + Set authors = new HashSet<>(); + String baseContent = baseRevision.readAgentMappings().get(); + + //Find all persons who added or modified the file since the last promotion. + RevisionAccess commonAncestor = newRevision.getCommonAncestor(baseRevision); + while (!newRevision.getRevisionId().equals(commonAncestor.getRevisionId())) { + if (newRevision.isAgentMappingsModified()) { + authors.add(newRevision.getAuthorName()); + } else if (newRevision.isAgentMappingsAdded()) { + authors.add(newRevision.getAuthorName()); + break; //THe file has been added, no need to take previous changes into account + } + newRevision = newRevision.getPreviousRevision() + .orElseThrow(() -> new IllegalStateException(EXPECTED_PARENT_EXIST)); + if (newRevision.agentMappingsExist() && newRevision.readAgentMappings() + .get() + .equals(baseContent)) { + break; // we have reached a revision where the content is in the original state, no need to look further + } + } + return authors; + } + /** * Walks back in history to the point where the given file was added. * On the way, all authors which have modifies the file are remembered. @@ -637,6 +660,14 @@ private Collection findModifyingAuthors(String file, RevCommit baseCommi */ private Collection findAuthorsSinceAddition(String file, RevCommit newCommit) { RevisionAccess newRevision = new RevisionAccess(git.getRepository(), newCommit); + + if(file.equals(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME)) + return findAuthorsSinceAdditionForAgentMappings(newRevision); + else + return findAuthorsSinceAdditionForConfiguration(file, newRevision); + } + + private Collection findAuthorsSinceAdditionForConfiguration(String file, RevisionAccess newRevision) { Set authors = new HashSet<>(); //Find all persons who edited the file since it was added while (!newRevision.isConfigurationFileAdded(file)) { @@ -650,6 +681,20 @@ private Collection findAuthorsSinceAddition(String file, RevCommit newCo return authors; } + private Collection findAuthorsSinceAdditionForAgentMappings(RevisionAccess newRevision) { + Set authors = new HashSet<>(); + //Find all persons who edited the file since it was added + while (!newRevision.isAgentMappingsAdded()) { + if (newRevision.isAgentMappingsModified()) { + authors.add(newRevision.getAuthorName()); + } + newRevision = newRevision.getPreviousRevision() + .orElseThrow(() -> new IllegalStateException(EXPECTED_PARENT_EXIST)); + } + authors.add(newRevision.getAuthorName()); //Also add the name of the person who added the file + return authors; + } + /** * Finds the most recent revision originating from "newCommit" in which the given file was deleted. * Does not walk past the common ancestor of "newCommit" and "baseCommit". @@ -657,12 +702,15 @@ private Collection findAuthorsSinceAddition(String file, RevCommit newCo * Returns the author of this revision. * * @param file the file to check - * @param baseCommit the commit to comapre agains, usually the live branch + * @param baseCommit the commit to compare against, usually the live branch * @param newCommit the commit in which the provided file does not exist anymore, usually on the workspace * * @return the author of the revision which is responsible for the deletion. */ private String findDeletingAuthor(String file, RevCommit baseCommit, RevCommit newCommit) { + if(file.equals(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME)) + throw new IllegalStateException(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME + " must not be deleted!"); + RevisionAccess newRevision = new RevisionAccess(git.getRepository(), newCommit); RevisionAccess baseRevision = new RevisionAccess(git.getRepository(), baseCommit); //move "baseRevision" to the last commit where this file was touched (potentially the root commit). @@ -694,6 +742,13 @@ private String findDeletingAuthor(String file, RevCommit baseCommit, RevCommit n * @return a revision which either modifies or adds the given file. */ private RevisionAccess findLastChangingRevision(String file, RevisionAccess baseRevision) { + if(file.equals(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME)) + return findLastChangingRevisionForAgentMappings(baseRevision); + else + return findLastChangingRevisionForConfiguration(file, baseRevision); + } + + private RevisionAccess findLastChangingRevisionForConfiguration(String file, RevisionAccess baseRevision) { while (!baseRevision.isConfigurationFileAdded(file) && !baseRevision.isConfigurationFileModified(file)) { baseRevision = baseRevision.getPreviousRevision() .orElseThrow(() -> new IllegalStateException(EXPECTED_PARENT_EXIST)); @@ -701,6 +756,14 @@ private RevisionAccess findLastChangingRevision(String file, RevisionAccess base return baseRevision; } + private RevisionAccess findLastChangingRevisionForAgentMappings(RevisionAccess baseRevision) { + while (!baseRevision.isAgentMappingsAdded() && !baseRevision.isAgentMappingsModified()) { + baseRevision = baseRevision.getPreviousRevision() + .orElseThrow(() -> new IllegalStateException(EXPECTED_PARENT_EXIST)); + } + return baseRevision; + } + /** * Sets the old and new file content of the specified diff entry using the given revision access instances. * @@ -710,6 +773,15 @@ private RevisionAccess findLastChangingRevision(String file, RevisionAccess base */ private void fillFileContent(SimpleDiffEntry entry, RevisionAccess oldRevision, RevisionAccess newRevision) { String file = entry.getFile(); + + if(file.equals(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME)) + fillAgentMappingsFileContent(entry, oldRevision, newRevision); + else + fillConfigurationFileContent(entry, oldRevision, newRevision); + } + + private void fillConfigurationFileContent(SimpleDiffEntry entry, RevisionAccess oldRevision, RevisionAccess newRevision) { + String file = entry.getFile(); String oldContent = null; String newContent = null; @@ -726,6 +798,23 @@ private void fillFileContent(SimpleDiffEntry entry, RevisionAccess oldRevision, entry.setNewContent(newContent); } + private void fillAgentMappingsFileContent(SimpleDiffEntry entry, RevisionAccess oldRevision, RevisionAccess newRevision) { + String oldContent = null; + String newContent = null; + + if (entry.getType() == DiffEntry.ChangeType.ADD) { + newContent = newRevision.readAgentMappings().orElse(null); + } else if (entry.getType() == DiffEntry.ChangeType.MODIFY) { + oldContent = oldRevision.readAgentMappings().orElse(null); + newContent = newRevision.readAgentMappings().orElse(null); + } else if (entry.getType() == DiffEntry.ChangeType.DELETE) { + oldContent = oldRevision.readAgentMappings().orElse(null); + } + + entry.setOldContent(oldContent); + entry.setNewContent(newContent); + } + /** * Creates an {@link AbstractTreeIterator} for the specified commit. * @@ -751,35 +840,35 @@ private AbstractTreeIterator prepareTreeParser(ObjectId commitId) throws IOExcep } /** - * Promoting the configuration files according to the specified {@link ConfigurationPromotion} definition. + * Promoting the files according to the specified {@link Promotion} definition. * * @param promotion the promotion definition * @param allowSelfPromotion whether users can promote their own files * * @return Additional information of the promotion in case the promotion was successful. This might contain additional - * information about warning or errors which did not affected the promotion itself. + * information about warning or errors which did not affect the promotion itself. * - * @throws SelfPromotionNotAllowedException in case the user tries to promote its own files but it is prohibited - * @throws ConcurrentModificationException in case there was a commit on the live branch in the mean time + * @throws SelfPromotionNotAllowedException in case the user tries to promote its own files, but it is prohibited + * @throws ConcurrentModificationException in case there was a commit on the live branch in the meantime * @throws PromotionFailedException in case the promotion has been failed */ - public PromotionResult promoteConfiguration(ConfigurationPromotion promotion, boolean allowSelfPromotion) throws GitAPIException { - return promoteConfiguration(promotion, allowSelfPromotion, getCurrentAuthor()); + public PromotionResult promote(Promotion promotion, boolean allowSelfPromotion) throws GitAPIException { + return promote(promotion, allowSelfPromotion, getCurrentAuthor()); } /** - * Promoting the configuration files according to the specified {@link ConfigurationPromotion} definition. + * Promoting the files according to the specified {@link Promotion} definition. * * @param promotion the promotion definition * @param allowSelfPromotion whether users can promote their own files * @param author the author used for the resulting promotion commit */ - public synchronized PromotionResult promoteConfiguration(ConfigurationPromotion promotion, boolean allowSelfPromotion, PersonIdent author) throws GitAPIException { + public synchronized PromotionResult promote(Promotion promotion, boolean allowSelfPromotion, PersonIdent author) throws GitAPIException { if (promotion == null || CollectionUtils.isEmpty(promotion.getFiles())) { - throw new IllegalArgumentException("ConfigurationPromotion must not be null and has to promote at least one file!"); + throw new IllegalArgumentException("Promotion must not be null and has to promote at least one file!"); } - log.info("User '{}' promotes {} configuration files.", author.getName(), promotion.getFiles().size()); + log.info("User '{}' promotes {} files.", author.getName(), promotion.getFiles().size()); PromotionResult result = PromotionResult.OK; try { @@ -840,20 +929,20 @@ public synchronized PromotionResult promoteConfiguration(ConfigurationPromotion } } } catch (IOException | GitAPIException ex) { - throw new PromotionFailedException("Configuration promotion has failed.", ex); + throw new PromotionFailedException("Promotion has failed.", ex); } finally { - log.info("Configuration promotion was successful."); + log.info("Promotion was successful."); // checkout workspace branch git.checkout().setName(Branch.WORKSPACE.getBranchName()).call(); - eventPublisher.publishEvent(new ConfigurationPromotionEvent(this, getLiveRevision())); + eventPublisher.publishEvent(new PromotionEvent(this, getLiveRevision())); } return result; } - private boolean containsSelfPromotion(ConfigurationPromotion promotion, WorkspaceDiff diff) { + private boolean containsSelfPromotion(Promotion promotion, WorkspaceDiff diff) { PersonIdent currentAuthor = getCurrentAuthor(); if (currentAuthor == GIT_SYSTEM_AUTHOR) { return false; @@ -878,11 +967,12 @@ private boolean containsSelfPromotion(ConfigurationPromotion promotion, Workspac * @return the file path including the files directory */ private String prefixRelativeFile(String file) { - if (file.startsWith("/")) { + if(file.equals(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME)) + return file; + else if (file.startsWith("/")) return AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + file; - } else { + else return AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + "/" + file; - } } /** @@ -1037,14 +1127,14 @@ private void mergeBranch(ObjectId baseObject, ObjectId targetObject, boolean rem .map(SimpleDiffEntry::getFile) .collect(Collectors.toList()); - ConfigurationPromotion promotion = ConfigurationPromotion.builder() + Promotion promotion = Promotion.builder() .commitMessage("Auto-promotion due to workspace remote synchronization.") .workspaceCommitId(getLatestCommit(Branch.WORKSPACE).get().getId().getName()) .liveCommitId(getLatestCommit(Branch.LIVE).get().getId().getName()) .files(diffFiles) .build(); - promoteConfiguration(promotion, true, GIT_SYSTEM_AUTHOR); + promote(promotion, true, GIT_SYSTEM_AUTHOR); } } diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/ConfigurationPromotion.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/Promotion.java similarity index 92% rename from components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/ConfigurationPromotion.java rename to components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/Promotion.java index 9963e37f06..badd7cfafa 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/ConfigurationPromotion.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/Promotion.java @@ -9,13 +9,13 @@ import java.util.List; /** - * Container class for the configuration promotion. + * Container class for file promotions. */ @Data @NoArgsConstructor @AllArgsConstructor @Builder -public class ConfigurationPromotion { +public class Promotion { /** * A short message describing the commit. diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/SimpleDiffEntry.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/SimpleDiffEntry.java index 38d2759bee..b441565407 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/SimpleDiffEntry.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/file/versioning/model/SimpleDiffEntry.java @@ -70,10 +70,13 @@ public static SimpleDiffEntry of(DiffEntry entry) { /** * Shortens the filename of this instance based on {@link AbstractFileAccessor#CONFIGURATION_FILES_SUBFOLDER}. * The shortened name is the original name without the subfolder prefix. + * The name will not be shortened for the agent_mapping.yml * * @return the same {@link SimpleDiffEntry} object */ public SimpleDiffEntry shortenName() { + if(file.equals(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME)) return this; + file = file.substring(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER.length()); return this; } diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingManager.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingManager.java index 5e1cb56400..cc2490ed49 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingManager.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingManager.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import rocks.inspectit.ocelot.file.FileManager; +import rocks.inspectit.ocelot.file.versioning.Branch; import rocks.inspectit.ocelot.mappings.model.AgentMapping; import javax.annotation.PostConstruct; @@ -14,6 +15,8 @@ import java.util.stream.IntStream; import static com.google.common.base.Preconditions.checkArgument; +import static rocks.inspectit.ocelot.file.versioning.Branch.LIVE; +import static rocks.inspectit.ocelot.file.versioning.Branch.WORKSPACE; /** * The manager class to handle and manage the agent mappings. @@ -35,34 +38,79 @@ public class AgentMappingManager { /** * Object mapper utils. */ - @Autowired private AgentMappingSerializer serializer; /** * Object mapper utils. */ - @Autowired private FileManager fileManager; + @VisibleForTesting + @Autowired + AgentMappingManager(AgentMappingSerializer serializer, FileManager fileManager) { + this.serializer = serializer; + this.fileManager = fileManager; + } + /** * Post construct. Initially reading the agent mappings if the mappings file exists. */ @PostConstruct public void postConstruct() throws IOException { if (!fileManager.getWorkspaceRevision().agentMappingsExist()) { - log.info("Generating default agent mappings"); + log.info("Generating default agent mappings for workspace branch"); List defaultMappings = Collections.singletonList(DEFAULT_MAPPING); serializer.writeAgentMappings(defaultMappings, fileManager.getWorkingDirectory()); } } /** - * Returns a unmodifiable representation of the current agent mappings list. + * @return The current source branch for the agent mapping file itself. + */ + public synchronized Branch getSourceBranch() { + return serializer.getSourceBranch(); + } + + /** + * Sets the source branch, from which the agent mapping file will be reade + * @param sourceBranch new source branch + * @return The set source branch + */ + public synchronized Branch setSourceBranch(String sourceBranch) { + checkArgument(sourceBranch != null, "The set source branch cannot be null."); + sourceBranch = sourceBranch.toLowerCase(); + + switch (sourceBranch) { + case "live": + return serializer.setSourceBranch(LIVE); + case "workspace": + return serializer.setSourceBranch(WORKSPACE); + default: + throw new UnsupportedOperationException("Unhandled branch: " + sourceBranch); + } + } + + /** + * Returns an unmodifiable representation of the agent mappings list. + * + * @param version The id of the version, which should be listed. + * If it is empty, the latest workspace version is used. + * Can be 'live' fir listing the latest live version. * * @return A list of {@link AgentMapping} */ + public synchronized List getAgentMappings(String version) { + if (version == null) { + return serializer.readAgentMappings(fileManager.getWorkspaceRevision()); + } else if (version.equals("live")) { + return serializer.readAgentMappings(fileManager.getLiveRevision()); + } else { + return serializer.readAgentMappings(fileManager.getCommitWithId(version)); + } + } + public synchronized List getAgentMappings() { - return serializer.readAgentMappings(fileManager.getWorkspaceRevision()); + return getAgentMappings(null); } /** diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializer.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializer.java index f6eb516d68..506aaa4709 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializer.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializer.java @@ -4,10 +4,19 @@ import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; +import com.google.common.annotations.VisibleForTesting; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; +import rocks.inspectit.ocelot.config.model.InspectitServerSettings; +import rocks.inspectit.ocelot.events.AgentMappingsSourceBranchChangedEvent; +import rocks.inspectit.ocelot.file.FileManager; import rocks.inspectit.ocelot.file.accessor.AbstractFileAccessor; +import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; import rocks.inspectit.ocelot.file.accessor.workingdirectory.AbstractWorkingDirectoryAccessor; +import rocks.inspectit.ocelot.file.versioning.Branch; import rocks.inspectit.ocelot.mappings.model.AgentMapping; import javax.annotation.PostConstruct; @@ -16,6 +25,10 @@ import java.util.List; import java.util.Optional; +import static rocks.inspectit.ocelot.file.accessor.AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME; +import static rocks.inspectit.ocelot.file.versioning.Branch.LIVE; +import static rocks.inspectit.ocelot.file.versioning.Branch.WORKSPACE; + /** * Utility for reading and writing the Agent Mappings. */ @@ -27,6 +40,25 @@ public class AgentMappingSerializer { private CollectionType mappingsListType; + private FileManager fileManager; + + private ApplicationEventPublisher publisher; + + /** + * SourceBranch for the agent mapping file itself. This does not affect the SourceBranch property inside the agent mappings! + */ + @Getter + private Branch sourceBranch; + + @VisibleForTesting + @Autowired + AgentMappingSerializer(InspectitServerSettings settings, FileManager fileManager, ApplicationEventPublisher publisher) { + this.fileManager = fileManager; + this.publisher = publisher; + String initialBranch = settings.getInitialAgentMappingsSourceBranch().toUpperCase(); + this.sourceBranch = Branch.valueOf(initialBranch); + } + /** * Post construct for initializing the mapper objects. */ @@ -68,4 +100,40 @@ public List readAgentMappings(AbstractFileAccessor readAccess) { public void writeAgentMappings(List agentMappings, AbstractWorkingDirectoryAccessor fileAccess) throws IOException { fileAccess.writeAgentMappings(ymlMapper.writeValueAsString(agentMappings)); } + + /** + * Sets the source branch, from which the agent mappings file will be read + * @param sourceBranch new source branch + * @return the set source branch + */ + public Branch setSourceBranch(Branch sourceBranch) { + log.info("Setting source branch for {} to {}", AGENT_MAPPINGS_FILE_NAME, sourceBranch); + Branch oldBranch = this.sourceBranch; + this.sourceBranch = sourceBranch; + + RevisionAccess currentRevisionAccess = getRevisionAccess(); + if(currentRevisionAccess.agentMappingsExist()) { + // Publish event to trigger configuration reload + publisher.publishEvent(new AgentMappingsSourceBranchChangedEvent(this)); + } + else { + log.error("Source branch for {} cannot be set to {}, since no file was found", AGENT_MAPPINGS_FILE_NAME, sourceBranch); + this.sourceBranch = oldBranch; + } + return this.sourceBranch; + } + + /** + * @return The branch, which is currently used to access the agent mappings + */ + public RevisionAccess getRevisionAccess() { + switch (getSourceBranch()) { + case LIVE: + return fileManager.getLiveRevision(); + case WORKSPACE: + return fileManager.getWorkspaceRevision(); + default: + throw new UnsupportedOperationException("Unhandled branch: " + getSourceBranch()); + } + } } diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/file/DirectoryController.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/file/DirectoryController.java index 809a01808b..04a7b1e193 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/file/DirectoryController.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/file/DirectoryController.java @@ -22,7 +22,7 @@ public class DirectoryController extends FileBaseController { @Operation(summary = "List directory contents", description = "Can be used to get a list of the contents of a given directory. In addition, the branch can be specified which will be used as basis for the listing.") @Parameter(name = "Path", description = "The part of the url after /directories/ define the path to the directory whose contents shall be read.") @GetMapping(value = "directories/**") - public Collection listContents(@Parameter(description = "The id of the version which should be listed. If it is empty, the lastest workspace version is used. Can be 'live' fir listing the latest live version.") @RequestParam(value = "version", required = false) String commitId, HttpServletRequest request) { + public Collection listContents(@Parameter(description = "The id of the version which should be listed. If it is empty, the latest workspace version is used. Can be 'live' for listing the latest live version.") @RequestParam(value = "version", required = false) String commitId, HttpServletRequest request) { String path = RequestUtil.getRequestSubPath(request); if (commitId == null) { diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingController.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingController.java index b9283c3870..a85b05a394 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingController.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingController.java @@ -1,11 +1,14 @@ package rocks.inspectit.ocelot.rest.mappings; +import io.swagger.v3.oas.annotations.Parameter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.annotation.Secured; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; +import rocks.inspectit.ocelot.file.versioning.Branch; import rocks.inspectit.ocelot.mappings.AgentMappingManager; import rocks.inspectit.ocelot.mappings.model.AgentMapping; import rocks.inspectit.ocelot.rest.AbstractBaseController; @@ -40,8 +43,9 @@ public class AgentMappingController extends AbstractBaseController { * @return List of {@link AgentMapping}s. */ @GetMapping(value = "mappings") - public List getMappings() { - return mappingManager.getAgentMappings(); + public List getMappings(@Parameter(description = "The id of the version which should be listed. If it is empty, the lastest workspace version is used. Can be 'live' for listing the latest live version.") @RequestParam(value = "version", required = false) String commitId) { + List agentMappings = mappingManager.getAgentMappings(commitId); + return agentMappings; } /** @@ -129,4 +133,35 @@ public ResponseEntity putMapping(@PathVariable("mappingName") String mappingName auditLogger.logEntityCreation(agentMapping); return ResponseEntity.ok().build(); } + + /** + * Sets the source branch for the agent mappings file itself, which means that the actual agent mappings will be read from + * the agent mappings file, which is located in the specified branch. + * There exist only two possible branches, namely WORKSPACE and LIVE. + *

+ * This does not affect the sourceBranch property, which is specified inside the agent mappings to configure the + * source branch for the agent configurations. + *

+ * The configuration will automatically be reloaded, after the agent mappings have been changed + * + * @param branch the branch, which should be used as source branch for the agent mappings file + * @return 200 in case the operation was successful + */ + @Secured(UserRoleConfiguration.ADMIN_ACCESS_ROLE) + @PutMapping (value = "mappings/source") + public ResponseEntity setMappingSourceBranch(@RequestParam String branch) { + Branch setBranch = mappingManager.setSourceBranch(branch); + return new ResponseEntity<>(setBranch, HttpStatus.OK); + } + + /** + * Returns the current set source branch for the agent mappings file itself. + * + * @return Current source branch for the agent mappings file + */ + @GetMapping(value = "mappings/source") + public ResponseEntity getMappingSourceBranch() { + Branch branch = mappingManager.getSourceBranch(); + return new ResponseEntity<>(branch, HttpStatus.OK); + } } diff --git a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/configuration/PromotionController.java b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/promotion/PromotionController.java similarity index 84% rename from components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/configuration/PromotionController.java rename to components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/promotion/PromotionController.java index 1d51bbe9da..3297607378 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/configuration/PromotionController.java +++ b/components/inspectit-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/rest/promotion/PromotionController.java @@ -1,4 +1,4 @@ -package rocks.inspectit.ocelot.rest.configuration; +package rocks.inspectit.ocelot.rest.promotion; import com.google.gson.JsonObject; import io.swagger.v3.oas.annotations.Operation; @@ -17,7 +17,7 @@ import rocks.inspectit.ocelot.error.exceptions.SelfPromotionNotAllowedException; import rocks.inspectit.ocelot.file.FileManager; import rocks.inspectit.ocelot.file.versioning.PromotionResult; -import rocks.inspectit.ocelot.file.versioning.model.ConfigurationPromotion; +import rocks.inspectit.ocelot.file.versioning.model.Promotion; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceDiff; import rocks.inspectit.ocelot.rest.AbstractBaseController; import rocks.inspectit.ocelot.security.config.UserRoleConfiguration; @@ -45,7 +45,7 @@ public ResponseEntity handleSelfPromotion(Exception exception) { } @Operation(summary = "Fetch promotion files", description = "Fetches all configuration files which are ready for promotion.") - @GetMapping(value = "configuration/promotions") + @GetMapping(value = "promotions") public WorkspaceDiff getPromotions(@Parameter(description = "Specifies whether the old and new content of each files should also be returned.") @RequestParam(defaultValue = "false", name = "include-content") boolean includeContent, Authentication authentication) throws IOException, GitAPIException { WorkspaceDiff workspaceDiff = fileManager.getWorkspaceDiff(includeContent); workspaceDiff.setCanPromoteOwnChanges(allowSelfPromotion(authentication)); @@ -53,15 +53,15 @@ public WorkspaceDiff getPromotions(@Parameter(description = "Specifies whether t } @Secured(UserRoleConfiguration.PROMOTE_ACCESS_ROLE) - @Operation(summary = "Promote configurations", description = "Promotes the specified configuration files.") - @PostMapping(value = "configuration/promote") - public ResponseEntity promoteConfiguration(@Parameter(description = "The definition that contains the information about which files to promote.") @RequestBody ConfigurationPromotion promotion, Authentication authentication) throws GitAPIException { + @Operation(summary = "Promote files", description = "Promotes the specified files.") + @PostMapping(value = "promote") + public ResponseEntity promote(@Parameter(description = "The definition that contains the information about which files to promote.") @RequestBody Promotion promotion, Authentication authentication) throws GitAPIException { boolean allowSelfPromotion = allowSelfPromotion(authentication); if (promotion.getCommitMessage() == null || promotion.getCommitMessage().isEmpty()) { return ResponseEntity.badRequest().build(); } try { - PromotionResult promotionResult = fileManager.promoteConfiguration(promotion, allowSelfPromotion); + PromotionResult promotionResult = fileManager.promote(promotion, allowSelfPromotion); JsonObject resultJson = new JsonObject(); resultJson.addProperty("result", promotionResult.name()); diff --git a/components/inspectit-ocelot-configurationserver/src/main/resources/application.yml b/components/inspectit-ocelot-configurationserver/src/main/resources/application.yml index 2e87f19b4a..91aa4402e6 100644 --- a/components/inspectit-ocelot-configurationserver/src/main/resources/application.yml +++ b/components/inspectit-ocelot-configurationserver/src/main/resources/application.yml @@ -26,6 +26,8 @@ server: inspectit-config-server: # the directory which is used as working directory working-directory: working_directory + # source branch for agent mappings, which should be used during start up + initial-agent-mappings-source-branch: WORKSPACE # the expiration duration of JWT tokens token-lifespan: 60m # the e-mail suffix used for internal users diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManagerTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManagerTest.java index f10b10f73f..77b8595129 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManagerTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationManagerTest.java @@ -43,6 +43,7 @@ public class AgentConfigurationManagerTest { @BeforeEach public void beforeEach() { lenient().when(fileManager.getWorkspaceRevision()).thenReturn(fileAccessor); + lenient().when(serializer.getRevisionAccess()).thenReturn(fileAccessor); } void init() { diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTaskTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTaskTest.java index 68e55a02ec..23247e975f 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTaskTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/agentconfiguration/AgentConfigurationReloadTaskTest.java @@ -27,6 +27,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import static rocks.inspectit.ocelot.file.versioning.Branch.LIVE; +import static rocks.inspectit.ocelot.file.versioning.Branch.WORKSPACE; @ExtendWith(MockitoExtension.class) public class AgentConfigurationReloadTaskTest { @@ -50,6 +52,7 @@ public class AgentConfigurationReloadTaskTest { public void beforeEach() { lenient().when(fileManager.getWorkspaceRevision()).thenReturn(workspaceAccessor); lenient().when(fileManager.getLiveRevision()).thenReturn(liveAccessor); + lenient().when(serializer.getRevisionAccess()).thenReturn(workspaceAccessor); } @Nested @@ -69,12 +72,12 @@ public void loadWithException() { AgentMapping mapping = AgentMapping.builder() .name("test") .source("/test") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); AgentMapping mapping2 = AgentMapping.builder() .name("test2") .source("/test2") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); doReturn(Arrays.asList(mapping, mapping2)).when(serializer).readAgentMappings(any()); @@ -106,12 +109,12 @@ public void loadWithExceptionOnlyString() { AgentMapping mapping = AgentMapping.builder() .name("test") .source("/test") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); AgentMapping mapping2 = AgentMapping.builder() .name("test2") .source("/test2") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); doReturn(Arrays.asList(mapping, mapping2)).when(serializer).readAgentMappings(any()); @@ -143,12 +146,12 @@ public void loadWithExceptionOnlyList() { AgentMapping mapping = AgentMapping.builder() .name("test") .source("/test") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); AgentMapping mapping2 = AgentMapping.builder() .name("test2") .source("/test2") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); doReturn(Arrays.asList(mapping, mapping2)).when(serializer).readAgentMappings(any()); @@ -165,6 +168,47 @@ public void loadWithExceptionOnlyList() { .extracting(AgentConfiguration::getConfigYaml) .isEqualTo("{key: valid}\n"); } + + @Test + public void loadMappingFromWorkspace() { + when(workspaceAccessor.agentMappingsExist()).thenReturn(true); + + AgentMapping mapping = AgentMapping.builder() + .name("test") + .source("/test") + .sourceBranch(WORKSPACE) + .build(); + doReturn(Collections.singletonList(mapping)).when(serializer).readAgentMappings(any()); + MutableObject> configurations = new MutableObject<>(); + Consumer> consumer = configurations::setValue; + + AgentConfigurationReloadTask task = new AgentConfigurationReloadTask(serializer, fileManager, consumer); + task.run(); + + verify(serializer, times(1)).readAgentMappings(workspaceAccessor); + verify(serializer, times(0)).readAgentMappings(liveAccessor); + } + + @Test + public void loadMappingFromLive() { + lenient().when(serializer.getRevisionAccess()).thenReturn(liveAccessor); + when(liveAccessor.agentMappingsExist()).thenReturn(true); + + AgentMapping mapping = AgentMapping.builder() + .name("test") + .source("/test") + .sourceBranch(WORKSPACE) + .build(); + doReturn(Collections.singletonList(mapping)).when(serializer).readAgentMappings(any()); + MutableObject> configurations = new MutableObject<>(); + Consumer> consumer = configurations::setValue; + + AgentConfigurationReloadTask task = new AgentConfigurationReloadTask(serializer, fileManager, consumer); + task.run(); + + verify(serializer, times(0)).readAgentMappings(workspaceAccessor); + verify(serializer, times(1)).readAgentMappings(liveAccessor); + } } @Nested @@ -182,7 +226,7 @@ public void loadYaml() throws IOException { AgentMapping mapping = AgentMapping.builder() .name("test") .source("/test") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); String string = reloadTask.loadConfigForMapping(mapping); @@ -201,7 +245,7 @@ public void yamlWithTab() { AgentMapping mapping = AgentMapping.builder() .name("test") .source("/test") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build(); assertThatExceptionOfType(AgentConfigurationReloadTask.InvalidConfigurationFileException.class).isThrownBy(() -> reloadTask.loadConfigForMapping(mapping)) @@ -240,7 +284,7 @@ void nonExistingSourcesSpecified() throws IOException { String result = reloadTask.loadConfigForMapping(AgentMapping.builder() .source("a.yml") .source("/some/folder") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build()); assertThat(result).isEmpty(); @@ -257,7 +301,7 @@ void nonYamlIgnored() throws IOException { .source("b.YmL") .source("c.yaml") .source("d.txt") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build()); assertThat(result).isEmpty(); @@ -276,7 +320,7 @@ void leadingSlashesInSourcesRemoved() throws IOException { reloadTask.loadConfigForMapping(AgentMapping.builder() .source("/a.yml") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build()); verify(workspaceAccessor).configurationFileExists(eq("a.yml")); @@ -308,7 +352,7 @@ void priorityRespected() throws IOException { String result = reloadTask.loadConfigForMapping(AgentMapping.builder() .source("/z.yml") .source("/folder") - .sourceBranch(Branch.WORKSPACE) + .sourceBranch(WORKSPACE) .build()); assertThat(result).isEqualTo("{val1: z, val2: a, val3: b}\n"); diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetectorTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetectorTest.java index 9595ab45dc..53b66dc627 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetectorTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/ExternalChangeDetectorTest.java @@ -8,7 +8,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.context.ApplicationEventPublisher; -import rocks.inspectit.ocelot.events.ConfigurationPromotionEvent; +import rocks.inspectit.ocelot.events.PromotionEvent; import rocks.inspectit.ocelot.events.WorkspaceChangedEvent; import rocks.inspectit.ocelot.file.FileManager; import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; @@ -78,7 +78,7 @@ public void externalWorkspaceChange() { @Test public void internalLiveChange() { when(liveRevision.getRevisionId()).thenReturn("newLive"); - detector.configurationPromoted(new ConfigurationPromotionEvent(this, liveRevision)); + detector.configurationPromoted(new PromotionEvent(this, liveRevision)); detector.checkForUpdates(); @@ -91,9 +91,9 @@ public void externalLiveChange() { detector.checkForUpdates(); - ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(ConfigurationPromotionEvent.class); + ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(PromotionEvent.class); verify(publisher).publishEvent(eventCaptor.capture()); - ConfigurationPromotionEvent event = eventCaptor.getValue(); + PromotionEvent event = eventCaptor.getValue(); assertThat(event.getLiveRevision()).isSameAs(liveRevision); } diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/VersioningManagerTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/VersioningManagerTest.java index c2a1540c3e..097cb76595 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/VersioningManagerTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/file/versioning/VersioningManagerTest.java @@ -25,7 +25,7 @@ import rocks.inspectit.ocelot.file.FileTestBase; import rocks.inspectit.ocelot.file.accessor.AbstractFileAccessor; import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; -import rocks.inspectit.ocelot.file.versioning.model.ConfigurationPromotion; +import rocks.inspectit.ocelot.file.versioning.model.Promotion; import rocks.inspectit.ocelot.file.versioning.model.SimpleDiffEntry; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceDiff; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceVersion; @@ -47,7 +47,7 @@ class VersioningManagerTest extends FileTestBase { /** - * For convenience: if this field is not null, it will used as working directory during tests. + * For convenience: if this field is not null, it will be used as working directory during tests. * Note: the specified directory is CLEANED before each run, thus, if you have files there, they will be gone ;) */ public static final String TEST_DIRECTORY = null; @@ -110,7 +110,7 @@ public void initAndStageFiles() throws GitAPIException, IOException { assertThat(clean).isTrue(); assertThat(before).isFalse(); assertThat(after).isTrue(); - assertThat(count).isEqualTo(2); // Initializing Git repository + committing agent mappings + assertThat(count).isEqualTo(1); // Initializing Git repo + committing agent mappings happens in one commit } @Test @@ -129,14 +129,14 @@ public void multipleCalls() throws GitAPIException, IOException { int secondCount = versioningManager.getCommitCount(); assertThat(initSecond).isTrue(); assertThat(cleanFirst).isTrue(); - assertThat(secondCount).isEqualTo(2); // Initializing Git repository + committing agent mappings + assertThat(secondCount).isEqualTo(1); // Initializing Git repo + committing agent mappings happens in one commit versioningManager.initialize(); boolean cleanSecond = versioningManager.isClean(); int thirdCount = versioningManager.getCommitCount(); assertThat(cleanSecond).isTrue(); - assertThat(thirdCount).isEqualTo(2); + assertThat(thirdCount).isEqualTo(1); } @Test @@ -155,7 +155,7 @@ public void externalChanges() throws GitAPIException, IOException { int secondCount = versioningManager.getCommitCount(); assertThat(initSecond).isTrue(); assertThat(cleanFirst).isTrue(); - assertThat(secondCount).isEqualTo(2); // Initializing Git repository + committing agent mappings + assertThat(secondCount).isEqualTo(1); // Initializing Git repo + committing agent mappings happens in one commit // edit file createTestFiles(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + "/file.yml=content"); @@ -165,7 +165,7 @@ public void externalChanges() throws GitAPIException, IOException { boolean cleanSecond = versioningManager.isClean(); int thirdCount = versioningManager.getCommitCount(); assertThat(cleanSecond).isTrue(); - assertThat(thirdCount).isEqualTo(3); + assertThat(thirdCount).isEqualTo(2); } } @@ -497,10 +497,11 @@ public void getDiffById() throws IOException, GitAPIException { } @Nested - class PromoteConfiguration { + class PromoteFile { @Test public void promoteEverything() throws GitAPIException, IOException { + createTestFiles(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME); createTestFiles(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + "/file_removed.yml=content"); createTestFiles(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + "/file_no_change.yml"); createTestFiles(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + "/file_modified.yml"); @@ -513,12 +514,14 @@ public void promoteEverything() throws GitAPIException, IOException { String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); - promotion.setFiles(Arrays.asList("/file_added.yml", "/file_modified.yml", "/file_removed.yml")); + promotion.setFiles(Arrays.asList( + AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME, "/file_added.yml", "/file_modified.yml", "/file_removed.yml") + ); - versioningManager.promoteConfiguration(promotion, true); + versioningManager.promote(promotion, true); WorkspaceDiff diff = versioningManager.getWorkspaceDiffWithoutContent(); @@ -539,12 +542,12 @@ public void partialPromotion() throws GitAPIException, IOException { String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/file_modified.yml", "/file_removed.yml")); - versioningManager.promoteConfiguration(promotion, true); + versioningManager.promote(promotion, true); WorkspaceDiff diff = versioningManager.getWorkspaceDiffWithoutContent(); @@ -569,13 +572,13 @@ public void multiplePromotions() throws GitAPIException, IOException { String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/file_modified.yml")); // first promotion - versioningManager.promoteConfiguration(promotion, true); + versioningManager.promote(promotion, true); // second createTestFiles(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + "/file_modified.yml=new_content"); @@ -584,13 +587,13 @@ public void multiplePromotions() throws GitAPIException, IOException { liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - promotion = new ConfigurationPromotion(); + promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/file_modified.yml")); // second promotion - versioningManager.promoteConfiguration(promotion, true); + versioningManager.promote(promotion, true); // diff WorkspaceDiff diff = versioningManager.getWorkspaceDiffWithoutContent(); @@ -620,19 +623,19 @@ public void differentLiveBranch() throws GitAPIException, IOException { String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/file_modified.yml")); - versioningManager.promoteConfiguration(promotion, true); + versioningManager.promote(promotion, true); - ConfigurationPromotion secondPromotion = new ConfigurationPromotion(); + Promotion secondPromotion = new Promotion(); secondPromotion.setLiveCommitId(liveId); secondPromotion.setWorkspaceCommitId(workspaceId); secondPromotion.setFiles(Arrays.asList("/file_added.yml")); - assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> versioningManager.promoteConfiguration(secondPromotion, true)) + assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> versioningManager.promote(secondPromotion, true)) .withMessage("Live branch has been modified. The provided promotion definition is out of sync."); } @@ -646,7 +649,7 @@ public void promotionWithModification() throws GitAPIException, IOException { String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/file_modified.yml")); @@ -654,7 +657,7 @@ public void promotionWithModification() throws GitAPIException, IOException { createTestFiles(AbstractFileAccessor.CONFIGURATION_FILES_SUBFOLDER + "/file_modified.yml=content_B"); versioningManager.commitAllChanges("commit"); - versioningManager.promoteConfiguration(promotion, true); + versioningManager.promote(promotion, true); // diff live -> workspace WorkspaceDiff diff = versioningManager.getWorkspaceDiffWithoutContent(); @@ -680,7 +683,7 @@ public void selfPromotionProtectionEnabled() throws GitAPIException, IOException String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/file_modified.yml")); @@ -689,7 +692,7 @@ public void selfPromotionProtectionEnabled() throws GitAPIException, IOException versioningManager.commitAllChanges("commit"); doReturn("promoter").when(authentication).getName(); - versioningManager.promoteConfiguration(promotion, false); + versioningManager.promote(promotion, false); assertThat(versioningManager.getLiveRevision() .readConfigurationFile("file_modified.yml")).hasValue("content_A"); @@ -707,14 +710,14 @@ public void selfPromotionPrevented() throws GitAPIException, IOException { String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/file_modified.yml")); RevisionAccess live = versioningManager.getLiveRevision(); - assertThatThrownBy(() -> versioningManager.promoteConfiguration(promotion, false)).isInstanceOf(SelfPromotionNotAllowedException.class); + assertThatThrownBy(() -> versioningManager.promote(promotion, false)).isInstanceOf(SelfPromotionNotAllowedException.class); assertThat(versioningManager.getLiveRevision().getRevisionId()).isEqualTo(live.getRevisionId()); } @@ -784,11 +787,11 @@ private void promote(String... files) throws Exception { String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList(files)); - versioningManager.promoteConfiguration(promotion, true); + versioningManager.promote(promotion, true); } private void buildDummyHistory() throws Exception { @@ -828,6 +831,26 @@ void fileAddedInMostRecentChange() throws Exception { assertThat(modifyingAuthors).containsExactlyInAnyOrder("creating_user"); } + @Test + void agentMappingsAddedInMostRecentChange() throws Exception { + buildDummyHistory(); + + createTestFiles(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME); + doReturn("creating_user").when(authentication).getName(); + versioningManager.commitAllChanges("new commit"); + + SimpleDiffEntry diff = SimpleDiffEntry.builder() + .file(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME) + .type(DiffEntry.ChangeType.ADD) + .build(); + + List modifyingAuthors = versioningManager.getModifyingAuthors(diff, versioningManager.getLatestCommit(Branch.LIVE) + .get() + .getId(), versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId()); + + assertThat(modifyingAuthors).containsExactlyInAnyOrder("creating_user"); + } + @Test void fileAddedAndModifiedBeforeLastPromotion() throws Exception { buildDummyHistory(); @@ -902,6 +925,31 @@ void fileModified() throws Exception { assertThat(modifyingAuthors).containsExactlyInAnyOrder("creating_user", "second_editing_user"); } + @Test + void agentMappingsModified() throws Exception { + buildDummyHistory(); + + createTestFiles(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME); + doReturn("editing_user").when(authentication).getName(); + versioningManager.commitAllChanges("com1"); + promote(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME); + + doReturn("editing_user").when(authentication).getName(); + createTestFiles(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME + "=modified"); + versioningManager.commitAllChanges("com2"); + + SimpleDiffEntry diff = SimpleDiffEntry.builder() + .file(AbstractFileAccessor.AGENT_MAPPINGS_FILE_NAME) + .type(DiffEntry.ChangeType.MODIFY) + .build(); + + List modifyingAuthors = versioningManager.getModifyingAuthors(diff, versioningManager.getLatestCommit(Branch.LIVE) + .get() + .getId(), versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId()); + + assertThat(modifyingAuthors).containsExactlyInAnyOrder("editing_user"); + } + @Test void fileModifiedWithChangesUndone() throws Exception { buildDummyHistory(); @@ -1314,12 +1362,12 @@ public void initialConfigurationSyncTwoRemotes() throws URISyntaxException, GitA String liveId = versioningManager.getLatestCommit(Branch.LIVE).get().getId().name(); String workspaceId = versioningManager.getLatestCommit(Branch.WORKSPACE).get().getId().name(); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setLiveCommitId(liveId); promotion.setWorkspaceCommitId(workspaceId); promotion.setFiles(Arrays.asList("/foobar.yml")); - PromotionResult promotionResult = versioningManager.promoteConfiguration(promotion, true); + PromotionResult promotionResult = versioningManager.promote(promotion, true); assertThat(promotionResult).isEqualTo(PromotionResult.OK); // OK means no synchronization error } @@ -1333,4 +1381,4 @@ private void addEmptyFile(Git repo, String filename) throws IOException { Files.createFile(filesDir.resolve(filename)); } } -} \ No newline at end of file +} diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingManagerTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingManagerTest.java index af2f6eb33c..cc58d7e15b 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingManagerTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingManagerTest.java @@ -4,14 +4,15 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Spy; +import org.mockito.*; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationEventPublisher; +import rocks.inspectit.ocelot.config.model.InspectitServerSettings; +import rocks.inspectit.ocelot.events.AgentMappingsSourceBranchChangedEvent; import rocks.inspectit.ocelot.file.FileManager; import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; import rocks.inspectit.ocelot.file.accessor.workingdirectory.WorkingDirectoryAccessor; +import rocks.inspectit.ocelot.file.versioning.Branch; import rocks.inspectit.ocelot.mappings.model.AgentMapping; import java.io.IOException; @@ -32,7 +33,7 @@ public class AgentMappingManagerTest { @InjectMocks AgentMappingManager manager; - @Spy + @Mock AgentMappingSerializer serializer; @Mock @@ -44,9 +45,17 @@ public class AgentMappingManagerTest { @Mock RevisionAccess readAccessor; + @Mock + ApplicationEventPublisher publisher; + @BeforeEach public void init() { + InspectitServerSettings settings = InspectitServerSettings.builder().initialAgentMappingsSourceBranch("workspace").build(); + serializer = Mockito.spy(new AgentMappingSerializer(settings, fileManager, publisher)); serializer.postConstruct(); + + manager = new AgentMappingManager(serializer, fileManager); + verify(serializer).postConstruct(); lenient().doReturn(writeAccessor).when(fileManager).getWorkingDirectory(); lenient().doReturn(readAccessor).when(fileManager).getWorkspaceRevision(); @@ -533,4 +542,28 @@ public void targetNotExists() throws IOException { verifyNoMoreInteractions(serializer); } } -} \ No newline at end of file + + @Nested + public class SetAgentMappingsSourceBranch { + + @Test + public void verifySourceBranchHasChanged() { + when(fileManager.getLiveRevision()).thenReturn(readAccessor); + when(readAccessor.agentMappingsExist()).thenReturn(true); + + Branch oldBranch = manager.getSourceBranch(); + Branch newBranch = manager.setSourceBranch("LIVE"); + + verify(publisher, times(1)).publishEvent(any(AgentMappingsSourceBranchChangedEvent.class)); + assertThat(oldBranch.equals(newBranch)).isFalse(); + } + + @Test + public void verifyThrowsExceptions() { + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> manager.setSourceBranch(null)) + .withMessage("The set source branch cannot be null."); + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> manager.setSourceBranch("unknown")) + .withMessage("Unhandled branch: unknown"); + } + } +} diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializerTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializerTest.java index ce3164206a..3c8f10ac68 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializerTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/mappings/AgentMappingSerializerTest.java @@ -7,6 +7,11 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationEventPublisher; +import rocks.inspectit.ocelot.config.model.InspectitServerSettings; +import rocks.inspectit.ocelot.events.AgentMappingsSourceBranchChangedEvent; +import rocks.inspectit.ocelot.file.FileManager; +import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; import rocks.inspectit.ocelot.file.accessor.workingdirectory.AbstractWorkingDirectoryAccessor; import rocks.inspectit.ocelot.file.versioning.Branch; import rocks.inspectit.ocelot.mappings.model.AgentMapping; @@ -18,18 +23,27 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; +import static org.mockito.Mockito.verify; +import static rocks.inspectit.ocelot.file.versioning.Branch.LIVE; +import static rocks.inspectit.ocelot.file.versioning.Branch.WORKSPACE; @ExtendWith(MockitoExtension.class) public class AgentMappingSerializerTest { AgentMappingSerializer serializer; - @Mock - AbstractWorkingDirectoryAccessor fileAccessor; + AbstractWorkingDirectoryAccessor workingDirectoryAccessor; + @Mock + FileManager fileManager; + @Mock + ApplicationEventPublisher eventPublisher; + @Mock + RevisionAccess revisionAccess; @BeforeEach public void setup() { - serializer = new AgentMappingSerializer(); + InspectitServerSettings settings = InspectitServerSettings.builder().initialAgentMappingsSourceBranch("workspace").build(); + serializer = new AgentMappingSerializer(settings, fileManager, eventPublisher); serializer.postConstruct(); } @@ -41,14 +55,14 @@ public void successfullyWriteYaml() throws IOException { AgentMapping mapping = AgentMapping.builder() .name("mapping") .source("/any-source") - .sourceBranch(Branch.LIVE) + .sourceBranch(LIVE) .attribute("key", "val") .build(); - serializer.writeAgentMappings(Collections.singletonList(mapping), fileAccessor); + serializer.writeAgentMappings(Collections.singletonList(mapping), workingDirectoryAccessor); ArgumentCaptor writtenFile = ArgumentCaptor.forClass(String.class); - verify(fileAccessor).writeAgentMappings(writtenFile.capture()); + verify(workingDirectoryAccessor).writeAgentMappings(writtenFile.capture()); assertThat(writtenFile.getValue()).isEqualTo("- name: \"mapping\"\n" + " sourceBranch: \"LIVE\"\n"+ @@ -56,7 +70,7 @@ public void successfullyWriteYaml() throws IOException { " - \"/any-source\"\n" + " attributes:\n" + " key: \"val\"\n"); - verifyNoMoreInteractions(fileAccessor); + verifyNoMoreInteractions(workingDirectoryAccessor); } } @@ -72,16 +86,44 @@ public void successfullyReadYaml() { " attributes:\n" + " key: \"val\"\n"; - doReturn(Optional.of(dummyYaml)).when(fileAccessor).readAgentMappings(); + doReturn(Optional.of(dummyYaml)).when(workingDirectoryAccessor).readAgentMappings(); - List result = serializer.readAgentMappings(fileAccessor); + List result = serializer.readAgentMappings(workingDirectoryAccessor); assertThat(result).hasSize(1); AgentMapping mapping = result.get(0); assertThat(mapping.getName()).isEqualTo("mapping"); assertThat(mapping.getSources()).containsExactly("/any-source"); assertThat(mapping.getAttributes()).containsEntry("key", "val"); - assertThat(mapping.getSourceBranch()).isEqualTo(Branch.LIVE); + assertThat(mapping.getSourceBranch()).isEqualTo(LIVE); + } + } + + @Nested + public class setAgentMappingsSourceBranch { + + @Test + void verifySourceBranchHasChanged() { + when(fileManager.getLiveRevision()).thenReturn(revisionAccess); + when(revisionAccess.agentMappingsExist()).thenReturn(true); + + Branch oldBranch = serializer.getSourceBranch(); + Branch newBranch = serializer.setSourceBranch(LIVE); + + verify(eventPublisher, times(1)).publishEvent(any(AgentMappingsSourceBranchChangedEvent.class)); + assertThat(oldBranch.equals(newBranch)).isFalse(); + } + + @Test + void verifySourceBranchHasNotChanged() { + when(fileManager.getLiveRevision()).thenReturn(revisionAccess); + when(revisionAccess.agentMappingsExist()).thenReturn(false); + + Branch oldBranch = serializer.getSourceBranch(); + Branch newBranch = serializer.setSourceBranch(LIVE); + + verify(eventPublisher, times(0)).publishEvent(any(AgentMappingsSourceBranchChangedEvent.class)); + assertThat(oldBranch.equals(newBranch)).isTrue(); } } -} \ No newline at end of file +} diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingControllerTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingControllerTest.java index 9138bb4d62..ca95fa7788 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingControllerTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/mappings/AgentMappingControllerTest.java @@ -40,11 +40,11 @@ public class GetMappings { @Test public void successfullyGetAgentMappings() { List dummyList = new ArrayList<>(); - when(mappingManager.getAgentMappings()).thenReturn(dummyList); + when(mappingManager.getAgentMappings(any())).thenReturn(dummyList); - List result = controller.getMappings(); + List result = controller.getMappings(null); - verify(mappingManager).getAgentMappings(); + verify(mappingManager).getAgentMappings(null); verifyNoMoreInteractions(mappingManager); assertThat(result).isSameAs(dummyList); } @@ -164,4 +164,4 @@ public void addMappingAfter() throws IOException { assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); } } -} \ No newline at end of file +} diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/configuration/PromotionControllerIntTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/promotion/PromotionControllerIntTest.java similarity index 76% rename from components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/configuration/PromotionControllerIntTest.java rename to components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/promotion/PromotionControllerIntTest.java index 1dc2e3a2c0..c3b300d160 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/configuration/PromotionControllerIntTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/promotion/PromotionControllerIntTest.java @@ -1,4 +1,4 @@ -package rocks.inspectit.ocelot.rest.configuration; +package rocks.inspectit.ocelot.rest.promotion; import org.eclipse.jgit.diff.DiffEntry; import org.junit.jupiter.api.Nested; @@ -8,7 +8,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import rocks.inspectit.ocelot.IntegrationTestBase; -import rocks.inspectit.ocelot.file.versioning.model.ConfigurationPromotion; +import rocks.inspectit.ocelot.file.versioning.model.Promotion; import rocks.inspectit.ocelot.file.versioning.model.SimpleDiffEntry; import rocks.inspectit.ocelot.file.versioning.model.WorkspaceDiff; @@ -23,7 +23,7 @@ class GetPromotions { @Test public void noPromotionsAvailable() { - ResponseEntity result = authRest.getForEntity("/api/v1/configuration/promotions", WorkspaceDiff.class); + ResponseEntity result = authRest.getForEntity("/api/v1/promotions", WorkspaceDiff.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody().getEntries()).isEmpty(); @@ -33,7 +33,7 @@ public void noPromotionsAvailable() { public void getPromotionFiles() { authRest.exchange("/api/v1/files/src/file.yml", HttpMethod.PUT, null, Void.class); - ResponseEntity result = authRest.getForEntity("/api/v1/configuration/promotions", WorkspaceDiff.class); + ResponseEntity result = authRest.getForEntity("/api/v1/promotions", WorkspaceDiff.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody().getEntries()).containsExactly(SimpleDiffEntry.builder() @@ -51,15 +51,15 @@ class PromoteConfiguration { public void promoteFiles() { authRest.exchange("/api/v1/files/src/file.yml", HttpMethod.PUT, null, Void.class); - ResponseEntity diff = authRest.getForEntity("/api/v1/configuration/promotions", WorkspaceDiff.class); + ResponseEntity diff = authRest.getForEntity("/api/v1/promotions", WorkspaceDiff.class); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setFiles(Collections.singletonList("/src/file.yml")); promotion.setLiveCommitId(diff.getBody().getLiveCommitId()); promotion.setWorkspaceCommitId(diff.getBody().getWorkspaceCommitId()); promotion.setCommitMessage("test"); - ResponseEntity result = authRest.exchange("/api/v1/configuration/promote", HttpMethod.POST, new HttpEntity<>(promotion), String.class); + ResponseEntity result = authRest.exchange("/api/v1/promote", HttpMethod.POST, new HttpEntity<>(promotion), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("{\"result\":\"OK\"}"); @@ -69,15 +69,15 @@ public void promoteFiles() { public void promoteNoFiles() { authRest.exchange("/api/v1/files/src/file.yml", HttpMethod.PUT, null, Void.class); - ResponseEntity diff = authRest.getForEntity("/api/v1/configuration/promotions", WorkspaceDiff.class); + ResponseEntity diff = authRest.getForEntity("/api/v1/promotions", WorkspaceDiff.class); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setFiles(Collections.emptyList()); promotion.setLiveCommitId(diff.getBody().getLiveCommitId()); promotion.setWorkspaceCommitId(diff.getBody().getWorkspaceCommitId()); promotion.setCommitMessage("test"); - ResponseEntity result = authRest.exchange("/api/v1/configuration/promote", HttpMethod.POST, new HttpEntity<>(promotion), Void.class); + ResponseEntity result = authRest.exchange("/api/v1/promote", HttpMethod.POST, new HttpEntity<>(promotion), Void.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); } @@ -86,15 +86,15 @@ public void promoteNoFiles() { public void emptyPromotionMessage() { authRest.exchange("/api/v1/files/src/file.yml", HttpMethod.PUT, null, Void.class); - ResponseEntity diff = authRest.getForEntity("/api/v1/configuration/promotions", WorkspaceDiff.class); + ResponseEntity diff = authRest.getForEntity("/api/v1/promotions", WorkspaceDiff.class); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setFiles(Collections.emptyList()); promotion.setLiveCommitId(diff.getBody().getLiveCommitId()); promotion.setWorkspaceCommitId(diff.getBody().getWorkspaceCommitId()); promotion.setCommitMessage(""); - ResponseEntity result = authRest.exchange("/api/v1/configuration/promote", HttpMethod.POST, new HttpEntity<>(promotion), Void.class); + ResponseEntity result = authRest.exchange("/api/v1/promote", HttpMethod.POST, new HttpEntity<>(promotion), Void.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); } @@ -103,15 +103,15 @@ public void emptyPromotionMessage() { public void nullPromotionMessage() { authRest.exchange("/api/v1/files/src/file.yml", HttpMethod.PUT, null, Void.class); - ResponseEntity diff = authRest.getForEntity("/api/v1/configuration/promotions", WorkspaceDiff.class); + ResponseEntity diff = authRest.getForEntity("/api/v1/promotions", WorkspaceDiff.class); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setFiles(Collections.emptyList()); promotion.setLiveCommitId(diff.getBody().getLiveCommitId()); promotion.setWorkspaceCommitId(diff.getBody().getWorkspaceCommitId()); promotion.setCommitMessage(null); - ResponseEntity result = authRest.exchange("/api/v1/configuration/promote", HttpMethod.POST, new HttpEntity<>(promotion), Void.class); + ResponseEntity result = authRest.exchange("/api/v1/promote", HttpMethod.POST, new HttpEntity<>(promotion), Void.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST); } @@ -120,20 +120,20 @@ public void nullPromotionMessage() { public void conflictingPromotion() { authRest.exchange("/api/v1/files/src/file.yml", HttpMethod.PUT, null, Void.class); - ResponseEntity diff = authRest.getForEntity("/api/v1/configuration/promotions", WorkspaceDiff.class); + ResponseEntity diff = authRest.getForEntity("/api/v1/promotions", WorkspaceDiff.class); - ConfigurationPromotion promotion = new ConfigurationPromotion(); + Promotion promotion = new Promotion(); promotion.setFiles(Collections.singletonList("/src/file.yml")); promotion.setLiveCommitId(diff.getBody().getLiveCommitId()); promotion.setWorkspaceCommitId(diff.getBody().getWorkspaceCommitId()); promotion.setCommitMessage("test"); - authRest.exchange("/api/v1/configuration/promote", HttpMethod.POST, new HttpEntity<>(promotion), String.class); + authRest.exchange("/api/v1/promote", HttpMethod.POST, new HttpEntity<>(promotion), String.class); // conflicting promotion - ResponseEntity result = authRest.exchange("/api/v1/configuration/promote", HttpMethod.POST, new HttpEntity<>(promotion), String.class); + ResponseEntity result = authRest.exchange("/api/v1/promote", HttpMethod.POST, new HttpEntity<>(promotion), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.CONFLICT); } } -} \ No newline at end of file +} diff --git a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/versioning/VersioningControllerIntTest.java b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/versioning/VersioningControllerIntTest.java index c567d92eea..fa4be1ac8a 100644 --- a/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/versioning/VersioningControllerIntTest.java +++ b/components/inspectit-ocelot-configurationserver/src/test/java/rocks/inspectit/ocelot/rest/versioning/VersioningControllerIntTest.java @@ -23,9 +23,9 @@ public void emptyResponse() { assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); WorkspaceVersion[] resultBody = result.getBody(); - assertThat(resultBody).hasSize(2) + assertThat(resultBody).hasSize(1) .extracting(WorkspaceVersion::getAuthor, WorkspaceVersion::getMessage) - .contains(tuple("System", "Initializing Git repository using existing working directory"), tuple("System", "Staging and committing agent mappings during startup")); + .contains(tuple("System", "Initializing Git repository using existing working directory")); assertThat(resultBody).allMatch(version -> ObjectId.isId(version.getId())); } @@ -38,9 +38,9 @@ public void validResponse() { assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); WorkspaceVersion[] resultBody = result.getBody(); - assertThat(resultBody).hasSize(3) + assertThat(resultBody).hasSize(2) .extracting(WorkspaceVersion::getAuthor, WorkspaceVersion::getMessage) - .contains(tuple("admin", "Commit configuration file and agent mapping changes"), tuple("System", "Staging and committing agent mappings during startup"), tuple("System", "Initializing Git repository using existing working directory")); + .contains(tuple("admin", "Commit configuration file and agent mapping changes"), tuple("System", "Initializing Git repository using existing working directory")); assertThat(resultBody).allMatch(version -> ObjectId.isId(version.getId())); } @@ -60,4 +60,4 @@ public void useLimit() { } } -} \ No newline at end of file +} diff --git a/inspectit-ocelot-documentation/docs/assets/agent_mappings_source_branch.png b/inspectit-ocelot-documentation/docs/assets/agent_mappings_source_branch.png new file mode 100644 index 0000000000000000000000000000000000000000..2d9892611a3262191730c934479a6786169b6e40 GIT binary patch literal 226287 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Ξ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

GGYX0shxG#$@s|OK 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 OZW>$uQF-m&^Zy6zG3R&y literal 0 HcmV?d00001 diff --git a/inspectit-ocelot-documentation/docs/config-server/agent-mappings.md b/inspectit-ocelot-documentation/docs/config-server/agent-mappings.md index 31ebf3a477..2dfd3b79ee 100644 --- a/inspectit-ocelot-documentation/docs/config-server/agent-mappings.md +++ b/inspectit-ocelot-documentation/docs/config-server/agent-mappings.md @@ -3,11 +3,14 @@ id: agent-mappings title: Agent Mappings --- -Agent mappings are used to determine which agent receives which configuration. Here, individual files or specific folders can be defined, which serve as the basis for the resulting configuration. Furthermore, you can specify which branch (`WORKSPACE` or `LIVE`) the mapping should use to obtain the configuration files. +Agent mappings are used to determine which agent receives which configuration. Here, individual files or specific +folders can be defined, which serve as the basis for the resulting configuration. +Furthermore, you can specify which branch (`WORKSPACE` or `LIVE`) the mapping should use to obtain the configuration files. It's important to note that the first matching agent mapping will be used to determine which configuration is shipped to an agent. Additional agent mappings which may also match the attributes list sent by an agent will be ignored. -See section [HTTP-based Configuration](configuration/external-configuration-sources.md#http-based-configuration) for information on how to specify which attributes will be sent by an agent. +See section [HTTP-based Configuration](configuration/external-configuration-sources.md#http-based-configuration) for +information on how to specify which attributes will be sent by an agent. An agent mapping consists of the following properties: @@ -31,6 +34,35 @@ This default agent mapping maps each agent to each configuration file of the `wo sourceBranch: "WORKSPACE" ``` +## Git Staging + +:::tip +You can find more detailed information about file staging and promotion [here](config-server/files-staging.md). +::: + +Since the version `2.5.7` the configuration for the agent mappings itself will also be included into the git staging. For all agent mappings +the configuration is stored in one file. After one or several agent mappings have been edited, the changes will also +appear on the promotion page. The promotion of the agent mappings configuration works directly like the promotion of agent configuration files. + +Additionally, it is possible to select a source branch (`WORKSPACE` or `LIVE`) for the agent mappings configuration itself. +This will determine, whether changes in the agent mappings should be applied directly or only after the promotion of the +agent mappings configuration. + +:::important +The source branch for the agent mappings configuration will **not affect** the defined `sourceBranch` in each **individual agent mapping**! +The `sourceBranch` property of an individual agent mapping determines, which branch should be used for the agent configuration files. +::: + +![Different Source Branches on Agent Mappings Page](assets/agent_mappings_source_branch.png) + +You can define, which source branch should be used at start-up for the agent mappings +in the application properties of the configuration server: + +```YAML +inspectit-config-server: + initial-agent-mappings-source-branch: WORKSPACE +``` + ## Example Agent Mappings ### Example 1 @@ -60,4 +92,5 @@ The following agent mapping will deliver all configuration files located in the attributes: service: "customer-service" sourceBranch: "WORKSPACE" -``` \ No newline at end of file +``` + diff --git a/inspectit-ocelot-documentation/docs/config-server/configuration-staging.md b/inspectit-ocelot-documentation/docs/config-server/files-staging.md similarity index 95% rename from inspectit-ocelot-documentation/docs/config-server/configuration-staging.md rename to inspectit-ocelot-documentation/docs/config-server/files-staging.md index a71c800323..4458f5c694 100644 --- a/inspectit-ocelot-documentation/docs/config-server/configuration-staging.md +++ b/inspectit-ocelot-documentation/docs/config-server/files-staging.md @@ -1,16 +1,16 @@ --- -id: configuration-files-staging -title: Configuration Files Staging Using Remote Git -sidebar_label: Configuration Files Staging +id: files-staging +title: File Staging Using Remote Git +sidebar_label: File Staging --- :::tip -It is recommended to first familiarize yourself with [how the configuration server manages configuration](config-server/managing-configurations.md) files before reading this chapter. +It is recommended to first familiarize yourself with [how the configuration server manages files](config-server/managing-files.md) before reading this chapter. ::: Since version `1.11.0` the Configuration Server offers the possibility that external Git repositories can be connected. This allows configuration files to be obtained from an external Git repository and also transferred to it. -This allows us to secure configuration files (e.g. for creating backups), initialize configuration servers with a specific set of configuration files or chain several configuration servers together. +This allows us to secure configuration files and agent mappings (e.g. for creating backups), initialize configuration servers with a specific set of configuration files or chain several configuration servers together. The latter can be used, for example, to cover more complex scenarios, such as synchronizing configuration files across multiple system stages. :::important @@ -170,4 +170,4 @@ All configuration server properties mentioned below refer to being set under the | `authentication-type` | `NONE` | The type of authentication to use. Possible values: `NONE`, `PASSWORD`, `PPK`. | | `username` | `null` | The username for accessing the remote repository. Only used in case of `PASSWORD` authentication. | | `password` | `null` | The password for accessing the remote repository. Only used in case of `PASSWORD` authentication. | -| `private-key-file` | `null` | Additional private key to use for SSH authentication. The server will automatically load the known hosts and private keys from the default locations (identity, id_rsa and id_dsa) in the user’s `.ssh` directory. Only used in case of `PPK` authentication. | \ No newline at end of file +| `private-key-file` | `null` | Additional private key to use for SSH authentication. The server will automatically load the known hosts and private keys from the default locations (identity, id_rsa and id_dsa) in the user’s `.ssh` directory. Only used in case of `PPK` authentication. | diff --git a/inspectit-ocelot-documentation/docs/config-server/managing-configurations.md b/inspectit-ocelot-documentation/docs/config-server/managing-files.md similarity index 64% rename from inspectit-ocelot-documentation/docs/config-server/managing-configurations.md rename to inspectit-ocelot-documentation/docs/config-server/managing-files.md index 98c3797723..6ae229b8f9 100644 --- a/inspectit-ocelot-documentation/docs/config-server/managing-configurations.md +++ b/inspectit-ocelot-documentation/docs/config-server/managing-files.md @@ -1,23 +1,38 @@ --- -id: managing-configurations -title: Managing Configuration Files +id: managing-files +title: Managing Files +sidebar_label: Managing Files --- -The configuration server internally uses Git to manage its working directory. This allows a versioning of configurations, so that it is possible to track when and how a configuration was created, changed or deleted. Additionally, it allows unwanted changes to be reverted and configuration files to be restored that would otherwise be lost. +The configuration server internally uses Git to manage its working directory. +This allows a versioning of configurations as well as the agent mappings, so that it is possible to track when and how a file was created, +changed or deleted. Additionally, it allows unwanted changes to be reverted and configuration files to be restored that +would otherwise be lost. -Furthermore, a staging of configurations is possible. By default, the configuration server has two branches (`WORKSPACE` and `LIVE`) which contain the configuration files and which can be used as the basis for the configuration to be delivered. All changes made by users to the configuration files affect the `WORKSPACE` branch. The `LIVE` branch cannot be changed directly by users. A change to the `LIVE` branch is only possible by transferring an already done change to the `WORKSPACE` branch to the `LIVE` branch - in this case called "promotion". +Furthermore, a staging of configurations and agent mappings is possible. By default, the configuration server has two +branches (`WORKSPACE` and `LIVE`) which can be used as the basis for the configurations to be delivered. +All changes made by users to the configuration files and the agent mappings affect the `WORKSPACE` branch. +The `LIVE` branch cannot be changed directly by users. A change to the `LIVE` branch is only possible by transferring +an already done change to the `WORKSPACE` branch to the `LIVE` branch - in this case called "promotion". :::tip -It is possible for agents to obtain the configurations exclusively from the `LIVE` branch. As a result, users can now edit configuration files without having to deliver these - possibly incomplete changes - directly, thus preventing warnings due to invalid configurations. +It is possible for agents to obtain the configurations exclusively from the `LIVE` branch. As a result, users can now +edit configuration files without having to deliver these - possibly incomplete changes - directly, thus preventing +warnings due to invalid configurations. + +You can achieve this by setting the source branch for a specific agent mapping to `LIVE`. ::: -In order to deliver specific configurations to agents, so-called "agent mappings" can be used. These can be used to define precisely which files and from which branch an agent should receive. +**Agent Mappings** can be used, in order to deliver specific configurations to agents. +They can also be used to define precisely which files and from which branch an agent should receive. ![Configuration Server Workspace Architecture](assets/configuration-server-branches.png) -## Promoting Configuration Files +## Promoting Files -Changes to configuration files by users only affect the `WORKSPACE` branch. If a user wants to make a change to a configuration file, but the version of the `LIVE` branch is delivered to the agent, the user must do the following: +Changes to configuration files or agent mappings by users only affect the `WORKSPACE` branch. +If a user wants to make a change to a configuration file, but the version of the `LIVE` branch is delivered to the agent, +the user must do the following: * First, the user must perform the change, which allows the change to be tracked on the workspace branch. * Afterwards the change must be approved and promoted by a user who has promotion rights. Only through promotion the changes to a file will be transferred to the `LIVE` branch. @@ -40,8 +55,8 @@ In the following screenshot, the configuration server's promotion user interface ## Four-Eyes Promoting Restriction By default, any user with promotion rights can promote any changes. -In some setups it can be beneficial to enforce peer-reviews before promoting configuration changes. -The configuration server offers a mechanism to enforce a four eyes principle for configuration changes which can be enabled using the following setting: +In some setups it can be beneficial to enforce peer-reviews before promoting changes. +The configuration server offers a mechanism to enforce a four eyes principle for changes which can be enabled using the following setting: ```YAML inspectit-config-server: @@ -49,7 +64,7 @@ inspectit-config-server: four-eyes-promotion: true ``` -When this setting is enabled, users with promotion rights will no longer be able to promote their own configuration changes. +When this setting is enabled, users with promotion rights will no longer be able to promote their own changes. :::note This restriction is only applied to non-admin users! Users with admin rights will still be able to promote their own changes. @@ -70,7 +85,7 @@ inspectit-config-server: ## External Changes -While it is not recommended, it is possible to directly change the configuration files in the filesystem instead of via the +While it is not recommended, it is possible to directly change the files in the filesystem instead of via the configuration server's UI or REST-API. In order for your changes in the file-system to become active, you need to let the configuration server know about the external changes. @@ -79,4 +94,4 @@ A request to this endpoint causes all external changes to be committed to the `W Alternatively, you can also manually commit to the `WORKSPACE` branch in the working directory of the configuration server. However, you need to make sure that the server is either shut down or you need to have the guarantee that no other users are currently editing files via the UI, -otherwise your repository might get corrupted. \ No newline at end of file +otherwise your repository might get corrupted. diff --git a/inspectit-ocelot-documentation/website/sidebars.json b/inspectit-ocelot-documentation/website/sidebars.json index c3b203f988..53bfd828d1 100644 --- a/inspectit-ocelot-documentation/website/sidebars.json +++ b/inspectit-ocelot-documentation/website/sidebars.json @@ -49,8 +49,8 @@ "Configuration Server": [ "config-server/overview", "config-server/cs-configuration", - "config-server/managing-configurations", - "config-server/configuration-files-staging", + "config-server/managing-files", + "config-server/files-staging", "config-server/agent-mappings", "config-server/scope-wizard", "config-server/class-browser",