Skip to content

Commit

Permalink
Merge pull request #79 from Flared/mahinse/restart_error_message
Browse files Browse the repository at this point in the history
Rewrote the interfaces of the Splunk object to follow the hierarchy of the Javascript SplunkSDK
  • Loading branch information
TyMarc authored Jan 16, 2025
2 parents 5728ccd + ed7ddda commit 4222186
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 172 deletions.
8 changes: 4 additions & 4 deletions packages/react-components/src/StatusScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { FC, useEffect, useState } from 'react';
import Button from './components/Button';
import './global.css';
import { SplunkCollectionItem } from './models/splunk';
import { KVCollectionItem } from './models/splunk';
import './StatusScreen.css';
import {
fetchCollectionItems,
Expand Down Expand Up @@ -37,7 +37,7 @@ const StatusScreen: FC<{ theme: string }> = ({ theme }) => {
fetchCollectionItems(),
fetchVersionName('unknown'),
fetchCurrentIndexName(),
]).then(([id, splunkCollectionItems, version, indexName]) => {
]).then(([id, kvCollectionItems, version, indexName]) => {
const items: StatusItem[] = [
{
key: StatusItemKeys.VERSION,
Expand All @@ -57,7 +57,7 @@ const StatusScreen: FC<{ theme: string }> = ({ theme }) => {
value: `${id}`,
},
];
splunkCollectionItems.forEach((item) => {
kvCollectionItems.forEach((item) => {
if (item.key === StatusItemKeys.LAST_FETCHED) {
items.push({
key: item.key.startsWith(CollectionKeys.NEXT_PREFIX)
Expand Down Expand Up @@ -118,7 +118,7 @@ const StatusScreen: FC<{ theme: string }> = ({ theme }) => {
return 'Unknown Status Item';
}

function formatValue(item: SplunkCollectionItem): string {
function formatValue(item: KVCollectionItem): string {
if (item.key === StatusItemKeys.START_DATE || item.key === StatusItemKeys.LAST_FETCHED) {
const date = new Date(item.value);
return date.toLocaleString();
Expand Down
4 changes: 2 additions & 2 deletions packages/react-components/src/models/constants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { SplunkApplicationNamespace } from './splunk';
import { ApplicationNamespace } from './splunk';

export const APP_NAME = 'flare';
export const STORAGE_REALM = 'flare_integration_realm';
export const APPLICATION_NAMESPACE: SplunkApplicationNamespace = {
export const APPLICATION_NAMESPACE: ApplicationNamespace = {
owner: 'nobody',
app: APP_NAME,
sharing: 'app',
Expand Down
114 changes: 38 additions & 76 deletions packages/react-components/src/models/splunk.ts
Original file line number Diff line number Diff line change
@@ -1,103 +1,65 @@
export interface SplunkApplicationNamespace {
app?: string;
owner?: string;
sharing?: string;
}

export interface SplunkPassword {
name: string;
_properties: {
clear_password: string;
};
}

export interface SplunkCollectionItem {
export interface KVCollectionItem {
key: string;
value: string;
user: string;
}

export interface SplunkIndex {
name: string;
}

export interface SplunkSavedSearch {
name: string;
qualifiedPath: string;
update: (properties: Record<string, string>) => SplunkRequestResponse;
}

export interface SplunkAppAccessor {
reload: () => void;
}

export interface Stanza {
name: string;
export interface ApplicationNamespace {
app?: string;
owner?: string;
sharing?: string;
}

export interface SplunkRequestResponse {
export interface HTTPResponse {
status: number;
data: any;
}

export interface SplunkAppsAccessor {
fetch: () => SplunkAppsAccessor;
item: (applicationName: string) => SplunkAppAccessor;
export interface Endpoint {
fetch: () => this;
del: (relativePath: string) => HTTPResponse;
qualifiedPath: string;
}

export interface ConfigurationStanzaAccessor {
fetch: () => ConfigurationStanzaAccessor;
update: (properties: Record<string, string>) => SplunkRequestResponse;
list: () => Array<{ name: string }>;
export interface Resource extends Endpoint {
properties: () => Record<string, string>;
_properties: Record<string, string>;
}

export interface ConfigurationFileAccessor {
create: (stanzaName: string) => SplunkRequestResponse;
fetch: () => ConfigurationFileAccessor;
item: (
stanzaName: string,
properties: SplunkApplicationNamespace
) => ConfigurationStanzaAccessor;
list: () => Array<{ name: string }>;
export interface Entity extends Resource {
reload: () => void;
update: (properties: Record<string, string>) => HTTPResponse;
name: string;
}

export interface ConfigurationsAccessor {
fetch: () => ConfigurationsAccessor;
create: (configurationFilename: string) => SplunkRequestResponse;
item: (stanzaName: string, properties: SplunkApplicationNamespace) => ConfigurationFileAccessor;
list: () => Array<{ name: string }>;
export interface Collection<T extends Entity | Collection<Entity>> extends Resource {
item: (itemName: string, namespace: ApplicationNamespace) => T;
list: () => Array<T>;
}

export interface ConfigurationFile extends Collection<Entity> {
create: (stanzaName: string) => HTTPResponse;
name: string;
}

export interface SplunkIndexesAccessor {
fetch: () => SplunkIndexesAccessor;
create: (indexName: string, data: any) => SplunkRequestResponse;
item: (indexName: string) => SplunkIndex;
list: () => Array<SplunkIndex>;
export interface Configurations extends Collection<ConfigurationFile> {
create: (configurationFilename: string) => HTTPResponse;
}

export interface SplunkSavedSearchAccessor {
fetch: () => SplunkSavedSearchAccessor;
create: (indexName: string, data: any) => SplunkRequestResponse;
item: (indexName: string) => SplunkSavedSearch;
list: () => Array<SplunkSavedSearch>;
export interface Indexes extends Collection<Entity> {
create: (indexName: string, data: any) => HTTPResponse;
}

export interface SplunkStoragePasswordAccessors {
fetch: () => SplunkStoragePasswordAccessors;
item: (applicationName: string) => SplunkAppAccessor;
list: () => Array<SplunkPassword>;
del: (passwordId: string) => SplunkRequestResponse;
create: (params: { name: string; realm: string; password: string }) => SplunkRequestResponse;
export interface StoragePasswords extends Collection<Entity> {
create: (params: { name: string; realm: string; password: string }) => HTTPResponse;
}

export interface SplunkService {
configurations: (params: SplunkApplicationNamespace) => ConfigurationsAccessor;
apps: () => SplunkAppsAccessor;
storagePasswords: () => SplunkStoragePasswordAccessors;
indexes: () => SplunkIndexesAccessor;
savedSearches: () => SplunkSavedSearchAccessor;
get: (splunkUrlPath: string, data: any) => SplunkRequestResponse;
post: (splunkUrlPath: string, data: any) => SplunkRequestResponse;
export interface Service {
configurations: (params: ApplicationNamespace) => Configurations;
apps: () => Collection<Entity>;
storagePasswords: () => StoragePasswords;
indexes: () => Indexes;
savedSearches: () => Collection<Entity>;
serverInfo: () => any;
get: (splunkUrlPath: string, data: any) => HTTPResponse;
post: (splunkUrlPath: string, data: any) => HTTPResponse;
}
98 changes: 39 additions & 59 deletions packages/react-components/src/utils/configurationFileHelper.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import {
ConfigurationFileAccessor,
ConfigurationsAccessor,
ConfigurationStanzaAccessor,
SplunkService,
} from '../models/splunk';
import { APPLICATION_NAMESPACE } from '../models/constants';
import { ConfigurationFile, Configurations, Entity, HTTPResponse, Service } from '../models/splunk';
import { promisify } from './util';

// ----------------------------------
Expand All @@ -13,10 +9,10 @@ import { promisify } from './util';
// Existence Functions
// ---------------------
function doesConfigurationExist(
configurationsAccessor: ConfigurationsAccessor,
configurations: Configurations,
configurationFilename: string
): boolean {
for (const stanza of configurationsAccessor.list()) {
for (const stanza of configurations.list()) {
if (stanza.name === configurationFilename) {
return true;
}
Expand All @@ -26,7 +22,7 @@ function doesConfigurationExist(
}

function doesStanzaExist(
configurationFileAccessor: ConfigurationFileAccessor,
configurationFileAccessor: ConfigurationFile,
stanzaName: string
): boolean {
for (const stanza of configurationFileAccessor.list()) {
Expand All @@ -42,62 +38,54 @@ function doesStanzaExist(
// Retrieval Functions
// ---------------------
function getConfigurationFile(
configurationsAccessor: ConfigurationsAccessor,
configurations: Configurations,
configurationFilename: string
): ConfigurationFileAccessor {
const configurationFileAccessor = configurationsAccessor.item(configurationFilename, {
// Name space information not provided
});

return configurationFileAccessor;
): Promise<ConfigurationFile> {
return promisify(configurations.item(configurationFilename, APPLICATION_NAMESPACE).fetch)();
}

function getConfigurationFileStanza(
configurationFileAccessor: ConfigurationFileAccessor,
configurationFile: ConfigurationFile,
configurationStanzaName: string
): ConfigurationStanzaAccessor {
const configurationStanzaAccessor = configurationFileAccessor.item(configurationStanzaName, {
// Name space information not provided
});

return configurationStanzaAccessor;
): Promise<Entity> {
return promisify(
configurationFile.item(configurationStanzaName, APPLICATION_NAMESPACE).fetch
)();
}

function createStanza(
configurationFileAccessor: ConfigurationFileAccessor,
configurationFile: ConfigurationFile,
newStanzaName: string
): Promise<void> {
return promisify(configurationFileAccessor.create)(newStanzaName);
): Promise<HTTPResponse> {
return promisify(configurationFile.create)(newStanzaName);
}

function updateStanzaProperties(
configurationStanzaAccessor: ConfigurationStanzaAccessor,
configurationStanza: Entity,
newStanzaProperties: Record<string, string>
): Promise<void> {
return promisify(configurationStanzaAccessor.update)(newStanzaProperties);
): Promise<HTTPResponse> {
return promisify(configurationStanza.update)(newStanzaProperties);
}

// ---------------------
// Process Helpers
// ---------------------

function createConfigurationFile(
configurationsAccessor: ConfigurationsAccessor,
configurations: Configurations,
configurationFilename: string
): Promise<void> {
return promisify(configurationsAccessor.create)(configurationFilename);
): Promise<HTTPResponse> {
return promisify(configurations.create)(configurationFilename);
}

export async function updateConfigurationFile(
service: SplunkService,
service: Service,
configurationFilename: string,
stanzaName: string,
properties: Record<string, string>
): Promise<void> {
// Fetch the accessor used to get a configuration file
let configurations = service.configurations({
// Name space information not provided
});
let configurations = service.configurations(APPLICATION_NAMESPACE);
configurations = await promisify(configurations.fetch)();

// Check for the existence of the configuration file
Expand All @@ -111,61 +99,53 @@ export async function updateConfigurationFile(
}

// Fetchs the configuration file accessor
let configurationFileAccessor = getConfigurationFile(configurations, configurationFilename);
configurationFileAccessor = await promisify(configurationFileAccessor.fetch)();
let configurationFile = await getConfigurationFile(configurations, configurationFilename);

// Checks to see if the stanza where the inputs will be
// stored exist
const stanzaExist = doesStanzaExist(configurationFileAccessor, stanzaName);
const stanzaExist = doesStanzaExist(configurationFile, stanzaName);

// If the configuration stanza doesn't exist, create it
if (!stanzaExist) {
await createStanza(configurationFileAccessor, stanzaName);
await createStanza(configurationFile, stanzaName);

// Need to update the information after the creation of the stanza
configurationFile = await promisify(configurationFile.fetch)();
}
// Need to update the information after the creation of the stanza
configurationFileAccessor = await promisify(configurationFileAccessor.fetch)();

// Fetchs the configuration stanza accessor
let configurationStanzaAccessor = getConfigurationFileStanza(
configurationFileAccessor,
stanzaName
);
configurationStanzaAccessor = await promisify(configurationStanzaAccessor.fetch)();
const configurationStanza = await getConfigurationFileStanza(configurationFile, stanzaName);

// We don't care if the stanza property does or doesn't exist
// This is because we can use the
// configurationStanza.update() function to create and
// change the information of a property
await updateStanzaProperties(configurationStanzaAccessor, properties);
await updateStanzaProperties(configurationStanza, properties);
}

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

// Fetchs the configuration file accessor
let configurationFileAccessor = getConfigurationFile(configurations, configurationFilename);
configurationFileAccessor = await promisify(configurationFileAccessor.fetch)();
const configurationFile = await getConfigurationFile(configurations, configurationFilename);

// Fetchs the configuration stanza accessor
let configurationStanzaAccessor = getConfigurationFileStanza(
configurationFileAccessor,
const configurationStanzaAccessor = await getConfigurationFileStanza(
configurationFile,
stanzaName
);
configurationStanzaAccessor = await promisify(configurationStanzaAccessor.fetch)();

let propertyValue = defaultValue;
if (propertyName in configurationStanzaAccessor._properties) {
propertyValue = configurationStanzaAccessor._properties[propertyName];
if (propertyName in configurationStanzaAccessor.properties()) {
propertyValue = configurationStanzaAccessor.properties()[propertyName];
}

return propertyValue;
Expand Down
Loading

0 comments on commit 4222186

Please sign in to comment.