Skip to content
This repository has been archived by the owner on Feb 14, 2023. It is now read-only.

Using the Rails console to debug the cf api server

Tim Downey edited this page Jan 27, 2021 · 3 revisions

Sometimes it can be handy to start up an interactive REPL for debugging the current state of the Cloud Controller API. You can do this in cf-for-k8s with kubectl exec.

Start a shell

First we start an interactive shell with the /cnb/lifecycle/launcher to load required env vars and PATH

kubectl exec -it -n cf-system cf-api-server-5f454f986b-4gdbx -c cf-api-server -- /cnb/lifecycle/launcher /bin/bash

Start the console

/workspace/bin/console /config/cloud_controller_ng.yml

What can I do with this?

Now you can execute Ruby / Cloud Controller code with full access to the rest of the system. E.g.

Interacting with the Database

You can load various records from the database to observe and interact with them.

cnb@cf-api-server-5f454f986b-4gdbx:/workspace$ /workspace/bin/console /config/cloud_controller_ng.yml



From: /workspace/lib/cloud_controller/console.rb:53 :

    48:
    49: module VCAP::CloudController
    50:   # rubocop:disable Lint/Debugger
    51:   binding.pry quiet: true
    52:   # rubocop:enable Lint/Debugger
 => 53: end

[1] pry(VCAP::CloudController)> Domain.first
=> #<VCAP::CloudController::SharedDomain @values={:id=>1, :guid=>"a92e85d7-487c-4854-a21a-72e14f17eee2", :created_at=>2021-01-27 18:27:38 UTC, :updated_at=>2021-01-27 18:27:38 UTC, :name=>"apps.tim.k8s.capi.land", :wildcard=>true, :owning_organization_id=>nil, :router_group_guid=>nil, :internal=>false}>

[2] pry(VCAP::CloudController)> Route.first
=> #<VCAP::CloudController::Route @values={:id=>1, :guid=>"a38c12cb-65ef-4fef-b531-031ea1261668", :created_at=>2021-01-27 18:41:39 UTC, :updated_at=>2021-01-27 18:41:39 UTC, :host=>"catnip", :domain_id=>1, :space_id=>1, :path=>"", :port=>0, :vip_offset=>nil}>

Interacting with other Services

You can instantiate client instances to interact with other services like UAA, Eirini, and the Kubernetes API.

Here's an example of fetching a Route from the K8s API:

CloudController::DependencyLocator.instance.k8s_api_client.get_route(Route.first.guid, 'cf-workloads')

=> #<Kubeclient::Resource apiVersion="networking.cloudfoundry.org/v1alpha1", kind="Route", metadata={:creationTimestamp=>"2021-01-27T18:41:39Z", :finalizers=>["routes.networking.cloudfoundry.org"], :generation=>3, :labels=>{:"app.kubernetes.io/component"=>"cf-networking", :"app.kubernetes.io/managed-by"=>"cloudfoundry", :"app.kubernetes.io/name"=>"a38c12cb-65ef-4fef-b531-031ea1261668", :"app.kubernetes.io/part-of"=>"cloudfoundry", :"app.kubernetes.io/version"=>"0.0.0", :"cloudfoundry.org/domain_guid"=>"a92e85d7-487c-4854-a21a-72e14f17eee2", :"cloudfoundry.org/org_guid"=>"0a64ea09-7780-4ee2-a281-53d501ed6faa", :"cloudfoundry.org/route_guid"=>"a38c12cb-65ef-4fef-b531-031ea1261668", :"cloudfoundry.org/space_guid"=>"2471d6b6-6996-4db6-b1b9-356823513b38"}, :name=>"a38c12cb-65ef-4fef-b531-031ea1261668", :namespace=>"cf-workloads", :resourceVersion=>"11542", :selfLink=>"/apis/networking.cloudfoundry.org/v1alpha1/namespaces/cf-workloads/routes/a38c12cb-65ef-4fef-b531-031ea1261668", :uid=>"70176633-b6d2-47c5-8a16-2c559933e419"}, spec={:destinations=>[{:app=>{:guid=>"4a9361e0-5996-4116-9c7b-fb7b8eb6cca0", :process=>{:type=>"web"}}, :guid=>"08bbc361-e171-427b-a69a-be1a5ecc0c92", :port=>8080, :selector=>{:matchLabels=>{:"cloudfoundry.org/app_guid"=>"4a9361e0-5996-4116-9c7b-fb7b8eb6cca0", :"cloudfoundry.org/process_type"=>"web"}}}], :domain=>{:internal=>false, :name=>"apps.tim.k8s.capi.land"}, :host=>"catnip", :url=>"catnip.apps.tim.k8s.capi.land"}>

Misc Tips

You can quickly see what methods are available on an object with the following technique:

CloudController::DependencyLocator.instance.k8s_api_client.methods - Object.methods
=> [:get_image,
 :update_image,
 :delete_image,
 :create_route,
 :get_route,
 :update_route,
 :delete_route,
 :update_builder,
 :create_builder,
 :delete_builder,
 :get_builder,
 :create_image]

This essentially subtracts all the methods from the base Object Class leaving you with a list of the ones (mostly) unique to your Class.

To view more information about a particular method you can use the pry command show-method. For example:

show-method CloudController::DependencyLocator.instance.k8s_api_client.get_route

From: /workspace/lib/kubernetes/api_client.rb:58:
Owner: Kubernetes::ApiClient
Visibility: public
Signature: get_route(name, namespace)
Number of lines: 10

def get_route(name, namespace)
  @route_kube_client.get_route(name, namespace)
rescue Kubeclient::ResourceNotFoundError
  nil
rescue Kubeclient::HttpError => e
  logger.error('get_route', error: e.inspect, response: e.response, backtrace: e.backtrace)
  error = CloudController::Errors::ApiError.new_from_details('KubernetesRouteResourceError', name)
  error.set_backtrace(e.backtrace)
  raise error
end

There's a lot you can do with pry such as setting break points, stepping into and out of functions, viewing docs, and more which you can discover by reading pry cheat sheets and tutorials.