0.8.3 • Published 1 month ago

@kumori/kam v0.8.3

Weekly downloads
-
License
EUPL
Repository
-
Last release
1 month ago

= kam (Kumori artifact Manager)

This package implements kumori module management.

It installs the kam tool, as well as the cue program, needed to process the artifacts developed for the kumori platform.

In addition, kam also installs the kumori platform cli tools, kumorictl, and kumorimgr.

== Kumori artifacts, packages and modules A Kumori artifact describes a microservice in a way that allows the kumori platform to both manage its deployments, as well as integrate it within larger microservices.

A Kumori microservice can be described either as a component or as a service application. Descriptions or Kumori artifacts are carried out using the cue specification language, on which the kumori service model is defined.

The definition of a Kumori artifact consists of a cue package. In turn, cue packages ar organizaed within cue modules. Thus, kumori artifacts will be bundled within kumori modules themsekves.

A cue module is the unit of versioning and distribution in cue, and kumori leverages also this structure.

Ideally, kumori artifact management would piggyback on top of a cue module management, but at this moment, the cue ecosystem is lacking such a framework and set of tools. kam will fill this void, with a view to integrate with the cue ecosystem once it is more developed.

== cue module management At this point in time, the module/package definition in cue affects mostly to its loader. Thus, kam must take into account how that loader works in order to provide a proper organization of packages to work with the kumori tools.

=== The cue loader cue 's loader expects packages to live within a folder structure representing a module, where the root forlder of the module is recognized because it contains a cue.mod folder and within it, it contains a module.cue file with a module field whose string value is the name of the module.

If a cue package (e.g., package A) wants to use package B that is part of module with name M, it needs to use an import sentence that includes the package import path for B .

The package import path for package B is formed by concatenating its module name as stored within the special cue.mod/module.cue at the root folder of the module M to which B belongs, with the path from that root folder to the folder where the contents of package B are placed, and, finally, with the suffix :B.

Thus, A needs to have the following import sentence in order to use B.

source,cue

import ( "M/:B"

)

The suffix :B can be dropped from the import path if the basename of <path-to-B-from-root-of-M> is B itself..

Note that no special provision is made for imports between packages of the same module. Thus if in the above example A and B are within the same module M, the import sentence for A still needs to have the form shown above.

==== How does cue find the packages being imported.

When a cue file A imports package B, cue first finds A's module by traversing the folder structure upwards from A 's folder (until it finds the special cue.mod/module.cue, moment at which it determines it has reached the root of the module for A).

The loader then checks if A's module name is a prefix of the import path. In that case it assumes that the the module for B is the same as that of A and it finds the contents of B by traversing the rest of the path minus the prefix of the module's name.

Otherwise the loader starts searching within various subfolders within cue.mod, including the pkg, gen and usr subfolders. The search proceeds trying to match the package import path exactly with a path within pkg (and gen, usr), minus the :B suffix, if any.

Note that the assumption is that all leaf paths in cue.mod/pkg have two parts. An Mp part, with a path leading to a cue module's root directory, and a Pp part, leading to a package containing folder at the leaf. Thus, once the loader finds a path in pkg matching an import path, it ought to check that the module name found at the module root, M within the path corresponds with the prefix of the path at that root folder. I.e. Mp == M. When such condition is met the contents of the full path are loaded to satisfy the dependency, in accordance with how the loader actually picks up the contents of the package (see https://cuelang.org[])

Note, however, that the loader performs no check whatsoever on the imported package's module. It only pays attention to the folder structure...

Moreover, nested imports are not encapsulated. E.g., if A import B, which, in turn, imports C assuming all of them are in different modules, the logical structure would be for A's module to contain B 's module within A 's own cue.mod/pkg, and B 's module to contain C's module within B 's own cue.mod/pkg. However this does not work, as when processing packages from A all package imports, including those coming from B are searched within A 's cue.mod context. Which means that, in order for B to find C, C's module must be placed within the cue.mod/pkg forlder of A.

The above makes it difficult to bundle up a module and all its dependencies toghether to satisfy the way CUE wants to find imported packages.

==== Kumori's approach to circumvent CUE's loader

When a workspace is set up to work with Kumori modules, the workspace is configured as a CUE module, with its own cue.mod folder. Within that folder, a link is made from cue.mod/pkg to the module cache in a context of the user's choosing. By default, this context will be associated with the user's home directory in a specific subpath (e.g., .kumori/context).

Kumori modules are fully versioned, being the version part of the import path of the module. A complete module import path (its unambiguous name) has the following shape:

source,cue

//...//@

A Kumori module can then be installed (even multiple versions of the same module). When installing a module, it is placed, with the directory structure of its import path, within the user context's cache folder, making it available to any workspace linking to it.

To make this work, the author of a module, before publishing it, needs to build it. The process of building a kumori module consists of substituting all module import paths appearing in the cue files of the module for the import paths including the actual version of modules depended upon (the full module name as exemplified above).

The build process needs the module author to declare its dependencies somewhere. The place Kumori chose to keep metadata for kumori modules (for example, module dependencies) is the kmodule.cue file at the root of the CUE module of the workspace.

The kmodule.cue file declares the kmodule package which can be imported by the rest of the packages in the module.

To make it less cumbersome for packages in a module to depend on each other without needing to know the actual name/import path of the module they reside in, kumori modules' cue.mod/module.cue file contains exactly the same for any module: module: "...", that is, within the workspace the name of the module (its import path) is simply "...". Now, importing package B will only need an import path like so: import " .../B".

When building the kumori module, kam will substitute the references to ... with the full import path of the module being built, with its full semantic version qualification.

The result of the build process is a folder mirroring the structure and contents of the actual module's root folder, but where all import statements have been bound to both, the full name of the module (for paths starting with ...) and the full names of the imported modules. This build folder can finally be packaged within a tar tgz archive, and placed in suitable registries for distribution. To make it possible to verify the contents of a module, the build process also produces a checksum of the package.

This approach guarantees an effect similar to bundling a module with its exact dependencies guaranteeing that a module uses exactly the dependencies it declared when it was built.

Note that packaged module does not need to include a cue.mod folder, as it is not used for anything by the loader when importing from imported packages (as is the case with installed modules). An active workspace, by virtue of its link cue.mod/pkg to the context's cache will be able to access all

== Structure of a kumori workspace

A kumori workspace IS a cue module, with additional restrictions. As such, it is represented in a folder containing a cue.mod folder with a cue.mod/module.cue file, in which there is a module field whose value is "...".

In addition, a Kumori workspace also fulfills the following requirements.

  1. It contains a cue.mod/usr subfolder, and a cue.mod/pkg symbolic link to a cache of installed kumori modules. There may be at times other subfolders of cue.mod, like cue.mod/gen, containing generated artifacts from the main files in the module folder. In particular, if the workspace ends up as a kumori module, cue.mod/gen will be used as the build folder.
  2. When the worksapce is for a kumori module, there is a kumori.cue file, at the root folder, belonging to the kmodule package. This file contains metadata relevant to the kumori module, like version, name, and dependencies.
  3. Each artifact resides within its own subfolder of the root module. The artifact's CUE package name must coincide with the basename of its name. Also ideally, the artifact's folder should contain an artifact.cue file and a ref.cue file, both within the artifact's package.
  4. The artifact's directory path from the module's root directory is the artifact's name.
  5. Every artifact package MUST provide a #Artifact definition. This definition should comply with the #Artifact definition of the Kumori service model for the kind of artifact it represents

source,cue

#Module: { // The versions of cue this module has been tested with cue: ...string

// the domain of the set of artifacts it contains domain: string // The name of the module minus the domain name name: string

// NOTE: the typical situation is that the CUE module // is formed by path joining the domain with the name.

// Sem version of this module semver: { version: uint,uint,uint prerelease?: string buildmetadata?: string }

// The dictionary of module dependencies. // The key is an alias for the module's import path // The value is a full module import path name (complete // semantic version value) dependencies: string: string // The dictionary of checksums // A key is a complete/full module name, including semantic versioning // the value is the checksum associated with the depended module. sums: string: string // Names of artifacts defined artifacts: ...#ArtifactRecord }

#ArtifactRecord : { name: string kind: "component" | "service"

}

=== Kumori redistributable modules

Kumori modules can be created from workspaces by building them as explained above. A Kumori does not contain a cue.mod folder, it just contains the kmodule.cue file.

== The kam tool

The kam tool is in charge of managing Kumori artifacts through manipulation of CUE modules and packages.

kam complements and uses kumorictl/kumorimgr. In addition, the kam package can be used as a library that can be used to implement other useful functions.

kam implements the following functionality:

  • Compute the sum of a file as per golang.
  • Compute the sha of a folder, also as done in golang
  • Edit the version in various ways
  • Tag the current version if on a git repo
  • Add dependencies
  • Add dependency imports to a file
  • Create/Init a module
  • Create/Init an artifact (within a module)
  • Register modules globally in a context (with location method and checksum)
  • Bring modules into the global cache for their use
    • Modules can also be general CUE modules, although in this case, dependencies are not pursued (e.g., kumori.systems/kumori)
  • Building and packaging kumori modules
  • Setting up contexts
  • Publishing kumori module packages
  • Creating Deployment manifests and using kumorictl to launch them (TBD)
  • Managing multiple cluster tarhets for deployment (TBD)
  • Managing multiple kumori module registries. (TBD)

...

=== KAM, modules and workspaces

kam module init <name> creates a folder cue.mod within the folder where the tool is launched and initializes it with module.cue, so that the module name in module.cue is constant "...".

Also in links cue.mod/pkg to the user's kumori context's cache. It also creates the cue.mod/usr folder, to place there links from the dependency aliases to the actual modules they depend on.

Additionally, the command creates and initializes a kmodule.cue file at the module's root.

=== KAM and artifacts Artifacts defined within the module should fill their spec/ref fields.

kam module <artifact kind> init, creates a component/service artifact at the current folder. Artifact creation within a module proceeds by creating the files ref.cue and artifact.cue at the current folder (options exist to use a different folder).

ref.cue defines the spec/ref parts of the manifest, and should not be modified by the artifact author, as its contents are fully generated by kam.

On the other hand, kam fills artifact.cue with a skeleton implementation of the artifact, with only the parts that the author has to fill for the functionality it is implementing.

== Module management

The main purpose of kam is to help author kumori modules and artifacts within them, as well as prepare anc onfigure deployoments.

Part of the specification of a module is the set of dependencies it relies on. The main dependency is on the kumori model itself. The rest will typically be on other kumori modules implementing artifacts that play some role within the artifacts of the module being authored.

kam provides help to handle such dependencies, and it also helps manage installation of the depended modules, so that cue processing can be carried out for testing, before publishing the module.

Besides the current module being authored, kam also manages a kumori context. This context at the moment consists of a module registry, plus a cache of downloades modules. The registry serves the purpose of helping locate the module's contents. The cache stores the modules that have been downloaded.

There is also a weak reference count for modules that have been linked to by some module being authored.

The deafult directory context is in $HOME/.kumori. Within it one can find the context.json file, containing checksums and location information for registered modules, and the caching subdirectory. The caching subdirectory has been organized as if the context root was a CUE module.

Thus, the caching directory resides within the cue.mod/pkg subdirectory of the context directory. Within it cached modules are organized as expected by the CUE loader. The caching module receives the name deployments

The decission to adopt this organization will be made clear whe we introduce deployment support.

=== Adding a dependency to a module To add a dependency to a module, an alias for the dependency should be provided as well as some sort of version specification for it indicating which name/version pairs satisfy the dependency.

When adding such dependency, the context is queried to return a full name (vith semver) for the module as well a checksum. Then kam proceeds by adding an entry in kmodule.cue for the alias provided, to the full module name returned by the context. At the same time, it adds a checksum entry for that full module name.

Finally, it adds a link within the cue.mod/usr folder from the alias to the folder in the context cache containing the actual dependency.

Acting this way guarantees that the cue files within the workspace can be processed by CUE.

== Module registries

NOTE: We implement a file registry as well as an npm-based registry

== Deployments and testing

Testing a specification needs the ability of generating deployments.

TBD

== GIT We advise the usage of a git repository to handle the creation of kumori modules. When a new module is created, we include at its root a .gitignore file whose contents configure git to not include the cue.mod directory.

0.8.3

1 month ago

0.8.2

1 month ago

0.7.0-alpha.29.f

7 months ago

0.7.0-alpha.29.h

7 months ago

0.7.0-alpha.29.g

7 months ago

0.7.0-alpha.29.j

7 months ago

0.7.0-alpha.29.i

7 months ago

0.7.0-alpha.29.l

7 months ago

0.7.0-alpha.29.k

7 months ago

0.7.0-alpha.29.n

7 months ago

0.7.0-alpha.29.m

7 months ago

0.7.0-alpha.29.p

7 months ago

0.7.0-alpha.29.o

7 months ago

0.7.0-alpha.29.b

8 months ago

0.7.0-alpha.29.d

8 months ago

0.7.0-alpha.29.c

8 months ago

0.7.0-alpha.31

7 months ago

0.8.1

6 months ago

0.8.0

6 months ago

0.7.0-alpha.30

7 months ago

0.7.0-alpha.27

8 months ago

0.7.0-alpha.26

8 months ago

0.7.0-alpha.25

8 months ago

0.7.0-alpha.29

8 months ago

0.7.0-alpha.28

8 months ago

0.8.0-alpha.6

6 months ago

0.8.0-alpha.5

6 months ago

0.8.0-alpha.2

7 months ago

0.8.0-alpha.1

7 months ago

0.8.0-alpha.4

6 months ago

0.8.0-alpha.3

6 months ago

0.8.0-alpha.0

7 months ago

0.7.0-alpha.19

1 year ago

0.7.0-alpha.24

11 months ago

0.7.0-alpha.23

11 months ago

0.7.0-alpha.22

12 months ago

0.7.0-alpha.21

12 months ago

0.7.0-alpha.20

12 months ago

0.6.30

1 year ago

0.7.0-alpha.16

1 year ago

0.7.0-alpha.15

1 year ago

0.7.0-alpha.14

1 year ago

0.7.0-alpha.13

1 year ago

0.7.0-alpha.12

1 year ago

0.7.0-alpha.11

1 year ago

0.7.0-alpha.10

1 year ago

0.7.0-alpha.18

1 year ago

0.7.0-alpha.17

1 year ago

0.7.0-alpha.1

1 year ago

0.7.0-alpha.0

1 year ago

0.7.0-alpha.3

1 year ago

0.7.0-alpha.2

1 year ago

0.7.0-alpha.5

1 year ago

0.7.0-alpha.4

1 year ago

0.7.0-alpha.7

1 year ago

0.7.0-alpha.6

1 year ago

0.7.0-alpha.9

1 year ago

0.7.0-alpha.8

1 year ago

0.6.21

1 year ago

0.6.20

1 year ago

0.6.23

1 year ago

0.6.22

1 year ago

0.6.29

1 year ago

0.6.28

1 year ago

0.6.25

1 year ago

0.6.24

1 year ago

0.6.27

1 year ago

0.6.26

1 year ago

0.6.10

1 year ago

0.6.12

1 year ago

0.6.11

1 year ago

0.6.18

1 year ago

0.6.17

1 year ago

0.6.19

1 year ago

0.6.14

1 year ago

0.6.13

1 year ago

0.6.16

1 year ago

0.6.15

1 year ago

0.6.7

1 year ago

0.6.6

1 year ago

0.6.9

1 year ago

0.6.8

1 year ago

0.6.3

1 year ago

0.6.5

1 year ago

0.6.4

1 year ago

0.5.2

2 years ago

0.5.1

2 years ago

0.3.12

2 years ago

0.6.2

2 years ago

0.4.1

2 years ago

0.4.0

2 years ago

0.6.1

2 years ago

0.6.0

2 years ago

0.4.2

2 years ago

0.3.9

2 years ago

0.3.11

2 years ago

0.3.10

2 years ago

0.3.8

2 years ago

0.1.23

2 years ago

0.1.24

2 years ago

0.1.25

2 years ago

0.1.26

2 years ago

0.3.0

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.3.6

2 years ago

0.3.5

2 years ago

0.3.7

2 years ago

0.3.2

2 years ago

0.3.1

2 years ago

0.2.2

2 years ago

0.3.4

2 years ago

0.1.20

2 years ago

0.1.21

2 years ago

0.1.22

2 years ago

0.1.10

2 years ago

0.1.11

2 years ago

0.1.12

2 years ago

0.1.13

2 years ago

0.1.14

2 years ago

0.1.15

2 years ago

0.1.16

2 years ago

0.1.8

2 years ago

0.1.17

2 years ago

0.1.7

2 years ago

0.1.18

2 years ago

0.1.19

2 years ago

0.1.9

2 years ago

0.1.4

2 years ago

0.1.6

2 years ago

0.1.5

2 years ago

0.1.3

2 years ago

0.1.2

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago