package aakaas import ( "encoding/json" "net/http" "net/url" "time" abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" "github.com/SAP/jenkins-library/pkg/abaputils" "github.com/pkg/errors" ) // TargetVectorStatus : Status of TargetVector in AAKaaS type TargetVectorStatus string const ( // TargetVectorStatusGenerated : TargetVector is Generated (not published yet) TargetVectorStatusGenerated TargetVectorStatus = "G" // TargetVectorStatusTest : TargetVector is published for testing TargetVectorStatusTest TargetVectorStatus = "T" // TargetVectorStatusProductive : TargetVector is published for productive use TargetVectorStatusProductive TargetVectorStatus = "P" TargetVectorPublishStatusRunning TargetVectorStatus = "R" TargetVectorPublishStatusSuccess TargetVectorStatus = "S" TargetVectorPublishStatusError TargetVectorStatus = "E" ) // internal usage : Json Structure for AAKaaS Odata Service type jsonTargetVector struct { Tv *TargetVector `json:"d"` } // TargetVector : TargetVector desribes a deployble state of an ABAP product version type TargetVector struct { ID string `json:"Id"` ProductName string `json:"ProductName"` ProductVersion string `json:"ProductVersion"` SpsLevel string `json:"SpsLevel"` PatchLevel string `json:"PatchLevel"` Status string `json:"Status"` PublishStatus string `json:"PublishStatus"` Content TargetVectorCVs `json:"Content"` } // TargetVectorCV : deployable state of an software Component Version as part of an TargetVector type TargetVectorCV struct { ID string `json:"Id"` ScName string `json:"ScName"` ScVersion string `json:"ScVersion"` DeliveryPackage string `json:"DeliveryPackage"` SpLevel string `json:"SpLevel"` PatchLevel string `json:"PatchLevel"` } // TargetVectorCVs : deployable states of the software Component Versions of the product version type TargetVectorCVs struct { TargetVectorCVs []TargetVectorCV `json:"results"` } // Init : Initialize TargetVector for Creation in AAKaaS func (tv *TargetVector) InitNew(addonDescriptor *abaputils.AddonDescriptor) error { if addonDescriptor.AddonProduct == "" || addonDescriptor.AddonVersion == "" || addonDescriptor.AddonSpsLevel == "" || addonDescriptor.AddonPatchLevel == "" { return errors.New("Parameters missing. Please provide product name, version, spslevel and patchlevel") } tv.ProductName = addonDescriptor.AddonProduct tv.ProductVersion = addonDescriptor.AddonVersion tv.SpsLevel = addonDescriptor.AddonSpsLevel tv.PatchLevel = addonDescriptor.AddonPatchLevel var tvCVs []TargetVectorCV var tvCV TargetVectorCV for i := range addonDescriptor.Repositories { if addonDescriptor.Repositories[i].Name == "" || addonDescriptor.Repositories[i].Version == "" || addonDescriptor.Repositories[i].SpLevel == "" || addonDescriptor.Repositories[i].PatchLevel == "" || addonDescriptor.Repositories[i].PackageName == "" { return errors.New("Parameters missing. Please provide software component name, version, splevel, patchlevel and packagename") } tvCV.ScName = addonDescriptor.Repositories[i].Name tvCV.ScVersion = addonDescriptor.Repositories[i].Version tvCV.DeliveryPackage = addonDescriptor.Repositories[i].PackageName tvCV.SpLevel = addonDescriptor.Repositories[i].SpLevel tvCV.PatchLevel = addonDescriptor.Repositories[i].PatchLevel tvCVs = append(tvCVs, tvCV) } tv.Content.TargetVectorCVs = tvCVs return nil } // InitExisting : Initialize an already in AAKaaS existing TargetVector func (tv *TargetVector) InitExisting(ID string) { tv.ID = ID } // CreateTargetVector : Initial Creation of an TargetVector func (tv *TargetVector) CreateTargetVector(conn *abapbuild.Connector) error { conn.GetToken("/odata/aas_ocs_package") tvJSON, err := json.Marshal(tv) if err != nil { return errors.Wrap(err, "Generating Request Data for Create Target Vector failed") } appendum := "/odata/aas_ocs_package/TargetVectorSet" body, err := conn.Post(appendum, string(tvJSON)) if err != nil { return errors.Wrap(err, "Creating Target Vector in AAKaaS failed") } var jTV jsonTargetVector if err := json.Unmarshal(body, &jTV); err != nil { return errors.Wrap(err, "Unexpected AAKaaS response for create target vector: "+string(body)) } tv.ID = jTV.Tv.ID tv.Status = jTV.Tv.Status return nil } func (tv *TargetVector) PublishTargetVector(conn *abapbuild.Connector, targetVectorScope TargetVectorStatus) error { conn.GetToken("/odata/aas_ocs_package") appendum := "/odata/aas_ocs_package/PublishTargetVector?Id='" + url.QueryEscape(tv.ID) + "'&Scope='" + url.QueryEscape(string(targetVectorScope)) + "'" body, err := conn.Post(appendum, "") if err != nil { return errors.Wrap(err, "Publish Target Vector in AAKaaS failed") } var jTV jsonTargetVector if err := json.Unmarshal(body, &jTV); err != nil { return errors.Wrap(err, "Unexpected AAKaaS response for publish target vector: "+string(body)) } tv.Status = jTV.Tv.Status tv.PublishStatus = jTV.Tv.PublishStatus return nil } // GetTargetVector : Read details of the TargetVector func (tv *TargetVector) GetTargetVector(conn *abapbuild.Connector) error { if tv.ID == "" { return errors.New("Without ID no details of a targetVector can be obtained from AAKaaS") } appendum := "/odata/aas_ocs_package/TargetVectorSet('" + url.QueryEscape(tv.ID) + "')" body, err := conn.Get(appendum) if err != nil { return errors.Wrap(err, "Getting Target Vector details from AAKaaS failed") } var jTV jsonTargetVector if err := json.Unmarshal(body, &jTV); err != nil { return errors.Wrap(err, "Unexpected AAKaaS response for getting target vector details: "+string(body)) } tv.Status = jTV.Tv.Status tv.PublishStatus = jTV.Tv.PublishStatus //other fields not needed atm return nil } // PollForStatus : Poll AAKaaS until final PublishStatus reached and check if desired Status was reached func (tv *TargetVector) PollForStatus(conn *abapbuild.Connector, targetStatus TargetVectorStatus) error { timeout := time.After(conn.MaxRuntime) ticker := time.Tick(conn.PollingInterval) for { select { case <-timeout: return errors.New("Timed out (AAKaaS target Vector Status change)") case <-ticker: if err := tv.GetTargetVector(conn); err != nil { return errors.Wrap(err, "Getting TargetVector status during polling resulted in an error") } switch TargetVectorStatus(tv.PublishStatus) { case TargetVectorPublishStatusRunning: continue case TargetVectorPublishStatusSuccess: if TargetVectorStatus(tv.Status) == targetStatus { return nil } else { return errors.New("Publishing of Targetvector " + tv.ID + " resulted in state " + string(tv.Status) + "instead of expected state " + string(targetStatus)) } case TargetVectorPublishStatusError: return errors.New("Publishing of Targetvector " + tv.ID + " failed in AAKaaS") default: return errors.New("Polling returned invalid TargetVectorPublishStatus: " + string(tv.PublishStatus)) } } } } /**************** Mock Client Data ****************/ var AAKaaSHead = abapbuild.MockData{ Method: `HEAD`, Url: `/odata/aas_ocs_package`, Body: ` `, StatusCode: 200, Header: http.Header{"x-csrf-token": {"HRfJP0OhB9C9mHs2RRqUzw=="}}, } var AAKaaSTVPublishTestPost = abapbuild.MockData{ Method: `POST`, Url: `/odata/aas_ocs_package/PublishTargetVector?Id='W7Q00207512600000353'&Scope='T'`, Body: `{ "d": { "Id": "W7Q00207512600000353", "Vendor": "0000029218", "ProductName": "/DRNMSPC/PRD01", "ProductVersion": "0001", "SpsLevel": "0000", "PatchLevel": "0000", "Status": "G", "PublishStatus": "R" } }`, StatusCode: 200, } var AAKaaSTVPublishProdPost = abapbuild.MockData{ Method: `POST`, Url: `/odata/aas_ocs_package/PublishTargetVector?Id='W7Q00207512600000353'&Scope='P'`, Body: `{ "d": { "Id": "W7Q00207512600000353", "Vendor": "0000029218", "ProductName": "/DRNMSPC/PRD01", "ProductVersion": "0001", "SpsLevel": "0000", "PatchLevel": "0000", "Status": "G", "PublishStatus": "R" } }`, StatusCode: 200, } var AAKaaSGetTVPublishRunning = abapbuild.MockData{ Method: `GET`, Url: `/odata/aas_ocs_package/TargetVectorSet('W7Q00207512600000353')`, Body: `{ "d": { "Id": "W7Q00207512600000353", "Vendor": "0000029218", "ProductName": "/DRNMSPC/PRD01", "ProductVersion": "0001", "SpsLevel": "0000", "PatchLevel": "0000", "Status": "G", "PublishStatus": "R" } }`, StatusCode: 200, } var AAKaaSGetTVPublishTestSuccess = abapbuild.MockData{ Method: `GET`, Url: `/odata/aas_ocs_package/TargetVectorSet('W7Q00207512600000353')`, Body: `{ "d": { "Id": "W7Q00207512600000353", "Vendor": "0000029218", "ProductName": "/DRNMSPC/PRD01", "ProductVersion": "0001", "SpsLevel": "0000", "PatchLevel": "0000", "Status": "T", "PublishStatus": "S" } }`, StatusCode: 200, } var AAKaaSGetTVPublishProdSuccess = abapbuild.MockData{ Method: `GET`, Url: `/odata/aas_ocs_package/TargetVectorSet('W7Q00207512600000353')`, Body: `{ "d": { "Id": "W7Q00207512600000353", "Vendor": "0000029218", "ProductName": "/DRNMSPC/PRD01", "ProductVersion": "0001", "SpsLevel": "0000", "PatchLevel": "0000", "Status": "P", "PublishStatus": "S" } }`, StatusCode: 200, } var AAKaaSTVCreatePost = abapbuild.MockData{ Method: `POST`, Url: `/odata/aas_ocs_package/TargetVectorSet`, Body: `{ "d": { "Id": "W7Q00207512600000262", "Vendor": "0000203069", "ProductName": "/DRNMSPC/PRD01", "ProductVersion": "0001", "SpsLevel": "0000", "PatchLevel": "0000", "Status": "G", "Content": { "results": [ { "Id": "W7Q00207512600000262", "ScName": "/DRNMSPC/COMP01", "ScVersion": "0001", "DeliveryPackage": "SAPK-001AAINDRNMSPC", "SpLevel": "0000", "PatchLevel": "0000" } ] } } }`, StatusCode: 200, } var templateMockData = abapbuild.MockData{ Method: `GET`, Url: ``, Body: ``, StatusCode: 200, }