kubernetes_helpers.rb 11.8 KB
Newer Older
1 2 3
module KubernetesHelpers
  include Gitlab::Kubernetes

4 5 6 7 8 9 10 11
  def kube_response(body)
    { body: body.to_json }
  end

  def kube_pods_response
    kube_response(kube_pods_body)
  end

12 13 14 15
  def kube_deployments_response
    kube_response(kube_deployments_body)
  end

16 17
  def stub_kubeclient_discover(api_url)
    WebMock.stub_request(:get, api_url + '/api/v1').to_return(kube_response(kube_v1_discovery_body))
18
    WebMock.stub_request(:get, api_url + '/apis/extensions/v1beta1').to_return(kube_response(kube_v1beta1_discovery_body))
19
    WebMock.stub_request(:get, api_url + '/apis/rbac.authorization.k8s.io/v1').to_return(kube_response(kube_v1_rbac_authorization_discovery_body))
20
    WebMock.stub_request(:get, api_url + '/apis/serving.knative.dev/v1alpha1').to_return(kube_response(kube_v1alpha1_serving_knative_discovery_body))
21 22 23
  end

  def stub_kubeclient_pods(response = nil)
24
    stub_kubeclient_discover(service.api_url)
25 26 27 28 29
    pods_url = service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods"

    WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response)
  end

30 31 32 33 34 35 36
  def stub_kubeclient_deployments(response = nil)
    stub_kubeclient_discover(service.api_url)
    deployments_url = service.api_url + "/apis/extensions/v1beta1/namespaces/#{service.actual_namespace}/deployments"

    WebMock.stub_request(:get, deployments_url).to_return(response || kube_deployments_response)
  end

37 38 39 40 41 42 43 44 45 46 47
  def stub_kubeclient_knative_services(**options)
    options[:name] ||= "kubetest"
    options[:namespace] ||= "default"
    options[:domain] ||= "example.com"

    stub_kubeclient_discover(service.api_url)
    knative_url = service.api_url + "/apis/serving.knative.dev/v1alpha1/services"

    WebMock.stub_request(:get, knative_url).to_return(kube_response(kube_knative_services_body(options)))
  end

48
  def stub_kubeclient_get_secret(api_url, **options)
49
    options[:metadata_name] ||= "default-token-1"
50
    options[:namespace] ||= "default"
51

52
    WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{options[:namespace]}/secrets/#{options[:metadata_name]}")
53
      .to_return(kube_response(kube_v1_secret_body(options)))
54 55
  end

56
  def stub_kubeclient_get_secret_error(api_url, name, namespace: 'default', status: 404)
57
    WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/secrets/#{name}")
58
      .to_return(status: [status, "Internal Server Error"])
59 60
  end

61 62 63 64 65
  def stub_kubeclient_get_service_account(api_url, name, namespace: 'default')
    WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts/#{name}")
      .to_return(kube_response({}))
  end

66 67 68 69 70
  def stub_kubeclient_get_service_account_error(api_url, name, namespace: 'default', status: 404)
    WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts/#{name}")
      .to_return(status: [status, "Internal Server Error"])
  end

71 72 73 74 75
  def stub_kubeclient_create_service_account(api_url, namespace: 'default')
    WebMock.stub_request(:post, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts")
      .to_return(kube_response({}))
  end

76 77 78 79 80
  def stub_kubeclient_create_service_account_error(api_url, namespace: 'default')
    WebMock.stub_request(:post, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts")
      .to_return(status: [500, "Internal Server Error"])
  end

81 82 83 84 85
  def stub_kubeclient_put_service_account(api_url, name, namespace: 'default')
    WebMock.stub_request(:put, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts/#{name}")
      .to_return(kube_response({}))
  end

86 87 88 89 90
  def stub_kubeclient_create_secret(api_url, namespace: 'default')
    WebMock.stub_request(:post, api_url + "/api/v1/namespaces/#{namespace}/secrets")
      .to_return(kube_response({}))
  end

91 92 93 94 95 96 97 98 99 100
  def stub_kubeclient_put_secret(api_url, name, namespace: 'default')
    WebMock.stub_request(:put, api_url + "/api/v1/namespaces/#{namespace}/secrets/#{name}")
      .to_return(kube_response({}))
  end

  def stub_kubeclient_get_cluster_role_binding_error(api_url, name, status: 404)
    WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/#{name}")
      .to_return(status: [status, "Internal Server Error"])
  end

101 102 103 104 105
  def stub_kubeclient_create_cluster_role_binding(api_url)
    WebMock.stub_request(:post, api_url + '/apis/rbac.authorization.k8s.io/v1/clusterrolebindings')
      .to_return(kube_response({}))
  end

106 107 108 109 110
  def stub_kubeclient_get_role_binding(api_url, name, namespace: 'default')
    WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
      .to_return(kube_response({}))
  end

111 112 113 114 115
  def stub_kubeclient_get_role_binding_error(api_url, name, namespace: 'default', status: 404)
    WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
      .to_return(status: [status, "Internal Server Error"])
  end

116 117 118 119 120
  def stub_kubeclient_create_role_binding(api_url, namespace: 'default')
    WebMock.stub_request(:post, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings")
      .to_return(kube_response({}))
  end

121 122 123 124 125
  def stub_kubeclient_put_role_binding(api_url, name, namespace: 'default')
    WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
      .to_return(kube_response({}))
  end

126 127 128 129 130 131 132 133 134 135
  def stub_kubeclient_create_namespace(api_url)
    WebMock.stub_request(:post, api_url + "/api/v1/namespaces")
      .to_return(kube_response({}))
  end

  def stub_kubeclient_get_namespace(api_url, namespace: 'default')
    WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}")
      .to_return(kube_response({}))
  end

136
  def kube_v1_secret_body(**options)
137 138 139
    {
      "kind" => "SecretList",
      "apiVersion": "v1",
140 141 142 143 144 145 146
      "metadata": {
        "name": options[:metadata_name] || "default-token-1",
        "namespace": "kube-system"
      },
      "data": {
        "token": options[:token] || Base64.encode64('token-sample-123')
      }
147 148 149
    }
  end

150
  def kube_v1_discovery_body
151 152
    {
      "kind" => "APIResourceList",
153
      "resources" => [
154
        { "name" => "pods", "namespaced" => true, "kind" => "Pod" },
155
        { "name" => "deployments", "namespaced" => true, "kind" => "Deployment" },
156
        { "name" => "secrets", "namespaced" => true, "kind" => "Secret" },
157
        { "name" => "serviceaccounts", "namespaced" => true, "kind" => "ServiceAccount" },
158 159
        { "name" => "services", "namespaced" => true, "kind" => "Service" },
        { "name" => "namespaces", "namespaced" => true, "kind" => "Namespace" }
160 161 162 163 164 165 166 167 168 169
      ]
    }
  end

  def kube_v1beta1_discovery_body
    {
      "kind" => "APIResourceList",
      "resources" => [
        { "name" => "pods", "namespaced" => true, "kind" => "Pod" },
        { "name" => "deployments", "namespaced" => true, "kind" => "Deployment" },
170
        { "name" => "secrets", "namespaced" => true, "kind" => "Secret" },
171
        { "name" => "serviceaccounts", "namespaced" => true, "kind" => "ServiceAccount" },
172 173 174 175 176 177 178 179 180 181 182 183 184
        { "name" => "services", "namespaced" => true, "kind" => "Service" }
      ]
    }
  end

  def kube_v1_rbac_authorization_discovery_body
    {
      "kind" => "APIResourceList",
      "resources" => [
        { "name" => "clusterrolebindings", "namespaced" => false, "kind" => "ClusterRoleBinding" },
        { "name" => "clusterroles", "namespaced" => false, "kind" => "ClusterRole" },
        { "name" => "rolebindings", "namespaced" => true, "kind" => "RoleBinding" },
        { "name" => "roles", "namespaced" => true, "kind" => "Role" }
185
      ]
186 187 188
    }
  end

189 190 191 192 193 194 195 196 197 198 199 200
  def kube_v1alpha1_serving_knative_discovery_body
    {
      "kind" => "APIResourceList",
      "resources" => [
        { "name" => "revisions", "namespaced" => true, "kind" => "Revision" },
        { "name" => "services", "namespaced" => true, "kind" => "Service" },
        { "name" => "configurations", "namespaced" => true, "kind" => "Configuration" },
        { "name" => "routes", "namespaced" => true, "kind" => "Route" }
      ]
    }
  end

201 202 203 204 205
  def kube_pods_body
    {
      "kind" => "PodList",
      "items" => [kube_pod]
    }
206 207
  end

208 209 210 211 212 213 214
  def kube_deployments_body
    {
      "kind" => "DeploymentList",
      "items" => [kube_deployment]
    }
  end

215 216 217 218 219 220 221
  def kube_knative_services_body(**options)
    {
      "kind" => "List",
      "items" => [kube_service(options)]
    }
  end

222 223
  # This is a partial response, it will have many more elements in reality but
  # these are the ones we care about at the moment
224
  def kube_pod(name: "kube-pod", app: "valid-pod-label", status: "Running", track: nil)
225 226
    {
      "metadata" => {
227
        "name" => name,
228
        "generate_name" => "generated-name-with-suffix",
229
        "creationTimestamp" => "2016-11-25T19:55:19Z",
230 231 232 233
        "labels" => {
          "app" => app,
          "track" => track
        }
234 235 236 237
      },
      "spec" => {
        "containers" => [
          { "name" => "container-0" },
238 239
          { "name" => "container-1" }
        ]
240
      },
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
      "status" => { "phase" => status }
    }
  end

  def kube_deployment(name: "kube-deployment", app: "valid-deployment-label", track: nil)
    {
      "metadata" => {
        "name" => name,
        "generation" => 4,
        "labels" => {
          "app" => app,
          "track" => track
        }.compact
      },
      "spec" => { "replicas" => 3 },
      "status" => {
        "observedGeneration" => 4,
        "replicas" => 3,
        "updatedReplicas" => 3,
        "availableReplicas" => 3
      }
262 263 264
    }
  end

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
  def kube_service(name: "kubetest", namespace: "default", domain: "example.com")
    {
      "metadata" => {
          "creationTimestamp" => "2018-11-21T06:16:33Z",
          "name" => name,
          "namespace" => namespace,
          "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}"
      },
      "spec" => {
        "generation" => 2
      },
      "status" => {
        "domain" => "#{name}.#{namespace}.#{domain}",
        "domainInternal" => "#{name}.#{namespace}.svc.cluster.local",
        "latestCreatedRevisionName" => "#{name}-00002",
        "latestReadyRevisionName" => "#{name}-00002",
        "observedGeneration" => 2
      }
    }
  end

  def kube_service_full(name: "kubetest", namespace: "kube-ns", domain: "example.com")
    {
      "metadata" => {
        "creationTimestamp" => "2018-11-21T06:16:33Z",
        "name" => name,
        "namespace" => namespace,
        "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}",
        "annotation" => {
          "description" => "This is a test description"
        }
      },
      "spec" => {
        "generation" => 2,
        "build" => {
          "template" => "go-1.10.3"
        }
      },
      "status" => {
        "domain" => "#{name}.#{namespace}.#{domain}",
        "domainInternal" => "#{name}.#{namespace}.svc.cluster.local",
        "latestCreatedRevisionName" => "#{name}-00002",
        "latestReadyRevisionName" => "#{name}-00002",
        "observedGeneration" => 2
      }
    }
  end

313 314 315 316 317 318 319
  def kube_terminals(service, pod)
    pod_name = pod['metadata']['name']
    containers = pod['spec']['containers']

    containers.map do |container|
      terminal = {
        selectors: { pod: pod_name, container: container['name'] },
320
        url:  container_exec_url(service.api_url, service.actual_namespace, pod_name, container['name']),
321 322
        subprotocols: ['channel.k8s.io'],
        headers: { 'Authorization' => ["Bearer #{service.token}"] },
323 324
        created_at: DateTime.parse(pod['metadata']['creationTimestamp']),
        max_session_time: 0
325 326 327 328 329
      }
      terminal[:ca_pem] = service.ca_pem if service.ca_pem.present?
      terminal
    end
  end
330 331 332 333 334 335 336 337

  def kube_deployment_rollout_status
    ::Gitlab::Kubernetes::RolloutStatus.from_deployments(kube_deployment)
  end

  def empty_deployment_rollout_status
    ::Gitlab::Kubernetes::RolloutStatus.from_deployments()
  end
338
end