Skip to content

Commit

Permalink
Merge pull request #64 from NetApp/integration/main
Browse files Browse the repository at this point in the history
Sync bitbucket and GitHub
  • Loading branch information
wenjun666 authored Aug 23, 2021
2 parents 3c87313 + b88422d commit 998a9d2
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 13 deletions.
99 changes: 95 additions & 4 deletions cloudmanager/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ func (c *Client) CallAWSInstanceCreate(occmDetails createOCCMDetails) (string, e
tags = append(tags, tag)
}
}

// Specify the details of the instance that you want to create.
runInstancesInput := &ec2.RunInstancesInput{
BlockDeviceMappings: []*ec2.BlockDeviceMapping{
Expand Down Expand Up @@ -465,8 +464,6 @@ func (c *Client) CallAMIGet(occmDetails createOCCMDetails) (string, error) {
}
}

log.Print("CallAMIGet ", *result)

return latestAMI, nil
}

Expand Down Expand Up @@ -545,7 +542,21 @@ func (c *Client) CallVNetGetCidr(subscriptionID string, resourceGroup string, vn

// CallAWSInstanceGet can be used to make a request to get AWS Instance
func (c *Client) CallAWSInstanceGet(occmDetails createOCCMDetails) ([]ec2.Instance, error) {

if occmDetails.Region == "" {
regions, err := c.CallAWSRegionGet(occmDetails)
if err != nil {
return nil, err
}
var res []ec2.Instance
for _, region := range regions {
regionReservation, err := c.CallAWSGetReservationsForRegion(region)
if err != nil {
return nil, err
}
res = append(res, regionReservation...)
}
return res, nil
}
sess := session.Must(session.NewSession(aws.NewConfig().WithRegion(occmDetails.Region)))
svc := ec2.New(sess)
input := &ec2.DescribeInstancesInput{
Expand Down Expand Up @@ -598,6 +609,30 @@ func (c *Client) CallAWSInstanceGet(occmDetails createOCCMDetails) ([]ec2.Instan
return res, nil
}

// CallAWSRegionGet describe all regions.
func (c *Client) CallAWSRegionGet(occmDetails createOCCMDetails) ([]string, error) {
sess := session.Must(session.NewSession())
svc := ec2.New(sess)

result, err := svc.DescribeRegions(nil)
if err != nil {
log.Printf("CallAWSRegionGet error: %#v", err)
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
return nil, aerr
}
}
return nil, err
}

var res []string
for _, region := range result.Regions {
res = append(res, *region.RegionName)
}
return res, nil
}

// CallAPIMethod can be used to make a request to any CVO/OCCM API method, receiving results as byte
func (c *Client) CallAPIMethod(method string, baseURL string, params map[string]interface{}, token string, hostType string) (int, []byte, string, error) {
c.initOnce.Do(c.init)
Expand Down Expand Up @@ -748,3 +783,59 @@ func (c *Client) CallAWSTagDelete(occmDetails createOCCMDetails) error {
fmt.Println(result)
return nil
}

// CallAWSDescribeInstanceAttribute returns disableAPITermination.
func (c *Client) CallAWSDescribeInstanceAttribute(occmDetails createOCCMDetails) (bool, error) {
sess := session.Must(session.NewSession(aws.NewConfig().WithRegion(occmDetails.Region)))
svc := ec2.New(sess)
input := &ec2.DescribeInstanceAttributeInput{
Attribute: aws.String("disableApiTermination"),
InstanceId: aws.String(occmDetails.InstanceID),
}

result, err := svc.DescribeInstanceAttribute(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
return false, aerr
}
}
return false, err
}
disableAPITermination := *result.DisableApiTermination.Value
if err != nil {
return false, err
}

return disableAPITermination, nil
}

// CallAWSGetReservationsForRegion gets reservations for a region.
func (c *Client) CallAWSGetReservationsForRegion(region string) ([]ec2.Instance, error) {

var res []ec2.Instance

sess := session.Must(session.NewSession(aws.NewConfig().WithRegion(region)))
svc := ec2.New(sess)
input := &ec2.DescribeInstancesInput{}

result, err := svc.DescribeInstances(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
default:
return nil, aerr
}
}
return nil, err
}

for _, reservation := range result.Reservations {
for _, instance := range reservation.Instances {
res = append(res, *instance)
}
}

return res, err
}
37 changes: 31 additions & 6 deletions cloudmanager/occm_aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"time"

"github.com/aws/aws-sdk-go/service/ec2"
"github.com/fatih/structs"
)

Expand Down Expand Up @@ -365,26 +366,25 @@ func (c *Client) createAWSInstance(occmDetails createOCCMDetails) (string, error
return instanceID, nil
}

func (c *Client) getAWSInstance(occmDetails createOCCMDetails, id string) (createOCCMDetails, error) {
func (c *Client) getAWSInstance(occmDetails createOCCMDetails, id string) (ec2.Instance, error) {

log.Print("getAWSInstance")

res, err := c.CallAWSInstanceGet(occmDetails)
returnOCCM := createOCCMDetails{}
if err != nil {
return createOCCMDetails{}, err
return ec2.Instance{}, nil
}
log.Printf("getAWSInstance result: %#v", res)
for _, instance := range res {
if *instance.InstanceId == id {
returnOCCM.AMI = *instance.ImageId
returnOCCM.InstanceID = *instance.InstanceId
returnOCCM.InstanceType = *instance.InstanceType
return returnOCCM, nil
return instance, nil
}
}

return createOCCMDetails{}, nil
return ec2.Instance{}, nil
}

func (c *Client) createOCCM(occmDetails createOCCMDetails, proxyCertificates []string) (OCCMMResult, error) {
Expand Down Expand Up @@ -438,7 +438,6 @@ func (c *Client) checkOCCMStatus() (occmAgent, error) {
baseURL := fmt.Sprintf("/agents-mgmt/agent/%sclients", c.ClientID)

hostType := "CloudManagerHost"

statusCode, response, _, err := c.CallAPIMethod("GET", baseURL, nil, c.Token, hostType)
if err != nil {
log.Print("checkOCCMStatus request failed ", statusCode)
Expand Down Expand Up @@ -572,3 +571,29 @@ func (c *Client) updateOCCM(occmDetails createOCCMDetails, proxyCertificates []s

return nil
}

func (c *Client) getCompany() (string, error) {
if c.Token == "" {
accesTokenResult, err := c.getAccessToken()
if err != nil {
return "", err
}
c.Token = accesTokenResult.Token
}
hostType := "CloudManagerHost"
baseURL := "/occm/api/occm/system/about"
statusCode, response, _, err := c.CallAPIMethod("GET", baseURL, nil, c.Token, hostType)
if err != nil {
log.Print("getCompany request failed ", statusCode)
return "", err
}
responseError := apiResponseChecker(statusCode, response, "getCompany")
if responseError != nil {
return "", responseError
}
var f interface{}
json.Unmarshal(response, &f)
m := f.(map[string]interface{})
siteIdentifier := m["siteIdentifier"].(map[string]interface{})
return siteIdentifier["company"].(string), nil
}
83 changes: 80 additions & 3 deletions cloudmanager/resource_netapp_cloudmanager_connector_aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"log"
"strings"

"github.com/hashicorp/terraform/helper/schema"
)
Expand All @@ -17,7 +18,7 @@ func resourceOCCMAWS() *schema.Resource {
Exists: resourceOCCMAWSExists,
Update: resourceOCCMAWSUpdate,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
State: resourceOCCMAWSImport,
},

Schema: map[string]*schema.Schema{
Expand Down Expand Up @@ -256,10 +257,73 @@ func resourceOCCMAWSRead(d *schema.ResourceData, meta interface{}) error {
return err
}

if res.InstanceID != id {
if *res.InstanceId != id {
return fmt.Errorf("Expected occm ID %v, Response could not find", id)
}

if occmDetails.Region == "" {
occmDetails.Region = *res.Placement.AvailabilityZone
occmDetails.Region = occmDetails.Region[:len(occmDetails.Region)-1]
d.Set("region", occmDetails.Region)
}
occmDetails.InstanceID = *res.InstanceId
disableAPITermination, err := client.CallAWSDescribeInstanceAttribute(occmDetails)
if err != nil {
return err
}
d.Set("enable_termination_protection", disableAPITermination)
d.Set("instance_type", res.InstanceType)
d.Set("subnet_id", res.SubnetId)
d.Set("security_group_id", res.SecurityGroups[0].GroupId)
d.Set("key_name", res.KeyName)
iamInstanceProfile := *res.IamInstanceProfile.Arn
slashIndex := strings.Index(iamInstanceProfile, "/")
iamInstanceProfile = iamInstanceProfile[slashIndex+1:]
d.Set("iam_instance_profile_name", iamInstanceProfile)
if _, ok := d.GetOk("ami"); ok {
d.Set("ami", res.ImageId)
}
// The following tags are ignored.
excludedTags := [...]string{"Name", "OCCMInstance", "Owner", "PrincipalId"}
tags := make([]map[string]string, 0)
for _, tag := range res.Tags {
var exclusion bool
for _, exTag := range excludedTags {
if *tag.Key == exTag {
exclusion = true
}
}
if exclusion == false {
tagMap := make(map[string]string)
tagMap["tag_key"] = *tag.Key
tagMap["tag_value"] = *tag.Value
tags = append(tags, tagMap)
}
if *tag.Key == "Name" {
d.Set("name", *tag.Value)
}
}
d.Set("aws_tag", tags)

if res.PublicIpAddress == nil {
d.Set("associate_public_ip_address", false)
} else {
d.Set("associate_public_ip_address", true)
}

if v, ok := d.GetOk("client_id"); ok {
client.ClientID = v.(string)
}

if _, ok := d.GetOk("company"); !ok {
company, err := client.getCompany()
if err != nil {
log.Printf("Error when reading system info from cloudmanager.")
return err
}
d.Set("company", company)
}

return nil
}

Expand Down Expand Up @@ -310,7 +374,7 @@ func resourceOCCMAWSExists(d *schema.ResourceData, meta interface{}) (bool, erro
return false, err
}

if res.InstanceID != id {
if *res.InstanceId != id {
d.SetId("")
return false, nil
}
Expand Down Expand Up @@ -360,3 +424,16 @@ func resourceOCCMAWSUpdate(d *schema.ResourceData, meta interface{}) error {
}
return nil
}

func resourceOCCMAWSImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), ":")
if len(parts) != 2 {
return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'client_id/connector_id'", d.Id())
}

d.SetId(parts[1])
d.Set("client_id", parts[0])

return []*schema.ResourceData{d}, nil

}
3 changes: 3 additions & 0 deletions website/docs/r/connector_aws.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,6 @@ The following attributes are exported in addition to the arguments listed above:

With netapp-cloudmanager_connector_aws, every resource has a unique ID, but names are not necessarily unique.

## Connector Import
The id used to import is constructed with two attributes: client id and connector id. The format is CLIENT_ID:CONNECTOR_ID

0 comments on commit 998a9d2

Please sign in to comment.