Reading config/env variable inside kibana plugin

Hello Community.
I have been trying for a while to read env variable inside kibana plugin JS code. I have the elk stack running as containers and want to provide environment variables via docker or configmap via kubernetes.
Approach: If i try to read a file then it won't read from the current directory since it's client side code. I can potentially PUT these config params on elasticsearch and read them from there but i don't want to do that. I want them to be either attached to the container as a mount or environment variable.
So, if anyone has already done this and found a solution to import env then please share your experience. It'll be a great help.

Thanks.

Hi, to get the value into the front-end code, you can use server.injectUiAppVars for this.

Here's an example of Timelion doing so to get ES client info into the UI: https://github.com/elastic/kibana/blob/3427a08108ee20fb0a37d4db1daa3ae478654305/src/legacy/core_plugins/timelion/init.js#L55

Thanks for the response Tim. I am a novice at this thing so do bare with me.
So, in order to use env bound to my container i will have to return somevar: config.get('MYCONTAINERVAR') in index.js. Is there a syntax to use this variable inside hack.js in public directory of the plugin? Something like process.env.somevar or $somevar.

Hi, the code in the public directory will not be able to read any environment variable directly. The environment variable will have to be captured on the server side, in your plugin init, to get it registered as an injected UI App Var, the way I showed you.

I put together a quick example plugin to demonstrate server.injectUiAppVars

index.js: call server.injectUiAppVars from init

export default function (kibana) {
  return new kibana.Plugin({
    require: ['elasticsearch'],
    name: 'myplugin',
    uiExports: {
      app: {
        title: 'MyPlugin',
        main: 'plugins/myplugin/app',
      },
    },
    config(Joi) {
      return Joi.object({
        enabled: Joi.boolean().default(true),
      }).default();
    },
    init(server) {
      server.injectUiAppVars('myplugin', () => {
        const config = server.config();
        return {
          environmentValue: 42 // TODO replace with `process.env['SOMETHING']
        };
      });
    },
  });
}

public/services/vars.js: make an Angular service that returns the server-side value:

import { uiModules } from 'ui/modules';
const module = uiModules.get('app/myplugin');
// This is for injecting into controllers
module.service('environmentService', function (environmentValue) {
  return {
    get: () => environmentValue,
  };
});

public/app.js, pass the service to a React component:

import React from 'react';
import { uiModules } from 'ui/modules';
import chrome from 'ui/chrome';
import { render, unmountComponentAtNode } from 'react-dom';
import 'ui/autoload/styles';
import './less/main.less';
import { Main } from './components/main';
import './services/vars';
const app = uiModules.get('apps/myplugin');
app.config($locationProvider => {
  $locationProvider.html5Mode({
    enabled: false,
    requireBase: false,
    rewriteLinks: false,
  });
});
app.config(stateManagementConfigProvider => stateManagementConfigProvider.disable());
function RootController($scope, $element, $http, environmentService) {
  const domNode = $element[0];
  // render react to DOM
  render(
    <Main
      title="My Plugin"
      httpClient={$http}
      environmentService={environmentService}
    />,
    domNode
  );
  // unmount react on controller destroy
  $scope.$on('$destroy', () => {
    unmountComponentAtNode(domNode);
  });
}
chrome.setRootController('myplugin', RootController);

public/components/main/main.js, use the service:

import React from 'react';
import {
  EuiPage,
  EuiPageBody,
  EuiPageContent,
  EuiPageContentBody,
  EuiText,
} from '@elastic/eui';
export class Main extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <EuiPage>
        <EuiPageBody>
          <EuiPageContent>
            <EuiPageContentBody>
              <EuiText>
                <h3>You have successfully!</h3>
                <p>
                  The environmentValue is {this.props.environmentService.get()}
                </p>
              </EuiText>
            </EuiPageContentBody>
          </EuiPageContent>
        </EuiPageBody>
      </EuiPage>
    );
  }
}
1 Like

Thanks a lot for clarification. Your plugin works if i use a static value in it(just like you did with environmentValue: 42). Although, when i use environmentValue: process.env['HOSTNAME'] it doesn't return anything. The logged error on the browser is
Error: [$injector:unpr] Unknown provider: environmentValueProvider <- environmentValue <- environmentService
HOSTNAME in this case is the environment variable attached to the kibana docker image.

Thank you so much for all the help. If you can suggest a sequential guide to follow into kibana plugin development then that'll be a huge help. The documentation on elastic.co is not substantial enough.

I'd try using some console.log statements and look at what gets logged in the Kibana server logs to see what values you'll be able to read.

The injected vars are serialized so they can be included in the browser page load. If the value for the object property is undefined, then the property doesn't exist after it is serialized.

It worked!!! Thank you so much for your help. The env i declared earlier were out of scope for my plugin so declared them as root and it worked fine then. Although, can you suggest the changes in your code to make it adaptive to version 6.2.4. I believe server.injectVars() was a part of uiExports before but for the life of me i can't make it behave the right way.
In the app.js can we console.log(environmentValue) from environmentService.
Thank you so much for all your help once again.

You're right: in 6.2.x, injectVars were part of uiExport.app. The Kibana Platform team removed that touchpoint in prep for the 8.x Kibana framework, which won't have uiExports.

To check on that, I'll again direct you to the Timelion code, this time going back to our 6.2 branch: https://github.com/elastic/kibana/blob/6.2/src/core_plugins/timelion/index.js#L11

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.