Skip to content

Commit

Permalink
Add marker protocols describing supported actions for API resources
Browse files Browse the repository at this point in the history
  • Loading branch information
iabudiab committed Nov 24, 2020
1 parent 2268ae0 commit f2b3a9a
Show file tree
Hide file tree
Showing 10 changed files with 380 additions and 287 deletions.
59 changes: 59 additions & 0 deletions Sources/SwiftkubeModelGen/JSONSchemaProcessor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// 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 Foundation
import PathKit
import ShellOut

class JSONSchemaProcessor {

let apiVersion: String

init(apiVersion: String) {
self.apiVersion = apiVersion
}

func process(outputPath: Path) throws -> Definitions {
let definitionsPath = try generateJSONSchema(outputPath: outputPath)
var schema = try loadAndDecodeJson(url: definitionsPath.url, type: Definitions.self)
schema.definitions = Dictionary(uniqueKeysWithValues: schema.definitions.map { key, value in
return (key.sanitizedRef() , value)
})

return schema
}

private func generateJSONSchema(outputPath: PathKit.Path) throws -> PathKit.Path {
let jsonSchemaPath = outputPath + Path("schema-\(apiVersion)")
let openAPIURL = "https://raw.githubusercontent.com/kubernetes/kubernetes/\(apiVersion)/api/openapi-spec/swagger.json"

let _ = try shellOut(to: "/usr/local/bin/openapi2jsonschema", arguments: [
"--expanded", "--kubernetes",
"--prefix", "https://swiftkube.dev/schema/\(apiVersion)/_definitions.json",
"-o", jsonSchemaPath.absolute().string,
openAPIURL
])

return jsonSchemaPath + Path("_definitions.json")
}

private func loadAndDecodeJson<T: Decodable>(url: URL, type: T.Type) throws -> T {
guard let data = try String(contentsOf: url, encoding: .utf8).data(using: .utf8) else {
throw ModelGenError.RuntimeError(message: "Error decoding JSON")
}
return try JSONDecoder().decode(type, from: data)
}
}
2 changes: 1 addition & 1 deletion Sources/SwiftkubeModelGen/Model/GroupVersionKind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ struct GroupVersionKind: Decodable, Hashable {
}

var renderedNamespaceScope: Bool {
return NamespaceScope[kind]!
return ResourceScope[self] ?? false
}

func hash(into hasher: inout Hasher) {
Expand Down
27 changes: 12 additions & 15 deletions Sources/SwiftkubeModelGen/Model/Resource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,25 @@ struct Definitions: Decodable {
var definitions: [String: Resource]
}

struct Resource: Decodable, Comparable {
class Resource: Decodable, Comparable {

let gvk: GroupVersionKind?
let type: Type
let description: String
let required: [String]
var gvk: GroupVersionKind?
var type: Type
var description: String
var required: [String]
var properties: [Property]
var deprecated: Bool = false
var requiresCodableExtension: Bool = false
var hasMetadata: Bool = false
var isListResource: Bool = false
var isAPIResource: Bool = false
var isListableResource: Bool = false
var isNamespaced: Bool = false
var isClusterScoped: Bool = false
var isReadableResource: Bool = false
var isListableResource: Bool = false
var isCreatableResource: Bool = false
var isReplaceableResource: Bool = false
var isDeletableResource: Bool = false
var isCollectionDeletableResource: Bool = false

enum CodingKeys: String, CodingKey {
case type
Expand All @@ -59,7 +63,7 @@ struct Resource: Decodable, Comparable {
case gvk = "x-kubernetes-group-version-kind"
}

init(from decoder: Decoder) throws {
required init(from decoder: Decoder) throws {
let resourceKey = decoder.codingPath.last?.stringValue

if let _ = IgnoredSchemaTypes.first(where: { resourceKey?.hasPrefix($0) ?? false }) {
Expand Down Expand Up @@ -109,13 +113,6 @@ struct Resource: Decodable, Comparable {
self.requiresCodableExtension = properties.contains { $0.type.requiresCodableExtension }
self.hasMetadata = properties.contains { $0.type.isMetadata }
self.isListResource = properties.contains(where: { $0.name == "items" }) && gvk?.kind.hasSuffix("List") ?? false
self.isAPIResource = APITypes.contains(gvk?.kind ?? "")
self.isNamespaced = NamespaceScope.contains { (key: String, value: Bool) -> Bool in
key == gvk?.kind && value == true
}
self.isClusterScoped = NamespaceScope.contains { (key: String, value: Bool) -> Bool in
key == gvk?.kind && value == false
}
}

static func < (lhs: Resource, rhs: Resource) -> Bool {
Expand Down
23 changes: 7 additions & 16 deletions Sources/SwiftkubeModelGen/Model/TypeReference.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,18 @@

import Foundation

private let TypePrefixes = Set([
"io.k8s.api.",
"io.k8s.apiextensions-apiserver.pkg.apis.",
"io.k8s.apimachinery.pkg.apis.",
"io.k8s.kube-aggregator.pkg.apis.",
])

struct TypeReference: Hashable, Comparable {
let ref: String
let gvk: GroupVersionKind
let group: String
let version: String
let gvk: GroupVersionKind
let kind: String
let listItemKind: String
let apiVersion: String

init(ref: String) {
let sanitized = ref.deletingPrefix("#/definitions/")

self.ref = sanitized
let key = TypePrefixes.reduce(self.ref) { result, prefix in
result.deletingPrefix(prefix)
}

let gvk = key.split(separator: ".", maxSplits: 2, omittingEmptySubsequences: true)
self.ref = ref.sanitizedRef()
let gvk = self.ref.split(separator: ".", maxSplits: 2, omittingEmptySubsequences: true)
self.group = String(gvk[0])
self.version = String(gvk[1])
self.kind = String(gvk[2])
Expand All @@ -59,4 +46,8 @@ struct TypeReference: Hashable, Comparable {
let rgvk = GroupVersionKind(group: rhs.group, version: rhs.version, kind: rhs.kind)
return lgvk < rgvk
}

func hash(into hasher: inout Hasher) {
hasher.combine(ref)
}
}
Loading

0 comments on commit f2b3a9a

Please sign in to comment.