github.com/sacloud/libsacloud/v2@v2.32.3/helper/builder/registry/builder.go (about)

     1  // Copyright 2016-2022 The Libsacloud Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package registry
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  
    21  	"github.com/sacloud/libsacloud/v2/sacloud"
    22  	"github.com/sacloud/libsacloud/v2/sacloud/types"
    23  )
    24  
    25  // Builder コンテナレジストリのセットアップを行う
    26  type Builder struct {
    27  	Name           string
    28  	Description    string
    29  	Tags           types.Tags
    30  	IconID         types.ID
    31  	VirtualDomain  string
    32  	AccessLevel    types.EContainerRegistryAccessLevel
    33  	SubDomainLabel string
    34  	Users          []*User
    35  
    36  	SettingsHash string
    37  	Client       *APIClient
    38  }
    39  
    40  // User ユーザー
    41  type User struct {
    42  	UserName   string
    43  	Password   string
    44  	Permission types.EContainerRegistryPermission
    45  }
    46  
    47  // Validate 値の検証
    48  func (b *Builder) Validate(ctx context.Context) error {
    49  	if b.SubDomainLabel == "" {
    50  		return fmt.Errorf("name prefix is required")
    51  	}
    52  	return nil
    53  }
    54  
    55  // Build コンテナレジストリの作成
    56  func (b *Builder) Build(ctx context.Context) (*sacloud.ContainerRegistry, error) {
    57  	if err := b.Validate(ctx); err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	reg, err := b.Client.ContainerRegistry.Create(ctx, &sacloud.ContainerRegistryCreateRequest{
    62  		Name:           b.Name,
    63  		Description:    b.Description,
    64  		Tags:           b.Tags,
    65  		IconID:         b.IconID,
    66  		AccessLevel:    b.AccessLevel,
    67  		SubDomainLabel: b.SubDomainLabel,
    68  		VirtualDomain:  b.VirtualDomain,
    69  	})
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	// add users
    75  	for _, user := range b.Users {
    76  		u := &sacloud.ContainerRegistryUserCreateRequest{
    77  			UserName:   user.UserName,
    78  			Password:   user.Password,
    79  			Permission: user.Permission,
    80  		}
    81  		if err := b.Client.ContainerRegistry.AddUser(ctx, reg.ID, u); err != nil {
    82  			return reg, err
    83  		}
    84  	}
    85  
    86  	return reg, nil
    87  }
    88  
    89  // Update コンテナレジストリの更新
    90  func (b *Builder) Update(ctx context.Context, id types.ID) (*sacloud.ContainerRegistry, error) {
    91  	if err := b.Validate(ctx); err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	// check exists
    96  	_, err := b.Client.ContainerRegistry.Read(ctx, id)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	_, err = b.Client.ContainerRegistry.Update(ctx, id, &sacloud.ContainerRegistryUpdateRequest{
   102  		Name:          b.Name,
   103  		Description:   b.Description,
   104  		Tags:          b.Tags,
   105  		IconID:        b.IconID,
   106  		AccessLevel:   b.AccessLevel,
   107  		VirtualDomain: b.VirtualDomain,
   108  		SettingsHash:  b.SettingsHash,
   109  	})
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	// reconcile user
   115  	added, updated, deleted, err := b.collectUserUpdates(ctx, id)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	// added
   120  	for _, user := range added {
   121  		u := &sacloud.ContainerRegistryUserCreateRequest{
   122  			UserName:   user.UserName,
   123  			Password:   user.Password,
   124  			Permission: user.Permission,
   125  		}
   126  		if err := b.Client.ContainerRegistry.AddUser(ctx, id, u); err != nil {
   127  			return nil, err
   128  		}
   129  	}
   130  	// updated
   131  	for _, user := range updated {
   132  		u := &sacloud.ContainerRegistryUserUpdateRequest{
   133  			Password:   user.Password,
   134  			Permission: user.Permission,
   135  		}
   136  		err := b.Client.ContainerRegistry.UpdateUser(ctx, id, user.UserName, u)
   137  		if err != nil {
   138  			return nil, err
   139  		}
   140  	}
   141  	// deleted
   142  	for _, u := range deleted {
   143  		if err := b.Client.ContainerRegistry.DeleteUser(ctx, id, u.UserName); err != nil {
   144  			return nil, err
   145  		}
   146  	}
   147  
   148  	// reload
   149  	reg, err := b.Client.ContainerRegistry.Read(ctx, id)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	return reg, nil
   154  }
   155  
   156  func (b *Builder) collectUserUpdates(ctx context.Context, id types.ID) (added, updated, deleted []*User, e error) {
   157  	searched, err := b.Client.ContainerRegistry.ListUsers(ctx, id)
   158  	if err != nil {
   159  		e = err
   160  		return
   161  	}
   162  	users := searched.Users
   163  
   164  	// added/updated
   165  	for _, desired := range b.Users {
   166  		isExists := false
   167  		for _, current := range users {
   168  			if desired.UserName == current.UserName {
   169  				updated = append(updated, desired)
   170  				isExists = true
   171  				break
   172  			}
   173  		}
   174  		if !isExists {
   175  			added = append(added, desired)
   176  		}
   177  	}
   178  	// deleted
   179  	for _, current := range users {
   180  		isExists := false
   181  		for _, desired := range b.Users {
   182  			if desired.UserName == current.UserName {
   183  				isExists = true
   184  				break
   185  			}
   186  		}
   187  		if !isExists {
   188  			deleted = append(deleted, &User{
   189  				UserName: current.UserName,
   190  			})
   191  		}
   192  	}
   193  	return added, updated, deleted, nil
   194  }