github.com/Axway/agent-sdk@v1.1.101/pkg/migrate/apisimigration.go (about)

     1  package migrate
     2  
     3  import (
     4  	"context"
     5  	"regexp"
     6  	"strconv"
     7  
     8  	apiv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
     9  	management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
    10  	"github.com/Axway/agent-sdk/pkg/apic/definitions"
    11  	"github.com/Axway/agent-sdk/pkg/config"
    12  	"github.com/Axway/agent-sdk/pkg/util"
    13  	"github.com/Axway/agent-sdk/pkg/util/log"
    14  )
    15  
    16  // APISIMigration - used for migrating API Service Instances
    17  type APISIMigration struct {
    18  	migration
    19  	logger log.FieldLogger
    20  }
    21  
    22  // NewAPISIMigration creates a new APISIMigration
    23  func NewAPISIMigration(client client, cfg config.CentralConfig) *APISIMigration {
    24  	return &APISIMigration{
    25  		migration: migration{
    26  			client: client,
    27  			cfg:    cfg,
    28  		},
    29  		logger: log.NewFieldLogger().
    30  			WithPackage("sdk.migrate").
    31  			WithComponent("instance-migration"),
    32  	}
    33  }
    34  
    35  // Migrate checks an APIServiceInstance for the "scopes" key in the schema, and removes it if it is found.
    36  func (m *APISIMigration) Migrate(ctx context.Context, ri *apiv1.ResourceInstance) (*apiv1.ResourceInstance, error) {
    37  	if ri.Kind != management.APIServiceGVK().Kind {
    38  		return ri, nil
    39  	}
    40  	logger := log.UpdateLoggerWithContext(ctx, m.logger)
    41  	logger.Trace("api service migration")
    42  
    43  	// skip migration if instance migration is not enabled
    44  	if !m.cfg.GetMigrationSettings().ShouldCleanInstances() {
    45  		return ri, nil
    46  	}
    47  
    48  	if isMigrationCompleted(ri, definitions.InstanceMigration) {
    49  		// migration ran already
    50  		logger.Debugf("service instance migration already completed")
    51  		return ri, nil
    52  	}
    53  
    54  	instances, _ := m.getInstances(ri)
    55  	logger.WithField("instances", instances).Debug("all instances")
    56  	if err := m.cleanInstances(ctx, instances); err != nil {
    57  		return ri, err
    58  	}
    59  
    60  	// mark the migration as complete
    61  	util.SetAgentDetailsKey(ri, definitions.InstanceMigration, definitions.MigrationCompleted)
    62  	return ri, m.updateRI(ri)
    63  }
    64  
    65  // getInstances gets a list of instances for the service
    66  func (m *APISIMigration) getInstances(ri *apiv1.ResourceInstance) ([]*apiv1.ResourceInstance, error) {
    67  	url := m.cfg.GetInstancesURL()
    68  	q := map[string]string{
    69  		"query": queryFuncByMetadataID(ri.Metadata.ID),
    70  	}
    71  
    72  	return m.getAllRI(url, q)
    73  }
    74  
    75  func (m *APISIMigration) cleanInstances(ctx context.Context, instances []*apiv1.ResourceInstance) error {
    76  	logger := log.NewLoggerFromContext(ctx)
    77  
    78  	logger.Tracef("cleaning instances")
    79  	type instanceNameIndex struct {
    80  		ri    *apiv1.ResourceInstance
    81  		index int
    82  	}
    83  
    84  	re := regexp.MustCompile(`([-\.a-z0-9]*)\.([0-9]*$)`)
    85  
    86  	// sort all instances into buckets based on name, removing any index number, noting the highest
    87  	toKeep := map[string]instanceNameIndex{}
    88  	for _, inst := range instances {
    89  		logger := logger.WithField(string(management.APIServiceInstanceCtx), inst.Name)
    90  		logger.Tracef("handling instances")
    91  		name := inst.Name
    92  		result := re.FindAllStringSubmatch(name, -1)
    93  		group := name
    94  		index := 0
    95  		var err error
    96  		if len(result) > 0 {
    97  			group = result[0][1]
    98  			index, err = strconv.Atoi(result[0][2])
    99  			if err != nil {
   100  				return err
   101  			}
   102  		}
   103  		logger = logger.WithField("service-group", group).WithField("instance-index", index)
   104  		logger.Tracef("parsed instance name")
   105  
   106  		keepIndex := -1
   107  		if i, ok := toKeep[group]; ok {
   108  			keepIndex = i.index
   109  		}
   110  
   111  		thisNameIndex := instanceNameIndex{
   112  			ri:    inst,
   113  			index: index,
   114  		}
   115  
   116  		if keepIndex == -1 {
   117  			logger.Trace("first instance in group")
   118  			toKeep[group] = thisNameIndex
   119  		} else if keepIndex < index {
   120  			logger.Tracef("removing previous high instance with name: %s", toKeep[group].ri.Name)
   121  			m.client.DeleteResourceInstance(toKeep[group].ri)
   122  			toKeep[group] = thisNameIndex
   123  		} else {
   124  			logger.Tracef("removing this instance")
   125  			m.client.DeleteResourceInstance(thisNameIndex.ri)
   126  		}
   127  	}
   128  
   129  	return nil
   130  }