github.com/sacloud/iaas-api-go@v1.12.0/fake/functions.go (about)

     1  // Copyright 2022-2023 The sacloud/iaas-api-go 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 fake
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"math/rand"
    21  	"net/http"
    22  	"reflect"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/sacloud/iaas-api-go"
    27  	"github.com/sacloud/iaas-api-go/accessor"
    28  	"github.com/sacloud/iaas-api-go/search"
    29  	"github.com/sacloud/iaas-api-go/types"
    30  )
    31  
    32  func init() {
    33  	rand.Seed(time.Now().UnixNano())
    34  }
    35  
    36  func random(max int) int {
    37  	return rand.Intn(max) //nolint:gosec
    38  }
    39  
    40  func newErrorNotFound(resourceKey string, id interface{}) error {
    41  	return iaas.NewAPIError("", nil, http.StatusNotFound, &iaas.APIErrorResponse{
    42  		IsFatal:      true,
    43  		Serial:       "",
    44  		Status:       "404 NotFound",
    45  		ErrorCode:    fmt.Sprintf("%d", http.StatusNotFound),
    46  		ErrorMessage: fmt.Sprintf("%s[ID:%s] is not found", resourceKey, id),
    47  	})
    48  }
    49  
    50  func newErrorBadRequest(resourceKey string, id interface{}, msgs ...string) error {
    51  	return iaas.NewAPIError("", nil, http.StatusBadRequest, &iaas.APIErrorResponse{
    52  		IsFatal:      true,
    53  		Serial:       "",
    54  		Status:       "400 BadRequest",
    55  		ErrorCode:    fmt.Sprintf("%d", http.StatusBadRequest),
    56  		ErrorMessage: fmt.Sprintf("request to %s[ID:%s] is bad: %s", resourceKey, id, strings.Join(msgs, " ")),
    57  	})
    58  }
    59  
    60  func newErrorConflict(resourceKey string, id interface{}, msgs ...string) error {
    61  	return iaas.NewAPIError("", nil, http.StatusConflict, &iaas.APIErrorResponse{
    62  		IsFatal:      true,
    63  		Serial:       "",
    64  		Status:       "409 Conflict",
    65  		ErrorCode:    fmt.Sprintf("%d", http.StatusConflict),
    66  		ErrorMessage: fmt.Sprintf("request to %s[ID:%s] is conflicted: %s", resourceKey, id, strings.Join(msgs, " ")),
    67  	})
    68  }
    69  
    70  func newInternalServerError(resourceKey string, id interface{}, msgs ...string) error {
    71  	return iaas.NewAPIError("", nil, http.StatusInternalServerError, &iaas.APIErrorResponse{
    72  		IsFatal:      true,
    73  		Serial:       "",
    74  		Status:       "500 Internal Server Error",
    75  		ErrorCode:    fmt.Sprintf("%d", http.StatusInternalServerError),
    76  		ErrorMessage: fmt.Sprintf("request to %s[ID:%s] is failed: %s", resourceKey, id, strings.Join(msgs, " ")),
    77  	})
    78  }
    79  
    80  func find(resourceKey, zone string, conditions *iaas.FindCondition) ([]interface{}, error) {
    81  	var results []interface{}
    82  	if conditions == nil {
    83  		conditions = &iaas.FindCondition{}
    84  	}
    85  
    86  	targets := ds().List(resourceKey, zone)
    87  
    88  FILTER_APPLY_LOOP:
    89  	for i, target := range targets {
    90  		// count
    91  		if conditions.Count != 0 && len(results) >= conditions.Count {
    92  			break
    93  		}
    94  
    95  		// from
    96  		if i < conditions.From {
    97  			continue
    98  		}
    99  
   100  		// filter
   101  		for key, expression := range conditions.Filter {
   102  			// TODO OpGreater/OpLess is not implemented
   103  			if key.Op == search.OpEqual {
   104  				fieldName := key.String()
   105  
   106  				// only ID/Name/Tags
   107  				switch fieldName {
   108  				case "ID", "Name", "Tags.Name", "Scope", "Class":
   109  					exp, ok := expression.(*search.EqualExpression)
   110  					if !ok {
   111  						exp = search.OrEqual(expression)
   112  					}
   113  
   114  					if fieldName == "Tags.Name" {
   115  						var tags types.Tags
   116  						if v, ok := target.(accessor.Tags); ok {
   117  							tags = v.GetTags()
   118  						}
   119  
   120  						for _, cond := range exp.Conditions {
   121  							condTags, ok := cond.([]string)
   122  							if ok {
   123  								for _, v := range condTags {
   124  									exists := false
   125  									for _, tag := range tags {
   126  										if tag == v {
   127  											exists = true
   128  										}
   129  									}
   130  									if !exists {
   131  										continue FILTER_APPLY_LOOP
   132  									}
   133  								}
   134  							}
   135  						}
   136  					} else {
   137  						var value interface{}
   138  						switch fieldName {
   139  						case "ID":
   140  							if v, ok := target.(accessor.ID); ok {
   141  								value = v.GetID()
   142  							}
   143  						case "Name":
   144  							if v, ok := target.(accessor.Name); ok {
   145  								value = v.GetName()
   146  							}
   147  						case "Scope":
   148  							if v, ok := target.(accessor.Scope); ok {
   149  								value = v.GetScope().String()
   150  							}
   151  						case "Class":
   152  							if v, ok := target.(accessor.Class); ok {
   153  								value = v.GetClass()
   154  							}
   155  						}
   156  
   157  						switch exp.Op {
   158  						case search.OpAnd:
   159  							for _, v := range exp.Conditions {
   160  								v1, ok1 := v.(string)
   161  								v2, ok2 := value.(string)
   162  								if !ok1 || !ok2 || !strings.Contains(v2, v1) {
   163  									continue FILTER_APPLY_LOOP
   164  								}
   165  							}
   166  						case search.OpOr:
   167  							match := false
   168  							for _, v := range exp.Conditions {
   169  								if reflect.DeepEqual(value, v) {
   170  									match = true
   171  								}
   172  							}
   173  							if !match {
   174  								continue FILTER_APPLY_LOOP
   175  							}
   176  						}
   177  					}
   178  				}
   179  			}
   180  		}
   181  
   182  		results = append(results, target)
   183  	}
   184  
   185  	// TODO sort/filter/include/exclude is not implemented
   186  	return results, nil
   187  }
   188  
   189  func copySameNameField(source interface{}, dest interface{}) {
   190  	data, _ := json.Marshal(source)
   191  	json.Unmarshal(data, dest) //nolint
   192  }
   193  
   194  func fill(target interface{}, fillFuncs ...func(interface{})) {
   195  	for _, f := range fillFuncs {
   196  		f(target)
   197  	}
   198  }
   199  
   200  func fillID(target interface{}) {
   201  	if v, ok := target.(accessor.ID); ok {
   202  		id := v.GetID()
   203  		if id.IsEmpty() {
   204  			v.SetID(pool().generateID())
   205  		}
   206  	}
   207  }
   208  
   209  func fillAvailability(target interface{}) {
   210  	if v, ok := target.(accessor.Availability); ok {
   211  		value := v.GetAvailability()
   212  		if value == types.Availabilities.Unknown {
   213  			v.SetAvailability(types.Availabilities.Available)
   214  		}
   215  	}
   216  }
   217  
   218  func fillScope(target interface{}) {
   219  	if v, ok := target.(accessor.Scope); ok {
   220  		value := v.GetScope()
   221  		if value == types.EScope("") {
   222  			v.SetScope(types.Scopes.User)
   223  		}
   224  	}
   225  }
   226  
   227  func fillDiskPlan(target interface{}) {
   228  	if v, ok := target.(accessor.DiskPlan); ok {
   229  		id := v.GetDiskPlanID()
   230  		switch id {
   231  		case types.DiskPlans.HDD:
   232  			v.SetDiskPlanName("標準プラン")
   233  		case types.DiskPlans.SSD:
   234  			v.SetDiskPlanName("SSDプラン")
   235  		}
   236  		v.SetDiskPlanStorageClass("iscsi9999")
   237  	}
   238  }
   239  
   240  func fillCreatedAt(target interface{}) {
   241  	if v, ok := target.(accessor.CreatedAt); ok {
   242  		value := v.GetCreatedAt()
   243  		if value.IsZero() {
   244  			v.SetCreatedAt(time.Now())
   245  		}
   246  	}
   247  }
   248  
   249  func fillModifiedAt(target interface{}) {
   250  	if v, ok := target.(accessor.ModifiedAt); ok {
   251  		value := v.GetModifiedAt()
   252  		if value.IsZero() {
   253  			v.SetModifiedAt(time.Now())
   254  		}
   255  	}
   256  }