Merge pull request #5998 from influxdata/feat/setup_v2_dbrp
feat: setup DBRP mapping automatically for a v2 connectionBNP_sign_artifacts
commit
3b181b1d9c
|
@ -14,6 +14,7 @@
|
|||
1. [#5959](https://github.com/influxdata/chronograf/pull/5959): Allow to customize annotation color.
|
||||
1. [#5967](https://github.com/influxdata/chronograf/pull/5967): Remember whether to start with shown annotations on Dashboard page.
|
||||
1. [#5977](https://github.com/influxdata/chronograf/pull/5977): Select current value in dropdown search input.
|
||||
1. [#5998](https://github.com/influxdata/chronograf/pull/5998): Setup DBRP mapping automatically for a v2 connection.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
@ -204,6 +204,7 @@ func NewMux(opts MuxOpts, service Service) http.Handler {
|
|||
// Source Proxy to Influx's flux endpoint; compression because the responses from
|
||||
// flux could be large.
|
||||
router.Handler("POST", "/chronograf/v1/sources/:id/proxy/flux", EnsureReader(service.ProxyFlux))
|
||||
router.Handler("GET", "/chronograf/v1/sources/:id/proxy/flux", EnsureReader(service.ProxyFlux))
|
||||
|
||||
// Write proxies line protocol write requests to InfluxDB
|
||||
router.POST("/chronograf/v1/sources/:id/write", EnsureViewer(service.Write))
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import {SOURCE_TYPE_INFLUX_V2} from 'src/shared/constants'
|
||||
import {Source} from 'src/types'
|
||||
import AJAX from 'src/utils/ajax'
|
||||
|
||||
export interface DBRP {
|
||||
id: string
|
||||
bucketID: string
|
||||
database: string
|
||||
retention_policy: string
|
||||
default: boolean
|
||||
}
|
||||
|
||||
async function getTelegrafBucketID(
|
||||
source: Source
|
||||
): Promise<string | undefined> {
|
||||
// try to get bucket of the same name
|
||||
const v2BucketsPath = `/api/v2/buckets?org=${encodeURIComponent(
|
||||
source.username
|
||||
)}&name=${encodeURIComponent(source.telegraf)}`
|
||||
try {
|
||||
const response = await AJAX({
|
||||
method: 'GET',
|
||||
url: `${source.links.flux}?version=${encodeURIComponent(
|
||||
source.version
|
||||
)}&path=${encodeURIComponent(v2BucketsPath)}`,
|
||||
data: '',
|
||||
})
|
||||
if (response.status !== 200) {
|
||||
return undefined
|
||||
}
|
||||
return response.data?.buckets?.[0]?.id
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
async function createDBRPMapping(
|
||||
source: Source,
|
||||
bucketID: string
|
||||
): Promise<DBRP | undefined> {
|
||||
// try to get bucket of the same name
|
||||
const body = {
|
||||
bucketID,
|
||||
database: source.telegraf,
|
||||
retention_policy: source.defaultRP || 'autogen',
|
||||
default: true,
|
||||
org: source.username,
|
||||
}
|
||||
try {
|
||||
const response = await AJAX({
|
||||
method: 'POST',
|
||||
url: `${source.links.flux}?version=${encodeURIComponent(
|
||||
source.version
|
||||
)}&path=/api/v2/dbrps`,
|
||||
data: body,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
})
|
||||
if (response.status === 201 && response.data.id) {
|
||||
return response.data as DBRP
|
||||
}
|
||||
console.warn('Cannot create v1 DBRP mapping', response.data)
|
||||
} catch (e) {
|
||||
console.warn('Cannot create v1 DBRP mapping', e)
|
||||
}
|
||||
}
|
||||
|
||||
export async function createDBRP(source: Source): Promise<DBRP | undefined> {
|
||||
if (
|
||||
!source.links?.flux ||
|
||||
source.type !== SOURCE_TYPE_INFLUX_V2 ||
|
||||
!source.telegraf
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const bucketID = await getTelegrafBucketID(source)
|
||||
if (!bucketID) {
|
||||
console.warn(
|
||||
`Cannot verify existence of ${source.telegraf} bucket, v1 DBRP mapping cannot be created`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// create DBRP mappings for bucket id
|
||||
return await createDBRPMapping(source, bucketID)
|
||||
}
|
|
@ -4,6 +4,8 @@ import _ from 'lodash'
|
|||
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||
// Types
|
||||
import {Source, Protoboard} from 'src/types'
|
||||
import {SOURCE_TYPE_INFLUX_V2} from 'src/shared/constants'
|
||||
import {createDBRP, DBRP} from './createDBRP'
|
||||
|
||||
interface SeriesObject {
|
||||
measurement: string
|
||||
|
@ -32,9 +34,10 @@ interface HostsSeries {
|
|||
|
||||
export const getSuggestedProtoboards = async (
|
||||
source: Source,
|
||||
protoboards: Protoboard[]
|
||||
protoboards: Protoboard[],
|
||||
afterCreatedDBRP: (dbrp: DBRP) => void = () => undefined
|
||||
): Promise<string[]> => {
|
||||
const hosts = await getHosts(source)
|
||||
const hosts = await getHosts(source, afterCreatedDBRP)
|
||||
|
||||
if (!hosts) {
|
||||
return []
|
||||
|
@ -94,16 +97,38 @@ export const addAppsToHosts = async (
|
|||
return newHosts
|
||||
}
|
||||
|
||||
export const getHosts = async (source: Source): Promise<Hosts> => {
|
||||
const getHosts = async (
|
||||
source: Source,
|
||||
afterCreatedDBRP: (dbrp: DBRP) => void
|
||||
): Promise<Hosts> => {
|
||||
const hosts = {}
|
||||
|
||||
const query = `SHOW TAG VALUES WITH KEY = "host" WHERE TIME > now() - 10m;`
|
||||
|
||||
const resp = await proxy({
|
||||
let resp = await proxy({
|
||||
source: source.links.proxy,
|
||||
query,
|
||||
db: source.telegraf,
|
||||
})
|
||||
const loadError = _.get(resp, ['data', 'results', '0', 'error'])
|
||||
if (loadError) {
|
||||
console.warn('Cannot suggest protoboards:', loadError)
|
||||
if (source.type === SOURCE_TYPE_INFLUX_V2) {
|
||||
// try to create DBRP mapping for ${source.telegraf} bucket
|
||||
const dbrp = await createDBRP(source)
|
||||
if (dbrp) {
|
||||
if (afterCreatedDBRP) {
|
||||
afterCreatedDBRP(dbrp)
|
||||
}
|
||||
// reload query
|
||||
resp = await proxy({
|
||||
source: source.links.proxy,
|
||||
query,
|
||||
db: source.telegraf,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allHostsSeries: HostsSeries[] = _.get(
|
||||
resp,
|
||||
|
|
|
@ -928,3 +928,13 @@ export const fluxWizardError = (message: string): Notification => ({
|
|||
duration: FIVE_SECONDS,
|
||||
message,
|
||||
})
|
||||
|
||||
export const notifyDBRPCreated = (
|
||||
bucket: string,
|
||||
db: string,
|
||||
rp: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
duration: TEN_SECONDS,
|
||||
message: `Default V1 DBRP mapping created. V2 bucket '${bucket}' is mapped to v1 database '${db}' with retention policy '${rp}'.`,
|
||||
})
|
||||
|
|
|
@ -27,11 +27,13 @@ import {notify as notifyAction} from 'src/shared/actions/notifications'
|
|||
import {
|
||||
notifyDashboardCreated,
|
||||
notifyDashboardCreationFailed,
|
||||
notifyDBRPCreated,
|
||||
} from 'src/shared/copy/notifications'
|
||||
|
||||
// Types
|
||||
import {Protoboard, Source, RemoteDataState} from 'src/types'
|
||||
import {NextReturn} from 'src/types/wizard'
|
||||
import {DBRP} from 'src/dashboards/utils/createDBRP'
|
||||
|
||||
interface SelectedDashboard {
|
||||
[x: string]: boolean
|
||||
|
@ -237,7 +239,7 @@ class DashboardStep extends Component<Props, State> {
|
|||
|
||||
private handleSuggest = async () => {
|
||||
const {protoboards} = this.state
|
||||
const {source} = this.props
|
||||
const {source, notify} = this.props
|
||||
|
||||
if (source) {
|
||||
if (this.isComponentMounted) {
|
||||
|
@ -247,7 +249,16 @@ class DashboardStep extends Component<Props, State> {
|
|||
try {
|
||||
const suggestedProtoboardsList = await getSuggestedProtoboards(
|
||||
source,
|
||||
protoboards
|
||||
protoboards,
|
||||
(dbrp: DBRP) => {
|
||||
notify(
|
||||
notifyDBRPCreated(
|
||||
source.telegraf,
|
||||
dbrp.database,
|
||||
dbrp.retention_policy
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (suggestedProtoboardsList.length === 0) {
|
||||
|
|
Loading…
Reference in New Issue