2022-04-02 12:40:35 -07:00
|
|
|
{
|
|
|
|
|
pkgs ? import <nixpkgs> {},
|
|
|
|
|
lib ? pkgs.lib,
|
|
|
|
|
spec ? ./istio-schema.json,
|
|
|
|
|
}:
|
|
|
|
|
with lib; let
|
2019-02-11 21:21:07 +01:00
|
|
|
gen = rec {
|
2021-05-13 17:27:08 -04:00
|
|
|
mkMerge = values: ''mkMerge [${concatMapStrings
|
2022-04-02 12:40:35 -07:00
|
|
|
(value: "
|
2019-02-11 21:21:07 +01:00
|
|
|
${value}
|
2021-05-13 17:27:08 -04:00
|
|
|
")
|
2022-04-02 12:40:35 -07:00
|
|
|
values}]'';
|
2019-02-11 21:21:07 +01:00
|
|
|
|
2021-05-13 17:27:08 -04:00
|
|
|
toNixString = value:
|
|
|
|
|
if isAttrs value || isList value
|
2019-02-11 21:21:07 +01:00
|
|
|
then builtins.toJSON value
|
|
|
|
|
else if isString value
|
|
|
|
|
then ''"${value}"''
|
|
|
|
|
else if value == null
|
|
|
|
|
then "null"
|
|
|
|
|
else builtins.toString value;
|
|
|
|
|
|
|
|
|
|
removeEmptyLines = str: concatStringsSep "\n" (filter (l: (builtins.match "( |)+" l) == null) (splitString "\n" str));
|
|
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
mkOption = {
|
|
|
|
|
description ? null,
|
|
|
|
|
type ? null,
|
|
|
|
|
default ? null,
|
|
|
|
|
apply ? null,
|
|
|
|
|
}:
|
|
|
|
|
removeEmptyLines '' mkOption {
|
|
|
|
|
${optionalString (description != null) "description = ${builtins.toJSON description};"}
|
|
|
|
|
${optionalString (type != null) ''type = ${type};''}
|
|
|
|
|
${optionalString (default != null) ''default = ${toNixString default};''}
|
|
|
|
|
${optionalString (apply != null) ''apply = ${apply};''}
|
|
|
|
|
}'';
|
2019-02-11 21:21:07 +01:00
|
|
|
|
2021-05-13 17:27:08 -04:00
|
|
|
mkOverride = priority: value: "mkOverride ${toString priority} ${toNixString value}";
|
2019-02-11 21:21:07 +01:00
|
|
|
|
|
|
|
|
types = {
|
|
|
|
|
unspecified = "types.unspecified";
|
|
|
|
|
str = "types.str";
|
|
|
|
|
int = "types.int";
|
|
|
|
|
bool = "types.bool";
|
|
|
|
|
attrs = "types.attrs";
|
|
|
|
|
nullOr = val: "(types.nullOr ${val})";
|
|
|
|
|
attrsOf = val: "(types.attrsOf ${val})";
|
|
|
|
|
listOf = val: "(types.listOf ${val})";
|
2022-04-02 12:40:35 -07:00
|
|
|
coercedTo = coercedType: coerceFunc: finalType: "(types.coercedTo ${coercedType} ${coerceFunc} ${finalType})";
|
2019-02-11 21:21:07 +01:00
|
|
|
either = val1: val2: "(types.either ${val1} ${val2})";
|
|
|
|
|
loaOf = type: "(types.loaOf ${type})";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
hasTypeMapping = def:
|
2022-04-02 12:40:35 -07:00
|
|
|
hasAttr "type" def
|
|
|
|
|
&& elem def.type ["string" "integer" "boolean"];
|
2019-02-11 21:21:07 +01:00
|
|
|
|
|
|
|
|
mergeValuesByKey = mergeKey: ''(mergeValuesByKey "${mergeKey}")'';
|
|
|
|
|
|
|
|
|
|
mapType = def:
|
2022-04-02 12:40:35 -07:00
|
|
|
if def.type == "string"
|
|
|
|
|
then
|
2019-02-11 21:21:07 +01:00
|
|
|
if hasAttr "format" def && def.format == "int-or-string"
|
|
|
|
|
then types.either types.int types.str
|
|
|
|
|
else types.str
|
2022-04-02 12:40:35 -07:00
|
|
|
else if def.type == "integer"
|
|
|
|
|
then types.int
|
|
|
|
|
else if def.type == "number"
|
|
|
|
|
then types.int
|
|
|
|
|
else if def.type == "boolean"
|
|
|
|
|
then types.bool
|
|
|
|
|
else if def.type == "object"
|
|
|
|
|
then types.attrs
|
2019-02-11 21:21:07 +01:00
|
|
|
else throw "type ${def.type} not supported";
|
|
|
|
|
|
2022-04-02 13:41:07 -07:00
|
|
|
submoduleOf = _definitions: ref: ''(submoduleOf "${ref}")'';
|
2019-02-11 21:21:07 +01:00
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
submoduleForDefinition = ref: name: kind: group: version: ''(submoduleForDefinition "${ref}" "${name}" "${kind}" "${group}" "${version}")'';
|
2019-02-11 21:21:07 +01:00
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
coerceAttrsOfSubmodulesToListByKey = ref: mergeKey: ''(coerceAttrsOfSubmodulesToListByKey "${ref}" "${mergeKey}")'';
|
2019-02-11 21:21:07 +01:00
|
|
|
|
|
|
|
|
attrsToList = "values: if values != null then mapAttrsToList (n: v: v) values else values";
|
|
|
|
|
|
|
|
|
|
refDefinition = attr: head (tail (tail (splitString "/" attr."$ref")));
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
fixJSON = content: replaceStrings ["\\u"] ["u"] content;
|
2019-02-11 21:21:07 +01:00
|
|
|
|
|
|
|
|
fetchSpecs = path: builtins.fromJSON (fixJSON (builtins.readFile path));
|
|
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
genDefinitions = swagger:
|
|
|
|
|
with gen; (mapAttrs
|
|
|
|
|
(
|
2022-04-02 13:41:07 -07:00
|
|
|
_name: definition:
|
2022-04-02 12:40:35 -07:00
|
|
|
# if $ref is in definition it means it's an alias of other definition
|
|
|
|
|
if hasAttr "$ref" definition
|
|
|
|
|
then definitions."${refDefinition definition}"
|
|
|
|
|
else if !(hasAttr "properties" definition)
|
|
|
|
|
then {
|
|
|
|
|
type = mapType definition;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
options =
|
|
|
|
|
mapAttrs
|
|
|
|
|
(
|
|
|
|
|
propName: property: let
|
|
|
|
|
isRequired = elem propName (definition.required or []);
|
|
|
|
|
requiredOrNot = type:
|
|
|
|
|
if isRequired
|
|
|
|
|
then type
|
|
|
|
|
else types.nullOr type;
|
|
|
|
|
optionProperties =
|
|
|
|
|
# if $ref is in property it references other definition,
|
|
|
|
|
# but if other definition does not have properties, then just take it's type
|
|
|
|
|
if hasAttr "$ref" property
|
|
|
|
|
then
|
|
|
|
|
if hasTypeMapping swagger.definitions.${refDefinition property}
|
|
|
|
|
then {
|
|
|
|
|
type = requiredOrNot (mapType swagger.definitions.${refDefinition property});
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
type = requiredOrNot (submoduleOf definitions (refDefinition property));
|
|
|
|
|
}
|
|
|
|
|
else if !(hasAttr "type" property)
|
2021-05-13 17:27:08 -04:00
|
|
|
then {
|
2022-04-02 12:40:35 -07:00
|
|
|
type = types.unspecified;
|
2021-05-13 17:27:08 -04:00
|
|
|
}
|
2022-04-02 12:40:35 -07:00
|
|
|
# if property has an array type
|
|
|
|
|
else if property.type == "array"
|
|
|
|
|
then
|
|
|
|
|
# if reference is in items it can reference other type of another
|
|
|
|
|
# definition
|
|
|
|
|
if hasAttr "$ref" property.items
|
2021-05-13 17:27:08 -04:00
|
|
|
then
|
2022-04-02 12:40:35 -07:00
|
|
|
# if it is a reference to simple type
|
|
|
|
|
if hasTypeMapping swagger.definitions.${refDefinition property.items}
|
|
|
|
|
then {
|
|
|
|
|
type = requiredOrNot (types.listOf (mapType swagger.definitions.${refDefinition property.items}.type));
|
2021-05-13 17:27:08 -04:00
|
|
|
}
|
2022-04-02 12:40:35 -07:00
|
|
|
# if a reference is to complex type
|
|
|
|
|
else
|
|
|
|
|
# if x-kubernetes-patch-merge-key is set then make it an
|
|
|
|
|
# attribute set of submodules
|
|
|
|
|
if hasAttr "x-kubernetes-patch-merge-key" property
|
|
|
|
|
then let
|
|
|
|
|
mergeKey = property."x-kubernetes-patch-merge-key";
|
|
|
|
|
in {
|
|
|
|
|
type = requiredOrNot (coerceAttrsOfSubmodulesToListByKey (refDefinition property.items) mergeKey);
|
|
|
|
|
apply = attrsToList;
|
|
|
|
|
}
|
|
|
|
|
# in other case it's a simple list
|
|
|
|
|
else {
|
|
|
|
|
type = requiredOrNot (types.listOf (submoduleOf definitions (refDefinition property.items)));
|
|
|
|
|
}
|
|
|
|
|
# in other case it only references a simple type
|
2021-05-13 17:27:08 -04:00
|
|
|
else {
|
2022-04-02 12:40:35 -07:00
|
|
|
type = requiredOrNot (types.listOf (mapType property.items));
|
2021-05-13 17:27:08 -04:00
|
|
|
}
|
2022-04-02 12:40:35 -07:00
|
|
|
else if property.type == "object" && hasAttr "additionalProperties" property
|
|
|
|
|
then
|
|
|
|
|
# if it is a reference to simple type
|
|
|
|
|
if
|
|
|
|
|
(
|
|
|
|
|
hasAttr "$ref" property.additionalProperties
|
|
|
|
|
&& hasTypeMapping swagger.definitions.${refDefinition property.additionalProperties}
|
|
|
|
|
)
|
|
|
|
|
then {
|
|
|
|
|
type = requiredOrNot (types.attrsOf (mapType swagger.definitions.${refDefinition property.additionalProperties}));
|
|
|
|
|
}
|
|
|
|
|
else if hasAttr "$ref" property.additionalProperties
|
|
|
|
|
then {
|
|
|
|
|
type = requiredOrNot types.attrs;
|
|
|
|
|
}
|
|
|
|
|
# if is an array
|
|
|
|
|
else if property.additionalProperties.type == "array"
|
|
|
|
|
then {
|
|
|
|
|
type = requiredOrNot (types.loaOf (mapType property.additionalProperties.items));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
type = requiredOrNot (types.attrsOf (mapType property.additionalProperties));
|
|
|
|
|
}
|
|
|
|
|
# just a simple property
|
|
|
|
|
else {
|
|
|
|
|
type = requiredOrNot (mapType property);
|
|
|
|
|
};
|
|
|
|
|
in
|
|
|
|
|
mkOption ({
|
|
|
|
|
description = property.description or "";
|
|
|
|
|
}
|
|
|
|
|
// optionProperties)
|
2021-05-13 17:27:08 -04:00
|
|
|
)
|
|
|
|
|
definition.properties;
|
2022-04-02 12:40:35 -07:00
|
|
|
config = let
|
|
|
|
|
optionalProps =
|
|
|
|
|
filterAttrs
|
|
|
|
|
(
|
2022-04-02 13:41:07 -07:00
|
|
|
propName: _property:
|
2022-04-02 12:40:35 -07:00
|
|
|
!(elem propName (definition.required or []))
|
|
|
|
|
)
|
|
|
|
|
definition.properties;
|
|
|
|
|
in
|
2022-04-02 13:41:07 -07:00
|
|
|
mapAttrs (_name: _property: mkOverride 1002 null) optionalProps;
|
2022-04-02 12:40:35 -07:00
|
|
|
}
|
2021-05-13 17:27:08 -04:00
|
|
|
)
|
2022-04-02 12:40:35 -07:00
|
|
|
swagger.definitions);
|
|
|
|
|
|
|
|
|
|
genResources = swagger:
|
|
|
|
|
(mapAttrsToList
|
2022-04-02 13:41:07 -07:00
|
|
|
(_name: property: rec {
|
2022-04-02 12:40:35 -07:00
|
|
|
splittedType = splitString "." (removePrefix "me.snowdrop.istio.api." property.javaType);
|
|
|
|
|
group = (concatStringsSep "." (take ((length splittedType) - 2) splittedType)) + ".istio.io";
|
|
|
|
|
kind = removeSuffix "Spec" (last splittedType);
|
|
|
|
|
version = last (take ((length splittedType) - 1) splittedType);
|
|
|
|
|
ref = removePrefix "#/definitions/" property."$ref";
|
|
|
|
|
})
|
|
|
|
|
(filterAttrs
|
|
|
|
|
(
|
2022-04-02 13:41:07 -07:00
|
|
|
_name: property:
|
2022-04-02 12:40:35 -07:00
|
|
|
(hasPrefix "me.snowdrop.istio.api" property.javaType)
|
|
|
|
|
&& hasSuffix "Spec" property.javaType
|
|
|
|
|
)
|
|
|
|
|
swagger.properties))
|
|
|
|
|
++ (mapAttrsToList
|
2022-04-02 13:41:07 -07:00
|
|
|
(_name: property: rec {
|
2022-04-02 12:40:35 -07:00
|
|
|
splittedType = splitString "." (removePrefix "me.snowdrop.istio.mixer." property.javaType);
|
|
|
|
|
group = "config.istio.io";
|
|
|
|
|
version = "v1alpha2";
|
|
|
|
|
kind = head (tail splittedType);
|
|
|
|
|
ref = removePrefix "#/definitions/" property."$ref";
|
|
|
|
|
})
|
|
|
|
|
(filterAttrs
|
|
|
|
|
(
|
2022-04-02 13:41:07 -07:00
|
|
|
_name: property:
|
2022-04-02 12:40:35 -07:00
|
|
|
(hasPrefix "me.snowdrop.istio.mixer" property.javaType)
|
|
|
|
|
&& hasSuffix "Spec" property.javaType
|
|
|
|
|
)
|
|
|
|
|
swagger.properties));
|
2019-02-11 21:21:07 +01:00
|
|
|
|
2021-05-13 17:27:08 -04:00
|
|
|
swagger = fetchSpecs spec;
|
2019-02-11 21:21:07 +01:00
|
|
|
|
2021-05-13 17:27:08 -04:00
|
|
|
definitions = genDefinitions swagger;
|
2021-05-28 19:25:48 -05:00
|
|
|
|
|
|
|
|
generated = ''
|
2022-04-02 12:40:35 -07:00
|
|
|
# This file was generated with kubenix k8s generator, do not edit
|
|
|
|
|
{lib, config, ... }:
|
|
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
|
|
let
|
|
|
|
|
types = lib.types // rec {
|
|
|
|
|
str = mkOptionType {
|
|
|
|
|
name = "str";
|
|
|
|
|
description = "string";
|
|
|
|
|
check = isString;
|
|
|
|
|
merge = mergeEqualOption;
|
|
|
|
|
};
|
2021-05-28 19:25:48 -05:00
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
# Either value of type `finalType` or `coercedType`, the latter is
|
|
|
|
|
# converted to `finalType` using `coerceFunc`.
|
|
|
|
|
coercedTo = coercedType: coerceFunc: finalType:
|
|
|
|
|
mkOptionType rec {
|
|
|
|
|
name = "coercedTo";
|
|
|
|
|
description = "''${finalType.description} or ''${coercedType.description}";
|
|
|
|
|
check = x: finalType.check x || coercedType.check x;
|
|
|
|
|
merge = loc: defs:
|
|
|
|
|
let
|
|
|
|
|
coerceVal = val:
|
|
|
|
|
if finalType.check val then val
|
|
|
|
|
else let
|
|
|
|
|
coerced = coerceFunc val;
|
|
|
|
|
in assert finalType.check coerced; coerced;
|
|
|
|
|
|
|
|
|
|
in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs);
|
|
|
|
|
getSubOptions = finalType.getSubOptions;
|
|
|
|
|
getSubModules = finalType.getSubModules;
|
|
|
|
|
substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m);
|
|
|
|
|
typeMerge = t1: t2: null;
|
|
|
|
|
functor = (defaultFunctor name) // { wrapped = finalType; };
|
|
|
|
|
};
|
2021-05-13 17:27:08 -04:00
|
|
|
};
|
2021-05-28 19:25:48 -05:00
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
mkOptionDefault = mkOverride 1001;
|
2021-05-28 19:25:48 -05:00
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
extraOptions = {
|
|
|
|
|
kubenix = {};
|
2021-05-13 17:27:08 -04:00
|
|
|
};
|
2022-04-02 12:40:35 -07:00
|
|
|
|
|
|
|
|
mergeValuesByKey = mergeKey: values:
|
|
|
|
|
listToAttrs (map
|
|
|
|
|
(value: nameValuePair (
|
|
|
|
|
if isAttrs value.''${mergeKey}
|
|
|
|
|
then toString value.''${mergeKey}.content
|
|
|
|
|
else (toString value.''${mergeKey})
|
|
|
|
|
) value)
|
|
|
|
|
values);
|
|
|
|
|
|
|
|
|
|
submoduleOf = ref: types.submodule ({name, ...}: {
|
|
|
|
|
options = definitions."''${ref}".options;
|
|
|
|
|
config = definitions."''${ref}".config;
|
2021-05-13 17:27:08 -04:00
|
|
|
});
|
2021-05-28 19:25:48 -05:00
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
submoduleWithMergeOf = ref: mergeKey: types.submodule ({name, ...}: let
|
|
|
|
|
convertName = name:
|
|
|
|
|
if definitions."''${ref}".options.''${mergeKey}.type == types.int
|
|
|
|
|
then toInt name
|
|
|
|
|
else name;
|
|
|
|
|
in {
|
|
|
|
|
options = definitions."''${ref}".options;
|
|
|
|
|
config = definitions."''${ref}".config // {
|
|
|
|
|
''${mergeKey} = mkOverride 1002 (convertName name);
|
|
|
|
|
};
|
|
|
|
|
});
|
2021-05-28 19:25:48 -05:00
|
|
|
|
2022-04-02 12:40:35 -07:00
|
|
|
submoduleForDefinition = ref: resource: kind: group: version:
|
|
|
|
|
types.submodule ({name, ...}: {
|
|
|
|
|
options = definitions."''${ref}".options // extraOptions;
|
|
|
|
|
config = mkMerge ([
|
|
|
|
|
definitions."''${ref}".config
|
|
|
|
|
{
|
|
|
|
|
kind = mkOptionDefault kind;
|
|
|
|
|
apiVersion = mkOptionDefault version;
|
|
|
|
|
|
|
|
|
|
# metdata.name cannot use option default, due deep config
|
|
|
|
|
metadata.name = mkOptionDefault name;
|
|
|
|
|
}
|
|
|
|
|
] ++ (config.defaults.''${resource} or [])
|
|
|
|
|
++ (config.defaults.all or []));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
coerceAttrsOfSubmodulesToListByKey = ref: mergeKey: (types.coercedTo
|
|
|
|
|
(types.listOf (submoduleOf ref))
|
|
|
|
|
(mergeValuesByKey mergeKey)
|
|
|
|
|
(types.attrsOf (submoduleWithMergeOf ref mergeKey))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
definitions = {
|
|
|
|
|
${concatStrings (mapAttrsToList (name: value: ''
|
2021-05-28 19:25:48 -05:00
|
|
|
"${name}" = {${optionalString (hasAttr "options" value) "
|
|
|
|
|
options = {${concatStrings (mapAttrsToList (name: value: ''
|
|
|
|
|
"${name}" = ${value};
|
2022-04-02 12:40:35 -07:00
|
|
|
'')
|
|
|
|
|
value.options)}};
|
2021-05-28 19:25:48 -05:00
|
|
|
"}
|
|
|
|
|
|
|
|
|
|
${optionalString (hasAttr "config" value) ''
|
2022-04-02 12:40:35 -07:00
|
|
|
config = {${concatStrings (mapAttrsToList (name: value: ''
|
2021-05-28 19:25:48 -05:00
|
|
|
"${name}" = ${value};
|
2022-04-02 12:40:35 -07:00
|
|
|
'')
|
|
|
|
|
value.config)}};
|
|
|
|
|
''}
|
2021-05-28 19:25:48 -05:00
|
|
|
};
|
2022-04-02 12:40:35 -07:00
|
|
|
'')
|
|
|
|
|
definitions)}
|
|
|
|
|
} // (import ./overrides.nix {inheirt definitions lib;}));
|
|
|
|
|
in {
|
|
|
|
|
kubernetes.customResources = [
|
|
|
|
|
${concatMapStrings
|
|
|
|
|
(resource: '' {
|
|
|
|
|
group = "${resource.group}";
|
|
|
|
|
version = "${resource.version}";
|
|
|
|
|
kind = "${resource.kind}";
|
|
|
|
|
description = "";
|
|
|
|
|
module = definitions."${resource.ref}";
|
|
|
|
|
}'')
|
|
|
|
|
(genResources swagger)}
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
'';
|
2021-05-28 19:25:48 -05:00
|
|
|
in
|
2022-04-02 12:40:35 -07:00
|
|
|
pkgs.runCommand "istio-gen.nix"
|
|
|
|
|
{
|
|
|
|
|
buildInputs = [pkgs.nixpkgs-fmt];
|
|
|
|
|
} ''
|
|
|
|
|
cat << 'GENERATED' > ./raw
|
|
|
|
|
"${generated}"
|
|
|
|
|
GENERATED
|
|
|
|
|
|
|
|
|
|
nixpkgs-fmt ./raw
|
|
|
|
|
cp ./raw $out
|
|
|
|
|
''
|