godaddy/kubernetes-client

Use within Google Cloud Functions

Open

#262 opened on May 7, 2018

View on GitHub
 (12 comments) (18 reactions) (0 assignees)JavaScript (954 stars) (206 forks)batch import
help wanted

Description

I wanted to kick off a job in my GKE cluster from a Google Cloud Function reacting to changes in Cloud Storage. Since there's no .kube/config it wasn't clear to me how to do that with the new fromKubeConfig initialization. I got it working by piecing together a config object from data retrieved by google-auth-library and @google-cloud/container clients. I'll leave it here to both ask if this way makes sense and to serve as an example for others trying to do something similar.

const {auth} = require('google-auth-library');
const container = require('@google-cloud/container');
const job = require('./job.json');
const kube = require('kubernetes-client');

const clusterClient = new container.v1.ClusterManagerClient();
const request = {
  projectId: process.env.GCLOUD_PROJECT,
  zone: 'us-east4-b',
  clusterId: 'cluster-2',
};

function getCluster() {
  return clusterClient.getCluster(request)
    .then(results => {
      return results[0];
    });
}

function getToken() {
  return auth.getClient()
    .then(client => {
      return client.getAccessToken();
    })
    .then(tokenResponse => {
      return tokenResponse.token;
    });
}

// kubeClient is a lazy global used for caching.
// https://cloud.google.com/functions/docs/bestpractices/tips#use_global_variables_to_reuse_objects_in_future_invocations
let kubeClient;

function getKubeClient(cluster, token) {
  kubeClient = new kube.Client({config: kube.config.fromKubeconfig({
    apiVersion: 'v1',
    kind: 'Config',
    preferences: {},
    'current-context': 'a',
    contexts: [
      {
        name: 'a',
        context: {
          cluster: 'a',
          user: 'a'
        }
      }
    ],
    clusters: [
      {
        name: 'a',
        cluster: {
          'certificate-authority-data': cluster.masterAuth.clusterCaCertificate,
          server: `https://${cluster.endpoint}`
        }
      }
    ],
    users: [
      {
        name: 'a',
        user: {
          'auth-provider': {
            config: {
              'access-token': token,
              'cmd-args': 'config config-helper --format=json',
              'cmd-path': '/google/google-cloud-sdk/bin/gcloud',
              'token-key': '{.credential.access_token}'
            },
            name: 'gcp'
          }
        }
      }
    ]
  })});
  return kubeClient.loadSpec();
}

exports.updateJob = (event) => {
  return (kubeClient && Promise.resolve(kubeClient) ||
    Promise.all([getCluster(), getToken()]).then(([cluster, token]) => {
      return getKubeClient(cluster, token);
    }))
    .then(kubeClient => {
      // Strip extension from filename to get job name
      const name = event.data.name.replace(/\.[^/.]+$/, "");
      job.metadata.generateName = `${name}-update-`;
      job.spec.template.spec.volumes[0].configMap.name = name;
      return kubeClient.apis.batch.v1.namespaces('default').jobs.post({body: job});
    })
    .then(res => {
      console.log('Job created:', res.body.metadata.name);
    });
};

Contributor guide

Use within Google Cloud Functions · godaddy/kubernetes-client#262 | Good First Issue