Skip to content

Commit

Permalink
fix(ui): resolved telegraf bucket dropdown bug and undefined token is…
Browse files Browse the repository at this point in the history
…sue (#17363)
  • Loading branch information
asalem1 authored Mar 20, 2020
1 parent b7e7de3 commit 42ad381
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 83 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
1. [17232](https://github.com/influxdata/influxdb/pull/17232): Allow dashboards to optionally be displayed in light mode
1. [17273](https://github.com/influxdata/influxdb/pull/17273): Add shell completions command for the influx cli
1. [17353](https://github.com/influxdata/influxdb/pull/17353): Make all pkg resources unique by metadata.name field
1. [17363](https://github.com/influxdata/influxdb/pull/17363): Telegraf config tokens can no longer be retrieved after creation, but new tokens can be created after a telegraf has been setup

### Bug Fixes

1. [17240](https://github.com/influxdata/influxdb/pull/17240): NodeJS logo displays properly in Firefox
1. [17363](https://github.com/influxdata/influxdb/pull/17363): Fixed telegraf configuration bugs where system buckets were appearing in the buckets dropdown

### UI Improvements

Expand Down
14 changes: 13 additions & 1 deletion ui/src/buckets/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
// Types
import {Bucket} from 'src/types'
import {AppState, Bucket, ResourceType} from 'src/types'

// Selectors
import {getAll} from 'src/resources/selectors'

export const SYSTEM = 'system'

export const getBucketByName = (
state: AppState,
bucketName: string
): Bucket => {
const buckets = getAll<Bucket>(state, ResourceType.Buckets)
const bucket = buckets.find(b => b.name === bucketName)
return bucket
}

export const isSystemBucket = (type: string): boolean => type === SYSTEM

const sortFunc = (a: Bucket, b: Bucket) => {
Expand Down
100 changes: 62 additions & 38 deletions ui/src/dataLoaders/actions/dataLoaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import {normalize} from 'normalizr'
import {client} from 'src/utils/api'
import {ScraperTargetRequest, PermissionResource} from '@influxdata/influx'
import {createAuthorization} from 'src/authorizations/apis'
import {postWrite as apiPostWrite, postLabel as apiPostLabel} from 'src/client'
import {postWrite as apiPostWrite} from 'src/client'

// Schemas
import {authSchema} from 'src/schemas'
import {telegrafSchema} from 'src/schemas/telegrafs'

// Utils
import {createNewPlugin} from 'src/dataLoaders/utils/pluginConfigs'
import {addLabelDefaults} from 'src/labels/utils'
import {getDataLoaders, getSteps} from 'src/dataLoaders/selectors'
import {getBucketByName} from 'src/buckets/selectors'
import {getByID} from 'src/resources/selectors'
import {getOrg} from 'src/organizations/selectors'

// Constants
Expand All @@ -37,13 +38,12 @@ import {
import {
GetState,
RemoteDataState,
LabelProperties,
Authorization,
AuthEntities,
ResourceType,
TelegrafEntities,
Telegraf,
} from 'src/types'
import {ILabel} from '@influxdata/influx'
import {
WritePrecision,
TelegrafRequest,
Expand All @@ -57,9 +57,10 @@ import {addTelegraf, editTelegraf} from 'src/telegrafs/actions/creators'
import {addAuthorization} from 'src/authorizations/actions/creators'
import {notify} from 'src/shared/actions/notifications'
import {
readWriteCardinalityLimitReached,
TelegrafConfigCreationError,
TelegrafConfigCreationSuccess,
readWriteCardinalityLimitReached,
TokenCreationError,
} from 'src/shared/copy/notifications'

const DEFAULT_COLLECTION_INTERVAL = 10000
Expand Down Expand Up @@ -401,6 +402,61 @@ export const createOrUpdateTelegrafConfigAsync = () => async (
createTelegraf(dispatch, getState, plugins)
}

export const generateTelegrafToken = (configID: string) => async (
dispatch,
getState: GetState
) => {
try {
const state = getState()
const orgID = getOrg(state).id
const telegraf = getByID<Telegraf>(state, ResourceType.Telegrafs, configID)
const bucketName = get(telegraf, 'metadata.buckets[0]', '')
if (bucketName === '') {
throw new Error(
'A token cannot be generated without a corresponding bucket'
)
}
const bucket = getBucketByName(state, bucketName)

const permissions = [
{
action: Permission.ActionEnum.Write,
resource: {
type: PermissionResource.TypeEnum.Buckets,
id: bucket.id,
orgID,
},
},
{
action: Permission.ActionEnum.Read,
resource: {
type: PermissionResource.TypeEnum.Telegrafs,
id: configID,
orgID,
},
},
]

const token = {
name: `${telegraf.name} token`,
orgID,
description: `WRITE ${bucketName} bucket / READ ${
telegraf.name
} telegraf config`,
permissions,
}

// create token
const createdToken = await createAuthorization(token)

// add token to data loader state
dispatch(setToken(createdToken.token))
} catch (error) {
console.error(error)
dispatch(notify(TokenCreationError))
}
}

const createTelegraf = async (dispatch, getState: GetState, plugins) => {
try {
const state = getState()
Expand Down Expand Up @@ -461,40 +517,8 @@ const createTelegraf = async (dispatch, getState: GetState, plugins) => {
// add token to authorizations state
dispatch(addAuthorization(normAuth))

// create token label
const properties = {
color: '#FFFFFF',
description: `token for telegraf config: ${telegrafConfigName}`,
tokenID: createdToken.id,
} as LabelProperties // hack to make compiler work

const resp = await apiPostLabel({
data: {
orgID: org.id,
name: `@influxdata.token-${new Date().getTime()}`, // fix for https://github.com/influxdata/influxdb/issues/15730
properties,
},
})

if (resp.status !== 201) {
throw new Error(resp.data.message)
}

const createdLabel = addLabelDefaults(resp.data.label)

// add label to telegraf config
const label = await client.telegrafConfigs.addLabel(
tc.id,
createdLabel as ILabel
)

const config = {
...tc,
labels: [label],
}

const normTelegraf = normalize<Telegraf, TelegrafEntities, string>(
config,
tc,
telegrafSchema
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ import {AppState, Bucket, Organization, ResourceType} from 'src/types'
// Selectors
import {getAll} from 'src/resources/selectors'
import {getOrg} from 'src/organizations/selectors'
import {isSystemBucket} from 'src/buckets/selectors'

// Utils
import {isSystemBucket} from 'src/buckets/constants'

export interface CollectorsStepProps {
currentStepIndex: number
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// Libraries
import React, {PureComponent} from 'react'
import {Alert, ComponentColor, IconFont} from '@influxdata/clockface'
import _ from 'lodash'

// Decorator
import {ErrorHandling} from 'src/shared/decorators/errors'

// Components
import CodeSnippet from 'src/shared/components/CodeSnippet'
import TokenCodeSnippet from 'src/shared/components/TokenCodeSnippet'

export interface Props {
token: string
Expand All @@ -17,7 +19,6 @@ export interface Props {
class TelegrafInstructions extends PureComponent<Props> {
public render() {
const {token, configID} = this.props
const exportToken = `export INFLUX_TOKEN=${token || ''}`
const configScript = `telegraf --config ${
this.origin
}/api/v2/telegrafs/${configID || ''}`
Expand All @@ -42,7 +43,13 @@ class TelegrafInstructions extends PureComponent<Props> {
copy the following command to your terminal window to set an
environment variable with your token.
</p>
<CodeSnippet copyText={exportToken} label="CLI" />
{token && (
<Alert icon={IconFont.AlertTriangle} color={ComponentColor.Primary}>
Make sure to copy your new personal access token now. You won’t be
able to see it again!
</Alert>
)}
<TokenCodeSnippet token={token} configID={configID} label="CLI" />
<h6>3. Start Telegraf</h6>
<p>
Finally, you can run the following command to start the Telegraf agent
Expand Down
3 changes: 3 additions & 0 deletions ui/src/resources/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export const getAll = <R>(
return allIDs.map(id => byID[id])
}

export const getToken = (state: AppState): string =>
get(state, 'dataLoading.dataLoaders.token', '') || ''

export const getByID = <R>(
{resources}: AppState,
type: ResourceType,
Expand Down
4 changes: 4 additions & 0 deletions ui/src/shared/components/CodeSnippet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
}
}

.new-token--btn {
margin: $ix-marg-a $ix-marg-c;
}

.code-snippet--footer {
background-color: rgba($g4-onyx, 0.5);
display: flex;
Expand Down
92 changes: 92 additions & 0 deletions ui/src/shared/components/TokenCodeSnippet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Libraries
import React, {FC} from 'react'
import {connect} from 'react-redux'
import {
Button,
ComponentColor,
ComponentSize,
ComponentStatus,
IconFont,
} from '@influxdata/clockface'

// Decorator
import {Notification} from 'src/types'

// Components
import FancyScrollbar from 'src/shared/components/fancy_scrollbar/FancyScrollbar'
import CopyButton from 'src/shared/components/CopyButton'

// Actions
import {generateTelegrafToken} from 'src/dataLoaders/actions/dataLoaders'

export interface Props {
configID: string
token: string
onCopyText?: (text: string, status: boolean) => Notification
testID?: string
label: string
}

interface DispatchProps {
onGenerateTelegrafToken: typeof generateTelegrafToken
}

const TokenCodeSnippet: FC<Props & DispatchProps> = ({
token,
onCopyText,
testID,
label = 'Code Snippet',
}) => {
const handleRefreshClick = () => {
const {configID, onGenerateTelegrafToken} = this.props
onGenerateTelegrafToken(configID)
}

return (
<div className="code-snippet" data-testid={testID}>
<FancyScrollbar
autoHide={false}
autoHeight={true}
maxHeight={400}
className="code-snippet--scroll"
>
<div className="code-snippet--text">
<pre>
export INFLUX_TOKEN=<i>{token || '<INFLUX_TOKEN>'}</i>
</pre>
</div>
</FancyScrollbar>
<div className="code-snippet--footer">
<div>
<CopyButton
textToCopy={token}
onCopyText={onCopyText}
contentName="Script"
/>
<Button
size={ComponentSize.ExtraSmall}
status={
token === '' ? ComponentStatus.Default : ComponentStatus.Disabled
}
text="Generate New Token"
titleText="Generate New Token"
icon={IconFont.Refresh}
color={ComponentColor.Success}
onClick={handleRefreshClick}
className="new-token--btn"
/>
</div>
<label className="code-snippet--label">{label}</label>
</div>
</div>
)
}

const mdtp: DispatchProps = {
onGenerateTelegrafToken: generateTelegrafToken,
}

export default connect<{}, DispatchProps>(
null,
mdtp
)(TokenCodeSnippet)
5 changes: 5 additions & 0 deletions ui/src/shared/copy/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ export const TelegrafConfigCreationError: Notification = {
message: `Failed to save configurations`,
}

export const TokenCreationError: Notification = {
...defaultErrorNotification,
message: `Failed to create a new Telegraf Token`,
}

// Task Notifications
// ----------------------------------------------------------------------------
export const addTaskLabelFailed = (): Notification => ({
Expand Down
Loading

0 comments on commit 42ad381

Please sign in to comment.