forked from fediversity/fediversity
254 lines
5.8 KiB
Nix
254 lines
5.8 KiB
Nix
{
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
inherit (pkgs.callPackage ./utils.nix { }) cast;
|
|
inherit (lib)
|
|
filterAttrs
|
|
flatten
|
|
mapAttrs
|
|
mkOption
|
|
removeAttrs
|
|
throwIf
|
|
types
|
|
;
|
|
inherit (types)
|
|
attrsOf
|
|
bool
|
|
enum
|
|
float
|
|
ints
|
|
number
|
|
submodule
|
|
listOf
|
|
str
|
|
;
|
|
sourceSchemas = filterAttrs (
|
|
k: _:
|
|
lib.elem k [
|
|
"data_source_schemas"
|
|
"resource_schemas"
|
|
]
|
|
);
|
|
in
|
|
rec {
|
|
# helpers to obtain TF provider data into `tfvars.json` to easily wrap TF resources / data sources
|
|
|
|
wrapTfType =
|
|
tfType: lib.foldr (typ: acc: if acc == null then typ else "${typ}(${acc})") null (flatten tfType);
|
|
|
|
wrapTfAttr =
|
|
{ type, ... }@attr:
|
|
removeAttrs attr [
|
|
"description_kind"
|
|
"computed"
|
|
"required"
|
|
"optional"
|
|
]
|
|
// {
|
|
type = wrapTfType type;
|
|
}
|
|
// (if (attr ? optional) then { default = null; } else { });
|
|
|
|
wrapTfAttrs = tfAttrs: {
|
|
variable = lib.mapAttrs (_: wrapTfAttr) (filterAttrs (_: v: !(v ? computed)) tfAttrs);
|
|
};
|
|
|
|
wrapTfSourceSchemas = mapAttrs (_: schemas: wrapTfAttrs schemas.block.attributes);
|
|
|
|
wrapTfProvider = schema: mapAttrs (_: wrapTfSourceSchemas) (sourceSchemas schema);
|
|
|
|
wrapTfProviderSchema =
|
|
output:
|
|
lib.mapAttrs' (k: v: {
|
|
name = lib.removePrefix "registry.opentofu.org/" k;
|
|
value = wrapTfProvider v;
|
|
}) output.provider_schemas;
|
|
|
|
# converting types
|
|
|
|
tfAttrType = submodule {
|
|
options = {
|
|
"type" = mkOption {
|
|
type = types.either str (types.listOf str);
|
|
};
|
|
"description" = mkOption {
|
|
type = str;
|
|
# default = "";
|
|
};
|
|
"description_kind" = mkOption {
|
|
type = enum [ "plain" ];
|
|
default = "plain";
|
|
};
|
|
"computed" = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
};
|
|
"sensitive" = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
};
|
|
"required" = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
};
|
|
"optional" = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
};
|
|
"deprecated" = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
};
|
|
};
|
|
};
|
|
|
|
tfAttrsType = attrsOf tfAttrType;
|
|
|
|
# converting TF to nix modules
|
|
|
|
fromTfTypes =
|
|
types:
|
|
let
|
|
typ = (lib.head types);
|
|
typs = (lib.tail types);
|
|
rest = (fromTfTypes typs);
|
|
in
|
|
{
|
|
inherit bool number;
|
|
"string" = str;
|
|
"int32" = ints.s32;
|
|
"int64" = ints.s32;
|
|
"float32" = float;
|
|
"float64" = float;
|
|
"dynamic" = types.unspecified;
|
|
"list" = listOf rest;
|
|
"map" = attrsOf rest;
|
|
"set" = listOf rest; # no unordered type in nix
|
|
object = throw "to be implemented";
|
|
tuple = throw "to be implemented";
|
|
}
|
|
.${typ};
|
|
|
|
fromTfAttr =
|
|
tfAttr:
|
|
let
|
|
inherit (cast tfAttrType tfAttr)
|
|
type
|
|
description
|
|
computed
|
|
optional
|
|
required
|
|
;
|
|
types = flatten type;
|
|
in
|
|
throwIf computed "computed TF attributes cannot be translated to Nix" mkOption (
|
|
(
|
|
if optional then
|
|
{ default = null; }
|
|
else
|
|
throwIf (!required) "either of required or optional must be true" { }
|
|
)
|
|
// {
|
|
inherit description;
|
|
type = fromTfTypes types;
|
|
}
|
|
);
|
|
|
|
fromTfAttrs =
|
|
allowSensitive: tfAttrs:
|
|
submodule {
|
|
options = lib.mapAttrs (_: fromTfAttr) (
|
|
lib.filterAttrs (
|
|
_: v: (if allowSensitive then true else !(v ? sensitive)) && !(v ? computed) && !(v ? deprecated)
|
|
) tfAttrs
|
|
);
|
|
};
|
|
|
|
fromTfSourceSchemas =
|
|
allowSensitive: schemas:
|
|
submodule {
|
|
options = mapAttrs (
|
|
_: { block, ... }: mkOption { type = fromTfAttrs allowSensitive block.attributes; }
|
|
) schemas;
|
|
};
|
|
|
|
fromTfProvider =
|
|
allowSensitive: schema:
|
|
submodule {
|
|
options = mapAttrs (_: schemas: mkOption { type = fromTfSourceSchemas allowSensitive schemas; }) (
|
|
sourceSchemas schema
|
|
);
|
|
};
|
|
|
|
fromTfProviderSchema =
|
|
allowSensitive:
|
|
{ provider_schemas, ... }:
|
|
submodule {
|
|
options = lib.mapAttrs' (k: schema: {
|
|
name = lib.removePrefix "registry.opentofu.org/" k;
|
|
value = mkOption { type = fromTfProvider allowSensitive schema; };
|
|
}) provider_schemas;
|
|
};
|
|
|
|
# extract from TF data
|
|
|
|
extractProviderSchemas =
|
|
allowSensitive: pluginFn:
|
|
let
|
|
tf = (pkgs.callPackage ./tf.nix { }).withPlugins pluginFn;
|
|
usedPlugins = pluginFn tf.plugins;
|
|
mainTf = pkgs.writers.writeJSON "main.tf.json" {
|
|
terraform.required_providers = lib.listToAttrs (
|
|
lib.lists.map (
|
|
{
|
|
meta,
|
|
owner,
|
|
version,
|
|
...
|
|
}:
|
|
let
|
|
name = lib.last (lib.splitString "/" meta.homepage);
|
|
in
|
|
{
|
|
inherit name;
|
|
value = {
|
|
source = "${owner}/${name}";
|
|
version = "= ${version}";
|
|
};
|
|
}
|
|
) usedPlugins
|
|
);
|
|
};
|
|
schemas = pkgs.stdenv.mkDerivation {
|
|
name = "tf-extract";
|
|
src = pkgs.linkFarm "tf-providers-main" [
|
|
{
|
|
name = "main.tf.json";
|
|
path = mainTf;
|
|
}
|
|
];
|
|
buildInputs = [
|
|
tf
|
|
pkgs.jq
|
|
];
|
|
buildPhase = ''
|
|
tofu init 1>/dev/null
|
|
tofu providers schema -json | jq . > ./schemas.json
|
|
'';
|
|
installPhase = ''
|
|
mkdir -p $out/share
|
|
cp ./schemas.json $out/share
|
|
'';
|
|
};
|
|
schema = lib.importJSON (builtins.storePath (builtins.toPath "${schemas}/share/schemas.json"));
|
|
wrapped = wrapTfProviderSchema schema;
|
|
converted = fromTfProviderSchema allowSensitive schema;
|
|
in
|
|
{
|
|
inherit schema wrapped converted;
|
|
};
|
|
|
|
}
|