container_registry.go raw

   1  package govultr
   2  
   3  import (
   4  	"context"
   5  	"fmt"
   6  	"net/http"
   7  
   8  	"github.com/google/go-querystring/query"
   9  )
  10  
  11  const vcrPath = "/v2/registry"
  12  const vcrListPath = "/v2/registries"
  13  
  14  // ContainerRegistryService is the interface to interact with the container
  15  // registry endpoints on the Vultr API.  Link :
  16  // https://www.vultr.com/api/#tag/Container-Registry
  17  type ContainerRegistryService interface {
  18  	Create(ctx context.Context, createReq *ContainerRegistryReq) (*ContainerRegistry, *http.Response, error)
  19  	Get(ctx context.Context, vcrID string) (*ContainerRegistry, *http.Response, error)
  20  	Update(ctx context.Context, vcrID string, updateReq *ContainerRegistryUpdateReq) (*ContainerRegistry, *http.Response, error)
  21  	Delete(ctx context.Context, vcrID string) error
  22  	List(ctx context.Context, options *ListOptions) ([]ContainerRegistry, *Meta, *http.Response, error)
  23  
  24  	ListRepositories(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryRepo, *Meta, *http.Response, error)
  25  	GetRepository(ctx context.Context, vcrID, imageName string) (*ContainerRegistryRepo, *http.Response, error)
  26  	UpdateRepository(ctx context.Context, vcrID, imageName string, updateReq *ContainerRegistryRepoUpdateReq) (*ContainerRegistryRepo, *http.Response, error) //nolint:lll
  27  	DeleteRepository(ctx context.Context, vcrID, imageName string) error
  28  
  29  	ListReplications(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryReplication, *Meta, *http.Response, error)
  30  	CreateReplication(ctx context.Context, vcrID, regionID string) (*ContainerRegistryReplication, *http.Response, error)
  31  	GetReplication(ctx context.Context, vcrID, regionID string) (*ContainerRegistryReplication, *http.Response, error)
  32  	DeleteReplication(ctx context.Context, vcrID, regionID string) error
  33  
  34  	UpdateRetentionSchedule(ctx context.Context, vcrID, schedule string) (*ContainerRegistryRetentionSchedule, *http.Response, error)
  35  	ExecuteRetention(ctx context.Context, vcrID string, dryRun bool) (*ContainerRegistryRetentionExecution, *http.Response, error)
  36  
  37  	ListRetentionRules(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryRetentionRule, *Meta, *http.Response, error) //nolint:lll
  38  	GetRetentionRule(ctx context.Context, vcrID string, ruleID int) (*ContainerRegistryRetentionRule, *http.Response, error)
  39  	CreateRetentionRule(ctx context.Context, vcrID string, ruleReq *ContainerRegistryRetentionRuleReq) (*ContainerRegistryRetentionRule, *http.Response, error) //nolint:lll
  40  	UpdateRetentionRule(ctx context.Context, vcrID string, ruleID int, disabled bool) (*ContainerRegistryRetentionRule, *http.Response, error)
  41  	DeleteRetentionRule(ctx context.Context, vcrID string, ruleID int) error
  42  
  43  	ListRobots(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryRobot, *Meta, *http.Response, error)
  44  	GetRobot(ctx context.Context, vcrID, robotName string) (*ContainerRegistryRobot, *http.Response, error)
  45  	UpdateRobot(ctx context.Context, vcrID, robotName string, updateReq *ContainerRegistryRobotReq) (*ContainerRegistryRobot, *http.Response, error) //nolint:lll
  46  	DeleteRobot(ctx context.Context, vcrID, robotName string) error
  47  
  48  	ListArtifacts(ctx context.Context, vcrID, imageName string, options *ListOptions) ([]ContainerRegistryArtifact, *Meta, *http.Response, error) //nolint:lll
  49  	GetArtifact(ctx context.Context, vcrID, imageName, artifactDigest string) (*ContainerRegistryArtifact, *http.Response, error)
  50  	DeleteArtifact(ctx context.Context, vcrID, imageName, artifactDigest string) error
  51  
  52  	CreateDockerCredentials(ctx context.Context, vcrID string, createOptions *DockerCredentialsOpt) (*ContainerRegistryDockerCredentials, *http.Response, error) //nolint:lll
  53  
  54  	ListRegions(ctx context.Context) ([]ContainerRegistryRegion, *Meta, *http.Response, error)
  55  	ListPlans(ctx context.Context) (*ContainerRegistryPlans, *http.Response, error)
  56  }
  57  
  58  // ContainerRegistryServiceHandler handles interaction between the container
  59  // registry service and the Vultr API.
  60  type ContainerRegistryServiceHandler struct {
  61  	client *Client
  62  }
  63  
  64  // ContainerRegistry represents a Vultr container registry subscription.
  65  type ContainerRegistry struct {
  66  	ID          string                    `json:"id"`
  67  	Name        string                    `json:"name"`
  68  	URN         string                    `json:"urn"`
  69  	Storage     ContainerRegistryStorage  `json:"storage"`
  70  	DateCreated string                    `json:"date_created"`
  71  	Public      bool                      `json:"public"`
  72  	RootUser    ContainerRegistryUser     `json:"root_user"`
  73  	Metadata    ContainerRegistryMetadata `json:"metadata"`
  74  }
  75  
  76  type containerRegistries struct {
  77  	ContainerRegistries []ContainerRegistry `json:"registries"`
  78  	Meta                *Meta               `json:"meta"`
  79  }
  80  
  81  // ContainerRegistryStorage represents the storage usage and limit.
  82  type ContainerRegistryStorage struct {
  83  	Used    ContainerRegistryStorageCount `json:"used"`
  84  	Allowed ContainerRegistryStorageCount `json:"allowed"`
  85  }
  86  
  87  // ContainerRegistryStorageCount represents the different storage usage counts.
  88  type ContainerRegistryStorageCount struct {
  89  	Bytes        float32 `json:"bytes"`
  90  	MegaBytes    float32 `json:"mb"`
  91  	GigaBytes    float32 `json:"gb"`
  92  	TeraBytes    float32 `json:"tb"`
  93  	DateModified string  `json:"updated_at"`
  94  }
  95  
  96  // ContainerRegistryUser contains the user data.
  97  type ContainerRegistryUser struct {
  98  	ID           int    `json:"id"`
  99  	UserName     string `json:"username"`
 100  	Password     string `json:"password"`
 101  	Root         bool   `json:"root"`
 102  	DateCreated  string `json:"added_at"`
 103  	DateModified string `json:"updated_at"`
 104  }
 105  
 106  // ContainerRegistryMetadata contains the meta data for the registry.
 107  type ContainerRegistryMetadata struct {
 108  	Region       ContainerRegistryRegion       `json:"region"`
 109  	Subscription ContainerRegistrySubscription `json:"subscription"`
 110  }
 111  
 112  // ContainerRegistrySubscription contains the subscription information for the
 113  // registry.
 114  type ContainerRegistrySubscription struct {
 115  	Billing ContainerRegistrySubscriptionBilling `json:"billing"`
 116  }
 117  
 118  // ContainerRegistrySubscriptionBilling represents the subscription billing
 119  // data on the registry.
 120  type ContainerRegistrySubscriptionBilling struct {
 121  	MonthlyPrice   float32 `json:"monthly_price"`
 122  	PendingCharges float32 `json:"pending_charges"`
 123  }
 124  
 125  // ContainerRegistryReq represents the data used to create a registry.
 126  type ContainerRegistryReq struct {
 127  	Name   string `json:"name"`
 128  	Public bool   `json:"public"`
 129  	Region string `json:"region"`
 130  	Plan   string `json:"plan"`
 131  }
 132  
 133  // ContainerRegistryUpdateReq represents the data used to update a registry.
 134  type ContainerRegistryUpdateReq struct {
 135  	Public *bool   `json:"public,omitempty"`
 136  	Plan   *string `json:"plan,omitempty"`
 137  }
 138  
 139  // ContainerRegistryRepo represents the data of a registry repository.
 140  type ContainerRegistryRepo struct {
 141  	Name          string `json:"name"`
 142  	Image         string `json:"image"`
 143  	Description   string `json:"description"`
 144  	DateCreated   string `json:"added_at"`
 145  	DateModified  string `json:"updated_at"`
 146  	PullCount     int    `json:"pull_count"`
 147  	ArtifactCount int    `json:"artifact_count"`
 148  }
 149  
 150  type containerRegistryRepos struct {
 151  	Repositories []ContainerRegistryRepo `json:"repositories"`
 152  	Meta         *Meta                   `json:"meta"`
 153  }
 154  
 155  // ContainerRegistryRepoUpdateReq is the data to update a registry repository.
 156  type ContainerRegistryRepoUpdateReq struct {
 157  	Description string `json:"description"`
 158  }
 159  
 160  // ContainerRegistryReplication represents a container registry replication.
 161  type ContainerRegistryReplication struct {
 162  	Region    string `json:"region"`
 163  	Namespace string `json:"namespace"`
 164  	URN       string `json:"urn"`
 165  }
 166  
 167  // ContainerRegistryReplicationReq represents a container registry replication.
 168  // request
 169  type ContainerRegistryReplicationReq struct {
 170  	Region string `json:"region"`
 171  }
 172  
 173  type containerRegistryReplicationsBase struct {
 174  	Replications []ContainerRegistryReplication `json:"replications"`
 175  	Meta         *Meta                          `json:"meta"`
 176  }
 177  
 178  // ContainerRegistryRetentionSchedule represents a container registry retention
 179  // schedule.
 180  type ContainerRegistryRetentionSchedule struct {
 181  	Schedule          string `json:"schedule"`
 182  	NextScheduledTime string `json:"next_scheduled_time"`
 183  }
 184  
 185  // ContainerRegistryRetentionScheduleReq represents a container registry
 186  // schedule request.
 187  type ContainerRegistryRetentionScheduleReq struct {
 188  	Cron string `json:"cron"`
 189  }
 190  
 191  // ContainerRegistryRetentionExecution represents a container registry
 192  // execution.
 193  type ContainerRegistryRetentionExecution struct {
 194  	Start   string `json:"start_time"`
 195  	End     string `json:"end_time"`
 196  	Trigger string `json:"trigger"`
 197  	DryRun  bool   `json:"dry_run"`
 198  }
 199  
 200  // ContainerRegistryRetentionExecutionReq represents a container registry
 201  // execution request.
 202  type ContainerRegistryRetentionExecutionReq struct {
 203  	DryRun bool `json:"dry_run"`
 204  }
 205  
 206  // ContainerRegistryRetentionRule represents a container registry retention
 207  // rule.
 208  type ContainerRegistryRetentionRule struct {
 209  	ID            int                                      `json:"id"`
 210  	Disabled      bool                                     `json:"disabled"`
 211  	Action        string                                   `json:"action"`
 212  	Parameters    ContainerRegistryRetentionRuleParameter  `json:"params"`
 213  	ScopeSelector ContainerRegistryScopeSelector           `json:"scope_selector"`
 214  	TagSelectors  []ContainerRegistryRetentionRuleSelector `json:"tag_selectors"`
 215  	Template      string                                   `json:"template"`
 216  }
 217  
 218  // ContainerRegistryRetentionRuleParameter represents a container registry rule
 219  // parameter.
 220  type ContainerRegistryRetentionRuleParameter struct {
 221  	AdditionalProperty int `json:"additional_prop"`
 222  }
 223  
 224  // ContainerRegistryScopeSelector represents a container registry retention
 225  // rule scope selector.
 226  type ContainerRegistryScopeSelector struct {
 227  	Repository []ContainerRegistryRetentionRuleSelector `json:"repository"`
 228  }
 229  
 230  // ContainerRegistryRetentionRuleSelector represents a container registry
 231  // retention rule selector.
 232  type ContainerRegistryRetentionRuleSelector struct {
 233  	Decoration string `json:"decoration"`
 234  	Kind       string `json:"kind"`
 235  	Pattern    string `json:"pattern"`
 236  }
 237  
 238  type containerRegistryRetentionRulesBase struct {
 239  	Rules []ContainerRegistryRetentionRule `json:"retention_rules"`
 240  	Meta  *Meta                            `json:"meta"`
 241  }
 242  
 243  // ContainerRegistryRetentionRuleReq represents the options for creating a
 244  // container registry retention rule.
 245  type ContainerRegistryRetentionRuleReq struct {
 246  	Type             string `json:"rule_type"`
 247  	Count            int    `json:"count,omitempty"`
 248  	RepositoryAction string `json:"repository_action"`
 249  	RepositoryMatch  string `json:"repository_match"`
 250  	TagAction        string `json:"tag_action"`
 251  	TagMatch         string `json:"tag_match"`
 252  	Untagged         bool   `json:"untagged"`
 253  }
 254  
 255  // ContainerRegistryRetentionRuleUpdateReq represents the options for updating
 256  // a container registry retention rule.
 257  type ContainerRegistryRetentionRuleUpdateReq struct {
 258  	Disabled bool `json:"disabled"`
 259  }
 260  
 261  // ContainerRegistryRobot represents the details of a container registry robot.
 262  type ContainerRegistryRobot struct {
 263  	Name        string                             `json:"name"`
 264  	Description string                             `json:"description"`
 265  	Secret      string                             `json:"secret"`
 266  	Disable     bool                               `json:"disable"`
 267  	Duration    int                                `json:"duration"`
 268  	Permissions []ContainerRegistryRobotPermission `json:"permissions"`
 269  	DateCreated string                             `json:"creation_time"`
 270  }
 271  
 272  // ContainerRegistryRobotPermission represent container registry robot
 273  // permission details.
 274  type ContainerRegistryRobotPermission struct {
 275  	Kind      string                         `json:"kind"`
 276  	Namespace string                         `json:"namespace"`
 277  	Access    []ContainerRegistryRobotAccess `json:"access"`
 278  }
 279  
 280  // ContainerRegistryRobotAccess represents container registry robot access
 281  // details.
 282  type ContainerRegistryRobotAccess struct {
 283  	Action   string `json:"action"`
 284  	Resource string `json:"resource"`
 285  	Effect   string `json:"effect"`
 286  }
 287  
 288  type containerRegistryRobotsBase struct {
 289  	Robots []ContainerRegistryRobot `json:"robots"`
 290  	Meta   *Meta                    `json:"meta"`
 291  }
 292  
 293  type ContainerRegistryRobotReq struct {
 294  	Description string                       `json:"description,omitempty"`
 295  	Disable     bool                         `json:"disable,omitempty"`
 296  	Duration    int                          `json:"duration,omitempty"`
 297  	Access      ContainerRegistryRobotAccess `json:"access,omitempty"`
 298  }
 299  
 300  // ContainerRegistryArtifact represents a container registry artifact.
 301  type ContainerRegistryArtifact struct {
 302  	ArtifactType      string                         `json:"artifact_type"`
 303  	Digest            string                         `json:"digest"`
 304  	ManifestMediaType string                         `json:"manifest_media_type"`
 305  	MediaType         string                         `json:"media_type"`
 306  	RepositoryName    string                         `json:"repository_name"`
 307  	Size              int                            `json:"size"`
 308  	Type              string                         `json:"type"`
 309  	Tags              []ContainerRegistryArtifactTag `json:"tags"`
 310  	DatePulled        string                         `json:"pull_time"`
 311  	DatePushed        string                         `json:"push_time"`
 312  }
 313  
 314  // ContainerRegistryArtifactTag represents tags on an artifact.
 315  type ContainerRegistryArtifactTag struct {
 316  	Name       string `json:"name"`
 317  	Immutable  bool   `json:"immutable"`
 318  	DatePulled string `json:"pull_time"`
 319  	DatePushed string `json:"push_time"`
 320  }
 321  
 322  type containerRegistryArtifactsBase struct {
 323  	Artifacts []ContainerRegistryArtifact `json:"artifacts"`
 324  	Meta      *Meta                       `json:"meta"`
 325  }
 326  
 327  // DockerCredentialsOpt contains the options used to create Docker credentials.
 328  type DockerCredentialsOpt struct {
 329  	ExpirySeconds *int
 330  	WriteAccess   *bool
 331  }
 332  
 333  // ContainerRegistryDockerCredentials represents the byte array of character
 334  // data returned after creating a Docker credential.
 335  type ContainerRegistryDockerCredentials []byte
 336  
 337  // UnmarshalJSON is a custom unmarshal function for
 338  // ContainerRegistryDockerCredentials.
 339  func (c *ContainerRegistryDockerCredentials) UnmarshalJSON(b []byte) error {
 340  	*c = b
 341  	return nil
 342  }
 343  
 344  // String converts the ContainerRegistryDockerCredentials to a string.
 345  func (c *ContainerRegistryDockerCredentials) String() string {
 346  	return string(*c)
 347  }
 348  
 349  // ContainerRegistryRegion represents the region data.
 350  type ContainerRegistryRegion struct {
 351  	ID           int                               `json:"id"`
 352  	Name         string                            `json:"name"`
 353  	URN          string                            `json:"urn"`
 354  	BaseURL      string                            `json:"base_url"`
 355  	Public       bool                              `json:"public"`
 356  	DateCreated  string                            `json:"added_at"`
 357  	DateModified string                            `json:"updated_at"`
 358  	DataCenter   ContainerRegistryRegionDataCenter `json:"data_center"`
 359  }
 360  
 361  // ContainerRegistryRegionDataCenter is the datacenter info for a given region.
 362  type ContainerRegistryRegionDataCenter struct {
 363  	ID          int    `json:"id"`
 364  	Name        string `json:"name"`
 365  	SiteCode    string `json:"site_code"`
 366  	Region      string `json:"region"`
 367  	Country     string `json:"country"`
 368  	Continent   string `json:"continent"`
 369  	Description string `json:"description"`
 370  	Airport     string `json:"airport"`
 371  }
 372  
 373  type containerRegistryRegions struct {
 374  	Regions []ContainerRegistryRegion `json:"regions"`
 375  	Meta    *Meta                     `json:"meta"`
 376  }
 377  
 378  // ContainerRegistryPlans contains all plan types.
 379  type ContainerRegistryPlans struct {
 380  	Plans ContainerRegistryPlanTypes `json:"plans"`
 381  }
 382  
 383  // ContainerRegistryPlanTypes represent the different plan types.
 384  type ContainerRegistryPlanTypes struct {
 385  	StartUp    ContainerRegistryPlan `json:"start_up"`
 386  	Business   ContainerRegistryPlan `json:"business"`
 387  	Premium    ContainerRegistryPlan `json:"premium"`
 388  	Enterprise ContainerRegistryPlan `json:"enterprise"`
 389  }
 390  
 391  // ContainerRegistryPlan represent the plan data.
 392  type ContainerRegistryPlan struct {
 393  	VanityName   string `json:"vanity_name"`
 394  	MaxStorageMB int    `json:"max_storage_mb"`
 395  	MonthlyPrice int    `json:"monthly_price"`
 396  }
 397  
 398  // Get retrieves a contrainer registry by ID
 399  func (h *ContainerRegistryServiceHandler) Get(ctx context.Context, id string) (*ContainerRegistry, *http.Response, error) {
 400  	req, errReq := h.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s", vcrPath, id), nil)
 401  	if errReq != nil {
 402  		return nil, nil, errReq
 403  	}
 404  
 405  	vcr := new(ContainerRegistry)
 406  	resp, errResp := h.client.DoWithContext(ctx, req, &vcr)
 407  	if errResp != nil {
 408  		return nil, resp, errResp
 409  	}
 410  
 411  	return vcr, resp, nil
 412  }
 413  
 414  // List retrieves the list of all container registries
 415  func (h *ContainerRegistryServiceHandler) List(ctx context.Context, options *ListOptions) ([]ContainerRegistry, *Meta, *http.Response, error) { //nolint:lll,dupl
 416  	req, errReq := h.client.NewRequest(ctx, http.MethodGet, vcrListPath, nil)
 417  	if errReq != nil {
 418  		return nil, nil, nil, errReq
 419  	}
 420  
 421  	qStrings, errQ := query.Values(options)
 422  	if errQ != nil {
 423  		return nil, nil, nil, errQ
 424  	}
 425  
 426  	req.URL.RawQuery = qStrings.Encode()
 427  
 428  	vcrs := new(containerRegistries)
 429  	resp, errResp := h.client.DoWithContext(ctx, req, &vcrs)
 430  	if errResp != nil {
 431  		return nil, nil, resp, errResp
 432  	}
 433  
 434  	return vcrs.ContainerRegistries, vcrs.Meta, resp, nil
 435  }
 436  
 437  // Create creates a container registry
 438  func (h *ContainerRegistryServiceHandler) Create(ctx context.Context, createReq *ContainerRegistryReq) (*ContainerRegistry, *http.Response, error) { //nolint:lll
 439  	req, errReq := h.client.NewRequest(ctx, http.MethodPost, vcrPath, createReq)
 440  	if errReq != nil {
 441  		return nil, nil, errReq
 442  	}
 443  
 444  	vcr := new(ContainerRegistry)
 445  	resp, errResp := h.client.DoWithContext(ctx, req, &vcr)
 446  	if errResp != nil {
 447  		return nil, resp, errResp
 448  	}
 449  
 450  	return vcr, resp, nil
 451  }
 452  
 453  // Update will update an existing container registry
 454  func (h *ContainerRegistryServiceHandler) Update(ctx context.Context, vcrID string, updateReq *ContainerRegistryUpdateReq) (*ContainerRegistry, *http.Response, error) { //nolint:lll
 455  	req, errReq := h.client.NewRequest(ctx, http.MethodPut, fmt.Sprintf("%s/%s", vcrPath, vcrID), updateReq)
 456  	if errReq != nil {
 457  		return nil, nil, errReq
 458  	}
 459  
 460  	vcr := new(ContainerRegistry)
 461  	resp, errResp := h.client.DoWithContext(ctx, req, &vcr)
 462  	if errResp != nil {
 463  		return nil, resp, errResp
 464  	}
 465  
 466  	return vcr, resp, nil
 467  }
 468  
 469  // Delete will delete a container registry
 470  func (h *ContainerRegistryServiceHandler) Delete(ctx context.Context, vcrID string) error {
 471  	req, errReq := h.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s", vcrPath, vcrID), nil)
 472  	if errReq != nil {
 473  		return errReq
 474  	}
 475  
 476  	_, errResp := h.client.DoWithContext(ctx, req, nil)
 477  	if errResp != nil {
 478  		return errResp
 479  	}
 480  
 481  	return nil
 482  }
 483  
 484  // ListRepositories will get a list of the repositories for a existing
 485  // container registry
 486  func (h *ContainerRegistryServiceHandler) ListRepositories(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryRepo, *Meta, *http.Response, error) { //nolint:lll,dupl
 487  	req, errReq := h.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/repositories", vcrPath, vcrID), nil)
 488  	if errReq != nil {
 489  		return nil, nil, nil, errReq
 490  	}
 491  
 492  	qStrings, errQ := query.Values(options)
 493  	if errQ != nil {
 494  		return nil, nil, nil, errQ
 495  	}
 496  
 497  	req.URL.RawQuery = qStrings.Encode()
 498  
 499  	vcrRepos := new(containerRegistryRepos)
 500  	resp, errResp := h.client.DoWithContext(ctx, req, &vcrRepos)
 501  	if errResp != nil {
 502  		return nil, nil, resp, errResp
 503  	}
 504  
 505  	return vcrRepos.Repositories, vcrRepos.Meta, resp, nil
 506  }
 507  
 508  // GetRepository will return an existing repository of the requested registry
 509  // ID and image name
 510  func (h *ContainerRegistryServiceHandler) GetRepository(ctx context.Context, vcrID, imageName string) (*ContainerRegistryRepo, *http.Response, error) { //nolint:lll
 511  	req, errReq := h.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/repository/%s", vcrPath, vcrID, imageName), nil)
 512  	if errReq != nil {
 513  		return nil, nil, errReq
 514  	}
 515  
 516  	vcrRepo := new(ContainerRegistryRepo)
 517  	resp, errResp := h.client.DoWithContext(ctx, req, &vcrRepo)
 518  	if errResp != nil {
 519  		return nil, resp, errResp
 520  	}
 521  
 522  	return vcrRepo, resp, nil
 523  }
 524  
 525  // UpdateRepository allows updating the repository with the specified registry
 526  // ID and image name
 527  func (h *ContainerRegistryServiceHandler) UpdateRepository(ctx context.Context, vcrID, imageName string, updateReq *ContainerRegistryRepoUpdateReq) (*ContainerRegistryRepo, *http.Response, error) { //nolint: lll
 528  	req, errReq := h.client.NewRequest(ctx, http.MethodPut, fmt.Sprintf("%s/%s/repository/%s", vcrPath, vcrID, imageName), updateReq)
 529  	if errReq != nil {
 530  		return nil, nil, errReq
 531  	}
 532  
 533  	vcrRepo := new(ContainerRegistryRepo)
 534  	resp, errResp := h.client.DoWithContext(ctx, req, &vcrRepo)
 535  	if errResp != nil {
 536  		return nil, resp, errResp
 537  	}
 538  
 539  	return vcrRepo, resp, nil
 540  }
 541  
 542  // DeleteRepository remove a repository from the container registry
 543  func (h *ContainerRegistryServiceHandler) DeleteRepository(ctx context.Context, vcrID, imageName string) error {
 544  	req, errReq := h.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s/repository/%s", vcrPath, vcrID, imageName), nil)
 545  	if errReq != nil {
 546  		return errReq
 547  	}
 548  
 549  	_, errResp := h.client.DoWithContext(ctx, req, nil)
 550  	if errResp != nil {
 551  		return errResp
 552  	}
 553  
 554  	return nil
 555  }
 556  
 557  // ListReplications retrieves a list of container registry replications
 558  func (h *ContainerRegistryServiceHandler) ListReplications(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryReplication, *Meta, *http.Response, error) { //nolint:lll,dupl
 559  	url := fmt.Sprintf("%s/%s/replications", vcrPath, vcrID)
 560  
 561  	req, err := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 562  	if err != nil {
 563  		return nil, nil, nil, err
 564  	}
 565  
 566  	qStrings, err := query.Values(options)
 567  	if err != nil {
 568  		return nil, nil, nil, err
 569  	}
 570  
 571  	req.URL.RawQuery = qStrings.Encode()
 572  
 573  	replications := new(containerRegistryReplicationsBase)
 574  
 575  	resp, err := h.client.DoWithContext(ctx, req, &replications)
 576  	if err != nil {
 577  		return nil, nil, resp, err
 578  	}
 579  
 580  	return replications.Replications, replications.Meta, resp, nil
 581  }
 582  
 583  // CreateReplication creates a container registry replication
 584  func (h *ContainerRegistryServiceHandler) CreateReplication(ctx context.Context, vcrID, regionID string) (*ContainerRegistryReplication, *http.Response, error) { //nolint:lll
 585  	url := fmt.Sprintf("%s/%s/replication", vcrPath, vcrID)
 586  
 587  	req, err := h.client.NewRequest(ctx, http.MethodPost, url, &ContainerRegistryReplicationReq{Region: regionID})
 588  	if err != nil {
 589  		return nil, nil, err
 590  	}
 591  
 592  	replication := new(ContainerRegistryReplication)
 593  
 594  	resp, err := h.client.DoWithContext(ctx, req, &replication)
 595  	if err != nil {
 596  		return nil, resp, err
 597  	}
 598  
 599  	return replication, resp, nil
 600  }
 601  
 602  // GetReplication retrieves a container registry replication
 603  func (h *ContainerRegistryServiceHandler) GetReplication(ctx context.Context, vcrID, regionID string) (*ContainerRegistryReplication, *http.Response, error) { //nolint:lll
 604  	url := fmt.Sprintf("%s/%s/replication/%s", vcrPath, vcrID, regionID)
 605  
 606  	req, errReq := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 607  	if errReq != nil {
 608  		return nil, nil, errReq
 609  	}
 610  
 611  	replication := new(ContainerRegistryReplication)
 612  
 613  	resp, errResp := h.client.DoWithContext(ctx, req, &replication)
 614  	if errResp != nil {
 615  		return nil, resp, errResp
 616  	}
 617  
 618  	return replication, resp, nil
 619  }
 620  
 621  // DeleteReplication deletes a container registry replication
 622  func (h *ContainerRegistryServiceHandler) DeleteReplication(ctx context.Context, vcrID, regionID string) error {
 623  	url := fmt.Sprintf("%s/%s/replication/%s", vcrPath, vcrID, regionID)
 624  
 625  	req, err := h.client.NewRequest(ctx, http.MethodDelete, url, nil)
 626  	if err != nil {
 627  		return err
 628  	}
 629  
 630  	if _, err := h.client.DoWithContext(ctx, req, nil); err != nil {
 631  		return err
 632  	}
 633  
 634  	return nil
 635  }
 636  
 637  // UpdateRetentionSchedule updates a container registry retention schedule
 638  func (h *ContainerRegistryServiceHandler) UpdateRetentionSchedule(ctx context.Context, vcrID, schedule string) (*ContainerRegistryRetentionSchedule, *http.Response, error) { //nolint:lll
 639  	url := fmt.Sprintf("%s/%s/retention/schedule", vcrPath, vcrID)
 640  
 641  	req, err := h.client.NewRequest(ctx, http.MethodPut, url, &ContainerRegistryRetentionScheduleReq{Cron: schedule})
 642  	if err != nil {
 643  		return nil, nil, err
 644  	}
 645  
 646  	sched := new(ContainerRegistryRetentionSchedule)
 647  
 648  	resp, errResp := h.client.DoWithContext(ctx, req, &sched)
 649  	if errResp != nil {
 650  		return nil, resp, errResp
 651  	}
 652  
 653  	return sched, resp, nil
 654  }
 655  
 656  // ExecuteRetention triggers a container registry retention execution
 657  func (h *ContainerRegistryServiceHandler) ExecuteRetention(ctx context.Context, vcrID string, dryRun bool) (*ContainerRegistryRetentionExecution, *http.Response, error) { //nolint:lll
 658  	url := fmt.Sprintf("%s/%s/retention/executions", vcrPath, vcrID)
 659  
 660  	req, err := h.client.NewRequest(ctx, http.MethodPost, url, &ContainerRegistryRetentionExecutionReq{DryRun: dryRun})
 661  	if err != nil {
 662  		return nil, nil, err
 663  	}
 664  
 665  	execution := new(ContainerRegistryRetentionExecution)
 666  
 667  	resp, errResp := h.client.DoWithContext(ctx, req, &execution)
 668  	if errResp != nil {
 669  		return nil, resp, errResp
 670  	}
 671  
 672  	return execution, resp, nil
 673  }
 674  
 675  // ListRetentionRules retrieves a list of container registry retention rules
 676  func (h *ContainerRegistryServiceHandler) ListRetentionRules(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryRetentionRule, *Meta, *http.Response, error) { //nolint:lll,dupl
 677  	url := fmt.Sprintf("%s/%s/retention/rules", vcrPath, vcrID)
 678  
 679  	req, err := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 680  	if err != nil {
 681  		return nil, nil, nil, err
 682  	}
 683  
 684  	qStrings, err := query.Values(options)
 685  	if err != nil {
 686  		return nil, nil, nil, err
 687  	}
 688  
 689  	req.URL.RawQuery = qStrings.Encode()
 690  
 691  	rules := new(containerRegistryRetentionRulesBase)
 692  
 693  	resp, err := h.client.DoWithContext(ctx, req, &rules)
 694  	if err != nil {
 695  		return nil, nil, resp, err
 696  	}
 697  
 698  	return rules.Rules, rules.Meta, resp, nil
 699  }
 700  
 701  // CreateRetentionRule creates a new container registry retention rule
 702  func (h *ContainerRegistryServiceHandler) CreateRetentionRule(ctx context.Context, vcrID string, ruleReq *ContainerRegistryRetentionRuleReq) (*ContainerRegistryRetentionRule, *http.Response, error) { //nolint:lll
 703  	url := fmt.Sprintf("%s/%s/retention/rules", vcrPath, vcrID)
 704  
 705  	req, err := h.client.NewRequest(ctx, http.MethodPost, url, ruleReq)
 706  	if err != nil {
 707  		return nil, nil, err
 708  	}
 709  
 710  	rule := new(ContainerRegistryRetentionRule)
 711  
 712  	resp, err := h.client.DoWithContext(ctx, req, &rule)
 713  	if err != nil {
 714  		return nil, resp, err
 715  	}
 716  
 717  	return rule, resp, nil
 718  }
 719  
 720  // GetRetentionRule retrieves a container registry retention rule
 721  func (h *ContainerRegistryServiceHandler) GetRetentionRule(ctx context.Context, vcrID string, ruleID int) (*ContainerRegistryRetentionRule, *http.Response, error) { //nolint:lll
 722  	url := fmt.Sprintf("%s/%s/retention/rules/%d", vcrPath, vcrID, ruleID)
 723  
 724  	req, err := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 725  	if err != nil {
 726  		return nil, nil, err
 727  	}
 728  
 729  	rule := new(ContainerRegistryRetentionRule)
 730  
 731  	resp, err := h.client.DoWithContext(ctx, req, &rule)
 732  	if err != nil {
 733  		return nil, resp, err
 734  	}
 735  
 736  	return rule, resp, nil
 737  }
 738  
 739  // UpdateRetentionRule updates a container registry retention rule
 740  func (h *ContainerRegistryServiceHandler) UpdateRetentionRule(ctx context.Context, vcrID string, ruleID int, disabled bool) (*ContainerRegistryRetentionRule, *http.Response, error) { //nolint:lll
 741  	url := fmt.Sprintf("%s/%s/retention/rules/%d", vcrPath, vcrID, ruleID)
 742  
 743  	req, err := h.client.NewRequest(ctx, http.MethodPut, url, &ContainerRegistryRetentionRuleUpdateReq{Disabled: disabled})
 744  	if err != nil {
 745  		return nil, nil, err
 746  	}
 747  
 748  	rule := new(ContainerRegistryRetentionRule)
 749  
 750  	resp, err := h.client.DoWithContext(ctx, req, &rule)
 751  	if err != nil {
 752  		return nil, resp, err
 753  	}
 754  
 755  	return rule, resp, nil
 756  }
 757  
 758  // DeleteRetentionRule deletes a container registry retention rule
 759  func (h *ContainerRegistryServiceHandler) DeleteRetentionRule(ctx context.Context, vcrID string, ruleID int) error {
 760  	url := fmt.Sprintf("%s/%s/retention/rules/%d", vcrPath, vcrID, ruleID)
 761  
 762  	req, err := h.client.NewRequest(ctx, http.MethodDelete, url, nil)
 763  	if err != nil {
 764  		return err
 765  	}
 766  
 767  	if _, err := h.client.DoWithContext(ctx, req, nil); err != nil {
 768  		return err
 769  	}
 770  
 771  	return nil
 772  }
 773  
 774  func (h *ContainerRegistryServiceHandler) ListRobots(ctx context.Context, vcrID string, options *ListOptions) ([]ContainerRegistryRobot, *Meta, *http.Response, error) { //nolint:lll,dupl
 775  	url := fmt.Sprintf("%s/%s/robots", vcrPath, vcrID)
 776  
 777  	req, err := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 778  	if err != nil {
 779  		return nil, nil, nil, err
 780  	}
 781  
 782  	qStrings, err := query.Values(options)
 783  	if err != nil {
 784  		return nil, nil, nil, err
 785  	}
 786  
 787  	req.URL.RawQuery = qStrings.Encode()
 788  
 789  	bots := new(containerRegistryRobotsBase)
 790  
 791  	resp, err := h.client.DoWithContext(ctx, req, &bots)
 792  	if err != nil {
 793  		return nil, nil, resp, err
 794  	}
 795  
 796  	return bots.Robots, bots.Meta, resp, nil
 797  }
 798  
 799  func (h *ContainerRegistryServiceHandler) GetRobot(ctx context.Context, vcrID, robotName string) (*ContainerRegistryRobot, *http.Response, error) { //nolint:lll
 800  	url := fmt.Sprintf("%s/%s/robot/%s", vcrPath, vcrID, robotName)
 801  
 802  	req, err := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 803  	if err != nil {
 804  		return nil, nil, err
 805  	}
 806  
 807  	bot := new(ContainerRegistryRobot)
 808  
 809  	resp, err := h.client.DoWithContext(ctx, req, &bot)
 810  	if err != nil {
 811  		return nil, resp, err
 812  	}
 813  
 814  	return bot, resp, nil
 815  }
 816  
 817  func (h *ContainerRegistryServiceHandler) UpdateRobot(ctx context.Context, vcrID, robotName string, updateReq *ContainerRegistryRobotReq) (*ContainerRegistryRobot, *http.Response, error) { //nolint:lll
 818  	url := fmt.Sprintf("%s/%s/robot/%s", vcrPath, vcrID, robotName)
 819  
 820  	req, err := h.client.NewRequest(ctx, http.MethodPut, url, updateReq)
 821  	if err != nil {
 822  		return nil, nil, err
 823  	}
 824  
 825  	bot := new(ContainerRegistryRobot)
 826  
 827  	resp, err := h.client.DoWithContext(ctx, req, &bot)
 828  	if err != nil {
 829  		return nil, resp, err
 830  	}
 831  
 832  	return bot, resp, nil
 833  }
 834  
 835  func (h *ContainerRegistryServiceHandler) DeleteRobot(ctx context.Context, vcrID, robotName string) error {
 836  	url := fmt.Sprintf("%s/%s/robot/%s", vcrPath, vcrID, robotName)
 837  
 838  	req, err := h.client.NewRequest(ctx, http.MethodDelete, url, nil)
 839  	if err != nil {
 840  		return err
 841  	}
 842  
 843  	if _, err := h.client.DoWithContext(ctx, req, nil); err != nil {
 844  		return err
 845  	}
 846  
 847  	return nil
 848  }
 849  
 850  func (h *ContainerRegistryServiceHandler) ListArtifacts(ctx context.Context, vcrID, imageName string, options *ListOptions) ([]ContainerRegistryArtifact, *Meta, *http.Response, error) { //nolint:lll,dupl
 851  	url := fmt.Sprintf("%s/%s/repository/%s/artifacts", vcrPath, vcrID, imageName)
 852  
 853  	req, err := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 854  	if err != nil {
 855  		return nil, nil, nil, err
 856  	}
 857  
 858  	qStrings, err := query.Values(options)
 859  	if err != nil {
 860  		return nil, nil, nil, err
 861  	}
 862  
 863  	req.URL.RawQuery = qStrings.Encode()
 864  
 865  	artifacts := new(containerRegistryArtifactsBase)
 866  
 867  	resp, err := h.client.DoWithContext(ctx, req, &artifacts)
 868  	if err != nil {
 869  		return nil, nil, resp, err
 870  	}
 871  
 872  	return artifacts.Artifacts, artifacts.Meta, resp, nil
 873  }
 874  
 875  func (h *ContainerRegistryServiceHandler) GetArtifact(ctx context.Context, vcrID, imageName, artifactDigest string) (*ContainerRegistryArtifact, *http.Response, error) { //nolint:lll
 876  	url := fmt.Sprintf("%s/%s/repository/%s/artifact/%s", vcrPath, vcrID, imageName, artifactDigest)
 877  
 878  	req, err := h.client.NewRequest(ctx, http.MethodGet, url, nil)
 879  	if err != nil {
 880  		return nil, nil, err
 881  	}
 882  
 883  	artifact := new(ContainerRegistryArtifact)
 884  
 885  	resp, err := h.client.DoWithContext(ctx, req, &artifact)
 886  	if err != nil {
 887  		return nil, resp, err
 888  	}
 889  
 890  	return artifact, resp, nil
 891  }
 892  
 893  func (h *ContainerRegistryServiceHandler) DeleteArtifact(ctx context.Context, vcrID, imageName, artifactDigest string) error {
 894  	url := fmt.Sprintf("%s/%s/repository/%s/artifact/%s", vcrPath, vcrID, imageName, artifactDigest)
 895  
 896  	req, err := h.client.NewRequest(ctx, http.MethodDelete, url, nil)
 897  	if err != nil {
 898  		return err
 899  	}
 900  
 901  	if _, err := h.client.DoWithContext(ctx, req, nil); err != nil {
 902  		return err
 903  	}
 904  
 905  	return nil
 906  }
 907  
 908  // CreateDockerCredentials will create new Docker credentials used by the
 909  // Docker CLI
 910  func (h *ContainerRegistryServiceHandler) CreateDockerCredentials(ctx context.Context, vcrID string, createOptions *DockerCredentialsOpt) (*ContainerRegistryDockerCredentials, *http.Response, error) { //nolint:lll
 911  	url := fmt.Sprintf("%s/%s/docker-credentials", vcrPath, vcrID)
 912  	req, errReq := h.client.NewRequest(ctx, http.MethodOptions, url, nil)
 913  	if errReq != nil {
 914  		return nil, nil, errReq
 915  	}
 916  
 917  	queryParam := req.URL.Query()
 918  	if createOptions.ExpirySeconds != nil {
 919  		queryParam.Add("expiry_seconds", fmt.Sprintf("%d", createOptions.ExpirySeconds))
 920  	}
 921  
 922  	if createOptions.WriteAccess != nil {
 923  		queryParam.Add("read_write", fmt.Sprintf("%t", *createOptions.WriteAccess))
 924  	}
 925  
 926  	req.URL.RawQuery = queryParam.Encode()
 927  
 928  	creds := new(ContainerRegistryDockerCredentials)
 929  	resp, errResp := h.client.DoWithContext(ctx, req, &creds)
 930  	if errResp != nil {
 931  		return nil, nil, errResp
 932  	}
 933  
 934  	return creds, resp, nil
 935  }
 936  
 937  // ListRegions will return a list of regions relevant to the container registry
 938  // API operations
 939  func (h *ContainerRegistryServiceHandler) ListRegions(ctx context.Context) ([]ContainerRegistryRegion, *Meta, *http.Response, error) {
 940  	req, errReq := h.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/region/list", vcrPath), nil)
 941  	if errReq != nil {
 942  		return nil, nil, nil, errReq
 943  	}
 944  
 945  	vcrRegions := new(containerRegistryRegions)
 946  	resp, errResp := h.client.DoWithContext(ctx, req, &vcrRegions)
 947  	if errResp != nil {
 948  		return nil, nil, resp, errResp
 949  	}
 950  
 951  	return vcrRegions.Regions, vcrRegions.Meta, resp, nil
 952  }
 953  
 954  // ListPlans returns a list of plans relevant to the container registry
 955  // offerings
 956  func (h *ContainerRegistryServiceHandler) ListPlans(ctx context.Context) (*ContainerRegistryPlans, *http.Response, error) {
 957  	req, errReq := h.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/plan/list", vcrPath), nil)
 958  	if errReq != nil {
 959  		return nil, nil, errReq
 960  	}
 961  
 962  	vcrPlans := new(ContainerRegistryPlans)
 963  	resp, errResp := h.client.DoWithContext(ctx, req, &vcrPlans)
 964  	if errResp != nil {
 965  		return nil, resp, errResp
 966  	}
 967  
 968  	return vcrPlans, resp, nil
 969  }
 970