- 
                Notifications
    
You must be signed in to change notification settings  - Fork 226
 
          Generate resource identifiers from ReadOne or ReadMany
          #105
        
          New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
ae4682e
              8413c3a
              8255972
              32ef02e
              cd53dbc
              4f3a2a7
              3b95cb3
              f287df2
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -317,7 +317,6 @@ func SetResource( | |
| return out | ||
| } | ||
| 
     | 
||
| 
     | 
||
| func ListMemberNameInReadManyOutput( | ||
| r *model.CRD, | ||
| ) string { | ||
| 
          
            
          
           | 
    @@ -770,6 +769,158 @@ func SetResourceGetAttributes( | |
| return out | ||
| } | ||
| 
     | 
||
| func SetResourceIdentifiers( | ||
| cfg *ackgenconfig.Config, | ||
| r *model.CRD, | ||
| // String representing the name of the variable that we will grab the Input | ||
| // shape from. This will likely be "identifier" since in the templates that | ||
| // call this method, the "source variable" is the CRD struct which is used | ||
| // to populate the target variable, which is the struct of unique | ||
| // identifiers | ||
| sourceVarName string, | ||
| // String representing the name of the variable that we will be **setting** | ||
| // with values we get from the Output shape. This will likely be | ||
| // "r.ko" since that is the name of the "target variable" that the | ||
| // templates that call this method use for the Input shape. | ||
| targetVarName string, | ||
| // Number of levels of indentation to use | ||
| indentLevel int, | ||
| ) string { | ||
| op := r.Ops.ReadOne | ||
| if op == nil { | ||
| // If single lookups can only be done using ReadMany | ||
| op = r.Ops.ReadMany | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
| inputShape := op.InputRef.Shape | ||
| if inputShape == nil { | ||
| return "" | ||
| } | ||
| 
     | 
||
| primaryKeyOut := "\n" | ||
| arnOut := "" | ||
| additionalKeyOut := "\n" | ||
| 
     | 
||
| indent := strings.Repeat("\t", indentLevel) | ||
| 
     | 
||
| primaryKeyOut += fmt.Sprintf("%sif %s.NameOrID == nil {\n", indent, sourceVarName) | ||
| primaryKeyOut += fmt.Sprintf("%s\treturn ackerrors.MissingNameIdentifier\n", indent) | ||
| primaryKeyOut += fmt.Sprintf("%s}\n", indent) | ||
| 
     | 
||
| primaryIdentifier := "" | ||
| 
     | 
||
| // Attempt to fetch the primary identifier from the configuration | ||
| opConfig, ok := cfg.Operations[op.Name] | ||
| if ok { | ||
| primaryIdentifier = opConfig.PrimaryIdentifierFieldName | ||
| } | ||
| 
     | 
||
| // Determine the "primary identifier" based on the names of each field | ||
| if primaryIdentifier == "" { | ||
| primaryIdentifierLookup := []string{ | ||
| "Name", | ||
| r.Names.Original + "Name", | ||
| r.Names.Original + "Id", | ||
| } | ||
| 
     | 
||
| for _, memberName := range inputShape.MemberNames() { | ||
| if util.InStrings(memberName, primaryIdentifierLookup) { | ||
| primaryIdentifier = memberName | ||
| } | ||
| } | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| // Still haven't determined the identifier? Panic | ||
| if primaryIdentifier == "" { | ||
| panic("Could not find primary identifier for " + r.Names.Original + | ||
| ". Set `primary_identifier_field_name` for the " + op.Name + | ||
| " operation in the generator config.") | ||
| } | ||
| } | ||
| 
     | 
||
| paginatorFieldLookup := []string{ | ||
| "NextToken", | ||
| "MaxResults", | ||
| } | ||
| 
     | 
||
| additionalKeyCount := 0 | ||
| for _, memberName := range inputShape.MemberNames() { | ||
| if r.UnpacksAttributesMap() && memberName == "Attributes" { | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| continue | ||
| } | ||
| 
     | 
||
| if util.InStrings(memberName, paginatorFieldLookup) { | ||
| continue | ||
| } | ||
| 
     | 
||
| memberShapeRef, _ := inputShape.MemberRefs[memberName] | ||
| memberShape := memberShapeRef.Shape | ||
| 
     | 
||
| // Only strings are currently accepted as valid inputs for | ||
| // additional key fields | ||
| if memberShape.Type != "string" { | ||
| continue | ||
| } | ||
| 
     | 
||
| if r.IsSecretField(memberName) { | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| panic("Secrets cannot be used as fields in identifiers") | ||
| } | ||
| 
     | 
||
| if r.IsPrimaryARNField(memberName) { | ||
| // r.ko.Status.ACKResourceMetadata.ARN = identifier.ARN | ||
| arnOut += fmt.Sprintf( | ||
| "\n%s%s.Status.ACKResourceMetadata.ARN = %s.ARN\n", | ||
| indent, targetVarName, sourceVarName, | ||
| ) | ||
| continue | ||
| 
     | 
||
| } | ||
| 
     | 
||
| isPrimaryIdentifier := memberName == primaryIdentifier | ||
| cleanMemberNames := names.New(memberName) | ||
| cleanMemberName := cleanMemberNames.Camel | ||
| 
     | 
||
| memberPath := "" | ||
| _, inSpec := r.SpecFields[memberName] | ||
| _, inStatus := r.StatusFields[memberName] | ||
| if inSpec { | ||
| memberPath = "Spec" | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| } else if inStatus { | ||
| memberPath = "Status" | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| } else if isPrimaryIdentifier { | ||
| panic("Primary identifier field '" + memberName + "' cannot be set in either spec or status.") | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| } else { | ||
| continue | ||
| } | ||
                
      
                  RedbackThomson marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| if isPrimaryIdentifier { | ||
| // r.ko.Status.BrokerID = identifier.NameOrID | ||
| primaryKeyOut += fmt.Sprintf("%s%s.%s.%s = %s.NameOrID\n", indent, targetVarName, memberPath, cleanMemberName, sourceVarName) | ||
| } else { | ||
| // f0, f0ok := identifier.AdditionalKeys["scalableDimension"] | ||
| 
         There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did we plan to support case-insensitive lookups? Because if the  I think we should probably support case-insensitive key lookups here. Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All other fields in the k8s spec are lowerCamelCased, I am trying to make the  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @RedbackThomson yeah, I guess that's a fair point. I just worry that without the TODO below on line 953 being implemented, that simple typos here will be quite difficult to detect. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah totally understandable. A typo in an   | 
||
| // if f0ok { | ||
| // r.ko.Spec.ScalableDimension = f0 | ||
| // } | ||
| 
     | 
||
| fieldIndexName := fmt.Sprintf("f%d", additionalKeyCount) | ||
| sourceAdaptedVarName := fmt.Sprintf("%s.AdditionalKeys[\"%s\"]", sourceVarName, cleanMemberNames.CamelLower) | ||
| 
     | 
||
| // TODO(RedbackThomson): If the identifiers don't exist, we should be | ||
| // throwing an error accessible to the user | ||
| additionalKeyOut += fmt.Sprintf("%s%s, %sok := %s\n", indent, fieldIndexName, fieldIndexName, sourceAdaptedVarName) | ||
| additionalKeyOut += fmt.Sprintf("%sif %sok {\n", indent, fieldIndexName) | ||
| additionalKeyOut += fmt.Sprintf("%s\t%s.%s.%s = %s\n", indent, targetVarName, memberPath, cleanMemberName, fieldIndexName) | ||
| additionalKeyOut += fmt.Sprintf("%s}\n", indent) | ||
| 
     | 
||
| additionalKeyCount++ | ||
| } | ||
| } | ||
| 
     | 
||
| // Only use at most one of ARN or nameOrID as primary identifier outputs | ||
| if arnOut != "" { | ||
| return arnOut + additionalKeyOut | ||
| } | ||
| return primaryKeyOut + additionalKeyOut | ||
| } | ||
| 
     | 
||
| // setResourceForContainer returns a string of Go code that sets the value of a | ||
| // target variable to that of a source variable. When the source variable type | ||
| // is a map, struct or slice type, then this function is called recursively on | ||
| 
          
            
          
           | 
    ||
Uh oh!
There was an error while loading. Please reload this page.