Rename "container" to "image"

- Updated `wwctl upgrade` to handle updates
- Maintained `.Container` and `.ContainerName` in tstruct
- Added `ContainerName()` methods to node and profile objects
- Added `--container`, `-C` aliases to wwctl commands (`<node|profile> <add|set>`)
- Added `wwctl container` alias
- Added support for `container_exit.sh` if `image_exit.sh` is not found

Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
Jonathon Anderson
2025-01-18 17:34:48 -07:00
parent 96396ed47e
commit 45a690ca4e
142 changed files with 2212 additions and 2183 deletions

View File

@@ -14,12 +14,12 @@ wwctl node delete
wwctl node list
wwctl node set
wwctl node status
wwctl container build
wwctl container delete
wwctl container import
wwctl container list
wwctl container show
wwctl container copy
wwctl image build
wwctl image delete
wwctl image import
wwctl image list
wwctl image show
wwctl image copy
Some notes on the files:

View File

@@ -1,7 +1,7 @@
# Warewulf API Daemon
wwapid is a grpc service serving the Warewulf API. For v1, the intent is to serve the same interface as wwctl serves. For this preview PR, we are serving much of ```wwctl node``` and ```wwctl container```.
wwapid is a grpc service serving the Warewulf API. For v1, the intent is to serve the same interface as wwctl serves. For this preview PR, we are serving much of ```wwctl node``` and ```wwctl image```.
Initial security is by mTLS. For development we are generating our own keys. A good tutorial for this is here: https://www.handracs.info/blog/grpcmtlsgo/
The configuration file is wwapid.conf.
The configuration file is wwapid.conf.

View File

@@ -12,7 +12,7 @@ import (
"path"
"github.com/warewulf/warewulf/internal/pkg/api/apiconfig"
"github.com/warewulf/warewulf/internal/pkg/api/container"
"github.com/warewulf/warewulf/internal/pkg/api/image"
apinode "github.com/warewulf/warewulf/internal/pkg/api/node"
"github.com/warewulf/warewulf/internal/pkg/api/routes/wwapiv1"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
@@ -121,92 +121,92 @@ func insecureMode() {
// Api implementation.
// ContainerBuild builds one or more containers.
func (s *apiServer) ContainerBuild(ctx context.Context, request *wwapiv1.ContainerBuildParameter) (response *wwapiv1.ContainerListResponse, err error) {
// ImageBuild builds one or more images.
func (s *apiServer) ImageBuild(ctx context.Context, request *wwapiv1.ImageBuildParameter) (response *wwapiv1.ImageListResponse, err error) {
// Parameter checks.
if request == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request")
}
if request.ContainerNames == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request.ContainerNames")
if request.ImageNames == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request.ImageNames")
}
// Build the container.
err = container.ContainerBuild(request)
// Build the image.
err = image.ImageBuild(request)
if err != nil {
return
}
// Return the built containers. (A REST POST returns what is modified.)
var containers []*wwapiv1.ContainerInfo
containers, err = container.ContainerList()
// Return the built images. (A REST POST returns what is modified.)
var images []*wwapiv1.ImageInfo
images, err = image.ImageList()
if err != nil {
return
}
response = &wwapiv1.ContainerListResponse{}
for i := 0; i < len(containers); i++ {
for j := 0; j < len(request.ContainerNames); j++ {
if containers[i].Name == request.ContainerNames[j] {
response.Containers = append(response.Containers, containers[i])
response = &wwapiv1.ImageListResponse{}
for i := 0; i < len(images); i++ {
for j := 0; j < len(request.ImageNames); j++ {
if images[i].Name == request.ImageNames[j] {
response.Images = append(response.Images, images[i])
}
}
}
return
}
// ContainerCopy duplicates a container.
func (s *apiServer) ContainerCopy(ctx context.Context, request *wwapiv1.ContainerCopyParameter) (response *emptypb.Empty, err error) {
// ImageCopy duplicates an image.
func (s *apiServer) ImageCopy(ctx context.Context, request *wwapiv1.ImageCopyParameter) (response *emptypb.Empty, err error) {
// Parameter checks.
if request == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request")
}
err = container.ContainerCopy(request)
err = image.ImageCopy(request)
return
}
// ContainerDelete deletes one or more containers from Warewulf.
func (s *apiServer) ContainerDelete(ctx context.Context, request *wwapiv1.ContainerDeleteParameter) (response *emptypb.Empty, err error) {
// ImageDelete deletes one or more images from Warewulf.
func (s *apiServer) ImageDelete(ctx context.Context, request *wwapiv1.ImageDeleteParameter) (response *emptypb.Empty, err error) {
// Parameter checks.
if request == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request")
}
if request.ContainerNames == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request.ContainerNames")
if request.ImageNames == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request.ImageNames")
}
err = container.ContainerDelete(request)
err = image.ImageDelete(request)
return
}
func (s *apiServer) ContainerImport(ctx context.Context, request *wwapiv1.ContainerImportParameter) (response *wwapiv1.ContainerListResponse, err error) {
func (s *apiServer) ImageImport(ctx context.Context, request *wwapiv1.ImageImportParameter) (response *wwapiv1.ImageListResponse, err error) {
// Import the container.
var containerName string
containerName, err = container.ContainerImport(request)
// Import the image.
var imageName string
imageName, err = image.ImageImport(request)
if err != nil {
return
}
// Return the imported container to the client.
var containers []*wwapiv1.ContainerInfo
containers, err = container.ContainerList()
// Return the imported image to the client.
var images []*wwapiv1.ImageInfo
images, err = image.ImageList()
if err != nil {
return
}
// Container name may have been shimmed in during import,
// which is why ContainerImport returns it.
for i := 0; i < len(containers); i++ {
if containerName == containers[i].Name {
response = &wwapiv1.ContainerListResponse{
Containers: []*wwapiv1.ContainerInfo{containers[i]},
// Image name may have been shimmed in during import,
// which is why ImageImport returns it.
for i := 0; i < len(images); i++ {
if imageName == images[i].Name {
response = &wwapiv1.ImageListResponse{
Images: []*wwapiv1.ImageInfo{images[i]},
}
return
}
@@ -214,30 +214,30 @@ func (s *apiServer) ContainerImport(ctx context.Context, request *wwapiv1.Contai
return
}
// ContainerList returns details about containers.
func (s *apiServer) ContainerList(ctx context.Context, request *emptypb.Empty) (response *wwapiv1.ContainerListResponse, err error) {
// ImageList returns details about images.
func (s *apiServer) ImageList(ctx context.Context, request *emptypb.Empty) (response *wwapiv1.ImageListResponse, err error) {
var containers []*wwapiv1.ContainerInfo
containers, err = container.ContainerList()
var images []*wwapiv1.ImageInfo
images, err = image.ImageList()
if err != nil {
return
}
response = &wwapiv1.ContainerListResponse{
Containers: containers,
response = &wwapiv1.ImageListResponse{
Images: images,
}
return
}
// ContainerShow returns details about containers.
func (s *apiServer) ContainerShow(ctx context.Context, request *wwapiv1.ContainerShowParameter) (response *wwapiv1.ContainerShowResponse, err error) {
// ImageShow returns details about images.
func (s *apiServer) ImageShow(ctx context.Context, request *wwapiv1.ImageShowParameter) (response *wwapiv1.ImageShowResponse, err error) {
// Parameter checks.
if request == nil {
return response, status.Errorf(codes.InvalidArgument, "nil request")
}
return container.ContainerShow(request)
return image.ImageShow(request)
}
// NodeAdd adds one or more nodes for management by Warewulf and returns the added nodes.

View File

@@ -1,9 +1,9 @@
# Warewulf API Rest Daemon
wwapird is a client of wwapid serving a REST interface for the Warewulf API. For v1, the intent is to serve the same interface as wwctl serves. For this preview PR, we are serving much of ```wwctl node``` and ```wwctl container```.
wwapird is a client of wwapid serving a REST interface for the Warewulf API. For v1, the intent is to serve the same interface as wwctl serves. For this preview PR, we are serving much of ```wwctl node``` and ```wwctl image```.
Initial security is by mTLS. For development we are generating our own keys. A good tutorial for this is here: https://www.handracs.info/blog/grpcmtlsgo/
The configuration file is wwapird.conf.
Sample cURLs with and without mTLS are in curl.sh. This file is just a scratchpad for examples.
Sample cURLs with and without mTLS are in curl.sh. This file is just a scratchpad for examples.

View File

@@ -11,17 +11,17 @@ curl --cacert /usr/local/etc/warewulf/keys/cacert.pem \
--cert /usr/local/etc/warewulf/keys/client.pem \
https://localhost:9871/version
# container list all
curl http://localhost:9871/v1/container
# image list all
curl http://localhost:9871/v1/image
# container import
curl -d '{"source": "docker://ghcr.io/warewulf/warewulf-rockylinux:8", "name": "rocky-8", "update": true, "default": true}' -H "Content-Type: application/json" -X POST http://localhost:9871/v1/container
# image import
curl -d '{"source": "docker://ghcr.io/warewulf/warewulf-rockylinux:8", "name": "rocky-8", "update": true, "default": true}' -H "Content-Type: application/json" -X POST http://localhost:9871/v1/image
# container delete
curl -X DELETE http://localhost:9871/v1/container?containerNames=rocky-8
# image delete
curl -X DELETE http://localhost:9871/v1/image?imageNames=rocky-8
# container build
curl -d '{"containerNames": ["rocky-8"], "force": true}' -H "Content-Type: application/json" -X POST http://localhost:9871/v1/containerbuild
# image build
curl -d '{"imageNames": ["rocky-8"], "force": true}' -H "Content-Type: application/json" -X POST http://localhost:9871/v1/imagebuild
# node list all
curl http://localhost:9871/v1/node