Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 177 additions & 18 deletions Gopkg.lock

Large diffs are not rendered by default.

128 changes: 119 additions & 9 deletions registries/adapters/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"net/url"
"strconv"

"fmt"

"github.com/automationbroker/bundle-lib/apb"
log "github.com/sirupsen/logrus"
yaml "gopkg.in/yaml.v1"
Expand All @@ -41,23 +43,70 @@ type Adapter interface {
FetchSpecs([]string) ([]*apb.Spec, error)
}

// BundleSpecLabel - label on the image that we should use to pull out the abp spec.
// BundleSpecLabel - label on the image that we should use to pull out the apb spec.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HA! nice find!

// TODO: needs to remain ansibleapp UNTIL we redo the apps in dockerhub
const BundleSpecLabel = "com.redhat.apb.spec"

// Configuration - Adapter configuration. Contains the info that the adapter
// would need to complete its request to the images.
type Configuration struct {
URL *url.URL
User string
Pass string
Org string
Runner string
Images []string
Namespaces []string
Tag string
URL *url.URL
User string
Pass string
Org string
Runner string
Images []string
Namespaces []string
Tag string
SkipVerifyTLS bool
}

type registryResponseError struct {
code int
message string
}

type imageLabel struct {
Spec string `json:"com.redhat.apb.spec"`
Runtime string `json:"com.redhat.apb.runtime"`
BundleRuntime string `json:"com.redhat.bundle.runtime"`
}

type config struct {
Label imageLabel `json:"Labels"`
Digest string `json:"digest"`
}

type manifestResponse struct {
SchemaVersion int `json:"schemaVersion"`
History []map[string]string `json:"history"`
}

type manifestConfig struct {
Config config `json:"config"`
}

func (rre *registryResponseError) Error() string {
return fmt.Sprintf("unexpected registry response code: %v message: %v", rre.code, rre.message)
}

func registryResponseHandler(resp *http.Response) ([]byte, error) {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode == http.StatusUnauthorized {
return nil, &registryResponseError{code: resp.StatusCode, message: "Unable to authenticate to the registry, registry credentials could be invalid"}
}

if resp.StatusCode != http.StatusOK {
return nil, &registryResponseError{code: resp.StatusCode, message: fmt.Sprintf("unexpected response code %v body %v", resp.StatusCode, string(body))}
}
return body, nil
}

/*
// Retrieve the spec from a registry manifest request
func imageToSpec(req *http.Request, image string) (*apb.Spec, error) {
log.Debug("Registry::imageToSpec")
Expand Down Expand Up @@ -152,6 +201,67 @@ func imageToSpec(req *http.Request, image string) (*apb.Spec, error) {

return spec, nil
}
*/

// Retrieve the spec from a manifest response
func responseToSpec(response []byte, image string) (*apb.Spec, error) {
mResp := manifestResponse{}

r := bytes.NewReader(response)
if err := json.NewDecoder(r).Decode(&mResp); err != nil {
log.Errorf("Error grabbing JSON body from manifest response: %s", err)
return nil, err
}
return configToSpec([]byte(mResp.History[0]["v1Compatibility"]), image)
}

// Retrieve the spec from manifest config
func configToSpec(config []byte, image string) (*apb.Spec, error) {
spec := &apb.Spec{}
mConf := manifestConfig{}

r := bytes.NewReader(config)
err := json.NewDecoder(r).Decode(&mConf)
if err != nil {
log.Errorf("Failed to unmarshal config object for image [%s]: %s", image, err)
return nil, err
}

// encoded spec
if mConf.Config.Label.Spec == "" {
log.Infof("Didn't find encoded Spec label. Assuming image is not APB and skipping")
return nil, nil
}

decodedSpecYaml, err := b64.StdEncoding.DecodeString(mConf.Config.Label.Spec)
if err != nil {
log.Errorf("Something went wrong decoding spec from label for '%s' : %s", image, err)
return nil, err
}
if err = yaml.Unmarshal(decodedSpecYaml, spec); err != nil {
log.Errorf("Something went wrong loading decoded spec yaml for '%s' : %s", image, err)
return nil, err
}

// prefer bundle runtime
version := mConf.Config.Label.Runtime
if mConf.Config.Label.BundleRuntime != "" {
log.Debugf("bundle runtime present using this over apb runtime")
version = mConf.Config.Label.BundleRuntime
}
spec.Runtime, err = getAPBRuntimeVersion(version)
if err != nil {
return nil, err
}

// image name to be pulled during provision
spec.Image = image

log.Debugf("Successfully converted Image %s into Spec", spec.Image)
log.Infof("adapter::configToSpec -> Image %s runtime is %d", spec.Image, spec.Runtime)

return spec, nil
}

func getAPBRuntimeVersion(version string) (int, error) {

Expand Down
20 changes: 17 additions & 3 deletions registries/adapters/dockerhub_adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,16 +222,30 @@ func (r DockerHubAdapter) loadSpec(imageName string) (*apb.Spec, error) {
if r.Config.Tag == "" {
r.Config.Tag = "latest"
}
req, err := http.NewRequest("GET", fmt.Sprintf(dockerHubManifestURL, imageName, r.Config.Tag), nil)

token, err := r.getBearerToken(imageName)
if err != nil {
return nil, err
}
token, err := r.getBearerToken(imageName)

req, err := http.NewRequest("GET", fmt.Sprintf(dockerHubManifestURL, imageName, r.Config.Tag), nil)
if err != nil {
return nil, err
}

req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
return imageToSpec(req, fmt.Sprintf("%s/%s:%s", r.RegistryName(), imageName, r.Config.Tag))
req.Header.Add("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}

body, err := registryResponseHandler(resp)
if err != nil {
return nil, fmt.Errorf("DockerHubAdapter::error handling dockerhub registery response %s", err)
}
return responseToSpec(body, fmt.Sprintf("%s/%s:%s", r.RegistryName(), imageName, r.Config.Tag))
}

func (r DockerHubAdapter) getBearerToken(imageName string) (string, error) {
Expand Down
Loading