Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating flare index on first configuration and let user change their cron job index in the configuration screen #45

Merged
merged 1 commit into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions packages/configuration-screen/src/ConfigurationScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { useEffect, useState, FC } from 'react';
import {
appName,
createFlareIndex,
redirectToHomepage,
retrieveApiKey,
retrieveAvailableIndexNames,
retrieveCurrentIndexName,
retrieveIngestMetadataOnly,
retrieveTenantId,
retrieveUserTenants,
Expand All @@ -25,11 +29,13 @@ const TOAST_TENANT_SUCCESS = 'tenant_success';
const ConfigurationScreen: FC<{ theme: string }> = ({ theme }) => {
const [apiKey, setApiKey] = useState('');
const [tenantId, setTenantId] = useState(-1);
const [indexName, setIndexName] = useState(appName);
const [errorMessage, setErrorMessage] = useState('');
const [tenants, setUserTenants] = useState<Tenant[]>([]);
const [isIngestingMetadataOnly, setIsIngestingMetadataOnly] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isCompleted, setIsCompleted] = useState(false);
const [indexNames, setIndexNames] = useState<string[]>([]);

toastManager.setTheme(theme);

Expand All @@ -54,6 +60,7 @@ const ConfigurationScreen: FC<{ theme: string }> = ({ theme }) => {

const handleApiKeyChange = (e): void => setApiKey(e.target.value);
const handleTenantIdChange = (e): void => setTenantId(parseInt(e.target.value, 10));
const handleIndexNameChange = (e): void => setIndexName(e.target.value);
const handleIsIngestingMetadataChange = (e): void => {
setIsIngestingMetadataOnly(e.target.checked);
};
Expand Down Expand Up @@ -95,7 +102,7 @@ const ConfigurationScreen: FC<{ theme: string }> = ({ theme }) => {

const handleSubmitTenant = (): void => {
setIsLoading(true);
saveConfiguration(apiKey, tenantId, isIngestingMetadataOnly)
saveConfiguration(apiKey, tenantId, indexName, isIngestingMetadataOnly)
.then(() => {
setIsLoading(false);
setIsCompleted(true);
Expand Down Expand Up @@ -128,13 +135,21 @@ const ConfigurationScreen: FC<{ theme: string }> = ({ theme }) => {
if (isCompleted) {
return;
}
Promise.all([retrieveApiKey(), retrieveTenantId(), retrieveIngestMetadataOnly()]).then(
([key, id, ingestMetadataOnly]) => {
createFlareIndex().then(() => {
Promise.all([
retrieveApiKey(),
retrieveTenantId(),
retrieveIngestMetadataOnly(),
retrieveCurrentIndexName(),
retrieveAvailableIndexNames(),
]).then(([key, id, ingestMetadataOnly, index, availableIndexNames]) => {
setApiKey(key);
setTenantId(id);
setIsIngestingMetadataOnly(ingestMetadataOnly);
}
);
setIndexName(index);
setIndexNames(availableIndexNames);
});
});
}, [isCompleted]);

useEffect(() => {
Expand Down Expand Up @@ -178,11 +193,14 @@ const ConfigurationScreen: FC<{ theme: string }> = ({ theme }) => {
show={currentConfigurationStep === ConfigurationSteps.UserPreferences}
selectedTenantId={tenantId}
tenants={tenants}
selectedIndexName={indexName}
indexNames={indexNames}
isLoading={isLoading}
isIngestingMetadataOnly={isIngestingMetadataOnly}
onNavigateBackClick={handleBackButton}
onSubmitUserPreferencesClick={handleSubmitTenant}
onTenantIdChange={handleTenantIdChange}
onIndexNameChange={handleIndexNameChange}
onIngestingMetadataChange={handleIsIngestingMetadataChange}
/>
<ConfigurationCompletedStep
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, useEffect, useState } from 'react';
import React, { FC } from 'react';
import Button from './Button';
import { getFlareDataUrl } from '../utils/setupConfiguration';
import ArrowRightIcon from './icons/ArrowRightIcon';
Expand All @@ -10,12 +10,6 @@ const ConfigurationCompletedStep: FC<{
tenantName: string;
onEditConfigurationClick: () => void;
}> = ({ show, tenantName, onEditConfigurationClick }) => {
const [indexName, setIndexName] = useState<string>();

useEffect(() => {
getFlareDataUrl().then((name) => setIndexName(name));
}, []);

return (
<div hidden={!show}>
<h5>
Expand All @@ -29,7 +23,7 @@ const ConfigurationCompletedStep: FC<{
Edit Configuration
</Button>
<div className="link">
<a href={indexName}>View Flare Data</a>
<a href={getFlareDataUrl()}>View Flare Data</a>
<ArrowRightIcon remSize={1} />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-top: 2.5rem;
margin-top: 1.5rem;
gap: 1rem;
}

Expand All @@ -13,6 +13,13 @@
width: 100%;
align-items: flex-start;
margin-top: 1rem;
gap: 1rem;
}

.form-item {
display: flex;
flex-direction: column;
align-items: flex-start;
}

.progress-bar-container {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,30 @@ const ConfigurationInitialStep: FC<{
<div hidden={!show}>
<h5>Enter your API key</h5>
<div className="form-group">
<div className="label-tooltip">
<Label isRequired>API Key</Label>
<Tooltip>
<div>
{'You can find your API Keys in your '}
<a target="_blank" href="https://app.flare.io/#/profile">
Flare Profile
</a>
</div>
</Tooltip>
</div>
<input
id="apiKey"
type="password"
value={apiKey}
onChange={onApiKeyChange}
className={`input ${errorMessage.length > 0 ? 'border-error' : ''}`}
placeholder="Your API Key"
/>
<div className="error-container" hidden={errorMessage.length === 0}>
<ErrorIcon remSize={1} />
<small>Error. {errorMessage}</small>
<div className="form-item">
<div className="label-tooltip">
<Label isRequired>API Key</Label>
<Tooltip>
<div>
{'You can find your API Keys in your '}
<a target="_blank" href="https://app.flare.io/#/profile">
Flare Profile
</a>
</div>
</Tooltip>
</div>
<input
id="apiKey"
type="password"
value={apiKey}
onChange={onApiKeyChange}
className={`input ${errorMessage.length > 0 ? 'border-error' : ''}`}
placeholder="Your API Key"
/>
<div className="error-container" hidden={errorMessage.length === 0}>
<ErrorIcon remSize={1} />
<small>Error. {errorMessage}</small>
</div>
</div>
<div className="button-group">
<Button onClick={(): void => onCancelConfigurationClick()} isSecondary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
font-size: 0.75rem;
color: var(--secondary-text-color);
margin-top: 5px;
margin-bottom: 1rem;
}

.switch-layout {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,66 @@ const ConfigurationUserPreferencesStep: FC<{
show: boolean;
tenants: Tenant[];
selectedTenantId: number;
indexNames: string[];
selectedIndexName: string;
isLoading: boolean;
isIngestingMetadataOnly: boolean;
onNavigateBackClick: () => void;
onSubmitUserPreferencesClick: () => void;
onTenantIdChange: (e: ChangeEvent) => void;
onIndexNameChange: (e: ChangeEvent) => void;
onIngestingMetadataChange: (e: ChangeEvent) => void;
}> = ({
show,
tenants,
selectedTenantId,
indexNames,
selectedIndexName,
isLoading,
isIngestingMetadataOnly,
onNavigateBackClick,
onSubmitUserPreferencesClick,
onTenantIdChange,
onIndexNameChange,
onIngestingMetadataChange,
}) => {
return (
<div hidden={!show}>
<h5>Please select the Tenant you want to ingest events from</h5>
<div className="form-group">
<Label isRequired>Tenant</Label>
<Select id="tenants" onChange={onTenantIdChange} value={selectedTenantId}>
{tenants.map((tenant) => {
return (
<option key={tenants.indexOf(tenant)} value={tenant.id}>
{tenant.name}
</option>
);
})}
</Select>
<small className="note">You can only monitor one tenant at a time.</small>
<div className="switch-layout">
<span>Only ingest the metadata of events</span>
<Switch value={isIngestingMetadataOnly} onChange={onIngestingMetadataChange} />
<div className="form-item">
<Label>Tenant</Label>
<Select id="tenants" onChange={onTenantIdChange} value={selectedTenantId}>
{tenants.map((tenant) => {
return (
<option key={tenants.indexOf(tenant)} value={tenant.id}>
{tenant.name}
</option>
);
})}
</Select>
<small className="note">You can only monitor one tenant at a time.</small>
</div>
<div className="form-item">
<Label>Splunk Index for event ingestion</Label>
<Select id="indexes" onChange={onIndexNameChange} value={selectedIndexName}>
{indexNames.map((indexName) => {
return (
<option key={indexNames.indexOf(indexName)} value={indexName}>
{indexName}
</option>
);
})}
</Select>
</div>
<div className="form-item">
<div className="switch-layout">
<span>Only ingest the metadata of events</span>
<Switch
value={isIngestingMetadataOnly}
onChange={onIngestingMetadataChange}
/>
</div>
</div>
<div className="button-group">
<Button onClick={(): void => onNavigateBackClick()} isSecondary>
Expand Down
2 changes: 1 addition & 1 deletion packages/configuration-screen/src/components/Select.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ select {
border: 1px solid var(--secondary-text-color);
border-radius: 40px;
padding-right: 1rem;
margin-top: 1rem;
margin-top: 0.5rem;
}

.select-container:hover {
Expand Down
2 changes: 1 addition & 1 deletion packages/configuration-screen/src/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ input {
input {
border: 1px solid var(--secondary-text-color);
border-radius: 40px;
margin-top: 1rem;
margin-top: 0.5rem;
}

input:hover {
Expand Down
14 changes: 12 additions & 2 deletions packages/configuration-screen/src/models/splunk.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import '../vendor/splunk.min.js';

export interface SplunkApplicationNamespace {
app?: string;
owner?: string;
Expand All @@ -13,6 +11,10 @@ export interface SplunkPassword {
};
}

export interface SplunkIndex {
name: string;
}

export interface SplunkAppAccessor {
reload: () => void;
}
Expand Down Expand Up @@ -51,6 +53,13 @@ export interface ConfigurationsAccessor {
list: () => Array<{ name: string }>;
}

export interface SplunkIndexesAccessor {
fetch: () => SplunkIndexesAccessor;
create: (indexName: string, data: any) => void;
item: (indexName: string) => SplunkIndex;
list: () => Array<SplunkIndex>;
}

export interface SplunkStoragePasswordAccessors {
fetch: () => SplunkStoragePasswordAccessors;
item: (applicationName: string) => SplunkAppAccessor;
Expand All @@ -63,6 +72,7 @@ export interface SplunkService {
configurations: (params: SplunkApplicationNamespace) => ConfigurationsAccessor;
apps: () => SplunkAppsAccessor;
storagePasswords: () => SplunkStoragePasswordAccessors;
indexes: () => SplunkIndexesAccessor;
post: (
splunkUrlPath: string,
data: any,
Expand Down
22 changes: 13 additions & 9 deletions packages/configuration-screen/src/utils/configurationFileHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,30 +139,34 @@ export async function updateConfigurationFile(
await updateStanzaProperties(configurationStanzaAccessor, properties);
}

export async function getCurrentIndexName(service: SplunkService): Promise<string> {
export async function getConfigurationStanzaValue(
service: SplunkService,
configurationFilename: string,
stanzaName: string,
propertyName: string,
defaultValue: string
): Promise<string> {
// Retrieve the accessor used to get a configuration file
let configurations = service.configurations({
// Name space information not provided
});
configurations = await promisify(configurations.fetch)();

// Retrieves the configuration file accessor
let configurationFileAccessor = getConfigurationFile(configurations, 'inputs');
let configurationFileAccessor = getConfigurationFile(configurations, configurationFilename);
configurationFileAccessor = await promisify(configurationFileAccessor.fetch)();

// Retrieves the configuration stanza accessor
let configurationStanzaAccessor = getConfigurationFileStanza(
configurationFileAccessor,
'script://$SPLUNK_HOME/etc/apps/flare/bin/cron_job_ingest_events.py'
stanzaName
);
configurationStanzaAccessor = await promisify(configurationStanzaAccessor.fetch)();

if (
!('index' in configurationStanzaAccessor._properties) ||
configurationStanzaAccessor._properties.index === 'default'
) {
return 'main';
let propertyValue = defaultValue;
if (propertyName in configurationStanzaAccessor._properties) {
propertyValue = configurationStanzaAccessor._properties[propertyName];
}

return configurationStanzaAccessor._properties.index;
return propertyValue;
}
Loading