Skip to content

Commit

Permalink
Add Pod follow logs and status API
Browse files Browse the repository at this point in the history
  • Loading branch information
iabudiab committed Nov 26, 2020
1 parent a82e20d commit 4a0a394
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 23 deletions.
42 changes: 36 additions & 6 deletions Sources/SwiftkubeClient/Client/GenericKubernetesClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,14 @@ public class GenericKubernetesClient<Resource: KubernetesAPIResource> {
}
}

private func makeRequest() -> RequestBuilder<Resource> {
return RequestBuilder(config: config, gvk: gvk)
}
}

internal extension GenericKubernetesClient {

func makeRequest() -> RequestBuilder<Resource> {
return RequestBuilder(config: config, gvk: gvk)
}

func handle<T: Decodable>(_ response: HTTPClient.Response, eventLoop: EventLoop) -> EventLoopFuture<T> {
return handleResourceOrStatus(response, eventLoop: eventLoop).flatMap { (result: ResourceOrStatus<T>) -> EventLoopFuture<T> in
guard case let ResourceOrStatus.resource(resource) = result else {
Expand Down Expand Up @@ -203,16 +204,45 @@ public extension GenericKubernetesClient where Resource: ListableResource {
}
}

public extension GenericKubernetesClient {
internal extension GenericKubernetesClient {

func status(in namespace: NamespaceSelector, name: String) throws -> EventLoopFuture<Resource> {
do {
let eventLoop = httpClient.eventLoopGroup.next()
let request = try makeRequest().to(.GET).resource(withName: name).status().in(namespace).build()

return httpClient.execute(request: request, logger: logger).flatMap { response in
self.handle(response, eventLoop: eventLoop)
}
} catch {
return httpClient.eventLoopGroup.next().makeFailedFuture(error)
}
}

func updateStatus(in namespace: NamespaceSelector, _ resource: Resource) throws -> EventLoopFuture<Resource> {
do {
let eventLoop = httpClient.eventLoopGroup.next()
let request = try makeRequest().to(.PUT).resource(resource).status().in(namespace).build()

return httpClient.execute(request: request, logger: logger).flatMap { response in
self.handle(response, eventLoop: eventLoop)
}
} catch {
return httpClient.eventLoopGroup.next().makeFailedFuture(error)
}
}
}

internal extension GenericKubernetesClient {

internal func watch(in namespace: NamespaceSelector, using watch: ResourceWatch<Resource>) throws -> HTTPClient.Task<Void> {
func watch(in namespace: NamespaceSelector, using watch: ResourceWatch<Resource>) throws -> HTTPClient.Task<Void> {
let request = try makeRequest().toWatch().in(namespace).build()
let delegate = WatchDelegate(watch: watch, logger: logger)

return httpClient.execute(request: request, delegate: delegate, logger: logger)
}

internal func follow(in namespace: NamespaceSelector, name: String, container: String?, using watch: LogWatch) throws -> HTTPClient.Task<Void> {
func follow(in namespace: NamespaceSelector, name: String, container: String?, using watch: LogWatch) throws -> HTTPClient.Task<Void> {
let request = try makeRequest().toFollow(pod: name, container: container).in(namespace).build()
let delegate = WatchDelegate(watch: watch, logger: logger)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// Copyright 2020 Iskandar Abudiab (iabudiab.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import AsyncHTTPClient
import NIO
import SwiftkubeModel

public extension NamespacedGenericKubernetesClient where Resource == core.v1.Pod {

func follow(in namespace: NamespaceSelector? = nil, name: String, container: String?, lineHandler: @escaping LogWatch.LineHandler) throws -> HTTPClient.Task<Void> {
return try super.follow(in: namespace ?? .namespace(self.config.namespace), name: name, container: container, using: LogWatch(logger: logger, lineHandler))
}

func status(in namespace: NamespaceSelector? = nil, name: String) throws -> EventLoopFuture<core.v1.Pod> {
return try super.status(in: namespace ?? .namespace(self.config.namespace), name: name)
}

func updateStatus(in namespace: NamespaceSelector? = nil, _ pod: core.v1.Pod) throws -> EventLoopFuture<core.v1.Pod> {
return try super.updateStatus(in: namespace ?? .namespace(self.config.namespace), pod)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ public extension NamespacedGenericKubernetesClient where Resource: ReadableResou
}

func watch(in namespace: NamespaceSelector? = nil, eventHandler: @escaping ResourceWatch<Resource>.EventHandler) throws -> HTTPClient.Task<Void> {
return try super.watch(in: namespace ?? NamespaceSelector.allNamespaces, using: ResourceWatch<Resource>(logger: logger, eventHandler))
}

func follow(in namespace: NamespaceSelector? = nil, name: String, container: String?, lineHandler: @escaping LogWatch.LineHandler) throws -> HTTPClient.Task<Void> {
return try super.follow(in: namespace ?? NamespaceSelector.allNamespaces, name: name, container: container, using: LogWatch(logger: logger, lineHandler))
return try super.watch(in: namespace ?? .namespace(self.config.namespace), using: ResourceWatch<Resource>(logger: logger, eventHandler))
}
}

Expand Down
34 changes: 22 additions & 12 deletions Sources/SwiftkubeClient/Client/RequestBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ internal class RequestBuilder<Resource: KubernetesAPIResource> {
var listOptions: [ListOption]?
var method: HTTPMethod!
var namespace: NamespaceSelector!
var watch: Bool = false
var follow: Bool = false
var statusRequest: Bool = false
var watchRequest: Bool = false
var followRequest: Bool = false
var container: String?

init(config: KubernetesClientConfig, gvk: GroupVersionKind) {
Expand All @@ -55,17 +56,22 @@ internal class RequestBuilder<Resource: KubernetesAPIResource> {
return self
}

func status() -> RequestBuilder {
self.statusRequest = true
return self
}

func toWatch() -> RequestBuilder {
self.method = .GET
self.watch = true
self.watchRequest = true
return self
}

func toFollow(pod: String, container: String?) -> RequestBuilder {
self.method = .GET
self.resourceName = pod
self.container = container
self.follow = true
self.followRequest = true
return self
}

Expand All @@ -91,7 +97,15 @@ internal class RequestBuilder<Resource: KubernetesAPIResource> {

func build() throws -> HTTPClient.Request {
var components = URLComponents(url: config.masterURL, resolvingAgainstBaseURL: false)
components?.path = urlPath(forNamespace: namespace, name: resourceName, follow: follow)
components?.path = urlPath(forNamespace: namespace, name: resourceName)

if statusRequest {
components?.path += "/status"
}

if followRequest {
components?.path += "/log"
}

guard !(method.hasRequestBody && resourceName == nil) else {
throw SwiftkubeClientError.badRequest("Resource `metadata.name` must be set.")
Expand All @@ -103,11 +117,11 @@ internal class RequestBuilder<Resource: KubernetesAPIResource> {
components?.queryItems?.append(contentsOf: listOptions.map { URLQueryItem(name: $0.name, value: $0.value) })
}

if watch {
if watchRequest {
components?.queryItems?.append(URLQueryItem(name: "watch", value: "true"))
}

if follow {
if followRequest {
components?.queryItems?.append(URLQueryItem(name: "follow", value: "true"))
}

Expand All @@ -130,7 +144,7 @@ internal class RequestBuilder<Resource: KubernetesAPIResource> {
return try HTTPClient.Request(url: url, method: method, headers: headers, body: body)
}

func urlPath(forNamespace namespace: NamespaceSelector, name: String?, follow: Bool) -> String {
func urlPath(forNamespace namespace: NamespaceSelector, name: String?) -> String {
var url: String

if case NamespaceSelector.allNamespaces = namespace {
Expand All @@ -143,10 +157,6 @@ internal class RequestBuilder<Resource: KubernetesAPIResource> {
url += "/\(name)"
}

if follow {
url += "/log"
}

return url
}

Expand Down

0 comments on commit 4a0a394

Please sign in to comment.