Esempio n. 1
0
func GetManifest(repository, tag string, exit bool) *Manifest {
	if manifest, ok := manifests[repository][tag]; ok {
		return manifest
	}
	url := fmt.Sprintf("%s/v2/%s/manifests/%s", config.Config.RegistryHost, repository, tag)
	logger.Logger.Debug("Requesting url: " + url)
	req := http.NewRequest(url)
	resp, err := req.Do()
	logger.Logger.CheckError(err)
	resp, err = resolve(resp, exit)
	if !exit && nil == resp {
		return nil
	}
	body, err := ioutil.ReadAll(resp.Body)
	logger.Logger.CheckError(err)
	manifest := NewManifest()
	err = json.Unmarshal(body, manifest)
	logger.Logger.CheckError(err)
	manifest.Digest = resp.Header.Get("Docker-Content-Digest")
	if _, ok := manifests[repository]; !ok {
		manifests[repository] = make(map[string]*Manifest, 0)
	}
	manifests[repository][tag] = manifest
	return manifest
}
Esempio n. 2
0
func GetSize(repository, tag string) int {
	manifest := GetManifest(repository, tag, true)
	var wg sync.WaitGroup
	var size int
	for _, layer := range manifest.FsLayers {
		wg.Add(1)
		go func(digest string) {
			url := fmt.Sprintf("%s/v2/%s/blobs/%s", config.Config.RegistryHost, repository, digest)
			logger.Logger.Debug("Requesting HEAD for url: " + url)
			req := http.NewRequest(url)
			req.SetMethod("HEAD")
			resp, err := req.Do()
			logger.Logger.CheckError(err)
			resp, err = resolve(resp, true)
			logger.Logger.CheckError(err)
			// resp.Header.Get("Accept-Ranges")
			length, err := strconv.Atoi(resp.Header.Get("Content-Length"))
			logger.Logger.CheckError(err)
			size += length
			wg.Done()
		}(layer["blobSum"])
	}
	wg.Wait()
	return size
}
// see: https://docs.docker.com/registry/spec/api/#listing-repositories
func GetRepositories() *Repositories {
	url := config.Config.RegistryHost + "/v2/_catalog"
	logger.Logger.Debug("Requesting url: " + url)
	req := http.NewRequest(url)
	resp, err := req.Do()
	logger.Logger.CheckError(err)
	resp, err = resolve(resp, true)
	body, err := ioutil.ReadAll(resp.Body)
	logger.Logger.CheckError(err)
	repository := &Repositories{}
	err = json.Unmarshal(body, repository)
	logger.Logger.CheckError(err)
	return repository
}
Esempio n. 4
0
func GetTags(repository string) *Tag {
	url := fmt.Sprintf("%s/v2/%s/tags/list", config.Config.RegistryHost, repository)
	logger.Logger.Debug("Requesting url: " + url)
	req := http.NewRequest(url)
	resp, err := req.Do()
	logger.Logger.CheckError(err)
	resp, err = resolve(resp, true)
	body, err := ioutil.ReadAll(resp.Body)
	logger.Logger.CheckError(err)
	tag := &Tag{}
	err = json.Unmarshal(body, tag)
	logger.Logger.CheckError(err)

	return tag
}
Esempio n. 5
0
// ApiCheck will check if the server implements the registry api v2
// If authentication (when needed) fails or server returns no 200
// or 401 status code it wil exit,
// see: https://docs.docker.com/registry/spec/api/#api-version-check
func ApiCheck() {
	logger.Logger.Debug("Server version check....")
	url := config.Config.RegistryHost + "/v2/"
	logger.Logger.Debug("Requesting HEAD for url: " + url)
	req := http.NewRequest(url)
	req.SetMethod("HEAD")
	req.AddHeader("Host", req.Raw().Host)
	resp, err := req.Do()
	logger.Logger.CheckError(err)
	logger.Logger.Debug("The registry implements the V2(.1) registry API.")
	if resp.StatusCode == 401 {
		logger.Logger.Debug("Server required authentication.")
	}
	resp, err = resolve(resp, true)
	if resp.StatusCode == 200 {
		logger.Logger.Debug("Authentication success.")
	}
}
Esempio n. 6
0
func Delete(repository, tag string, dry bool) {

	if dry {
		fmt.Println("Running a dry-run.")
	}

	var wg sync.WaitGroup
	blobs := NewLockedBlobList()

	for _, repos := range *GetList() {
		for _, tagName := range repos.Tags {
			if repos.Name == repository && tagName == tag {
				continue
			}
			wg.Add(1)
			go func(list *lockedBlobList, repos, tag string) {
				manifests := GetManifest(repos, tag, true)
				for _, blob := range manifests.FsLayers {
					list.add(blob["blobSum"], repos, tag)
				}
				wg.Done()
			}(blobs, repos.Name, tagName)
		}
	}
	wg.Wait()

	manifest := GetManifest(repository, tag, true)
	remove := blobList(make(map[string][]string, 0))

	if true != dry {
		for _, layer := range manifest.FsLayers {
			if false == blobs.has(layer["blobSum"]) {
				logger.Logger.Debug(fmt.Sprintf("Adding layer %s to queued for removal", layer["blobSum"]))
				remove.add(layer["blobSum"], repository, tag)
			} else {
				logger.Logger.Debug(fmt.Sprintf("Skipping layer %s is used by: %s", layer["blobSum"], strings.Join(blobs.get(layer["blobSum"]), ", ")))
			}
		}
	} else {
		// For dry run we just print a overview
		table := helpers.NewTable("DIGEST", "REMOVING", "USED BY")
		for _, layer := range manifest.FsLayers {
			if false == blobs.has(layer["blobSum"]) {
				table.AddRow(layer["blobSum"], true)
			} else {
				table.AddRow(layer["blobSum"], false, strings.Join(blobs.get(layer["blobSum"]), ", "))
			}
		}
		table.Print()
	}

	if true != dry {

		deleteBlob := func(digest string) {
			url := fmt.Sprintf("%s/v2/%s/blobs/%s", config.Config.RegistryHost, repository, digest)
			logger.Logger.Debug("Requesting DELETE for url: " + url)
			req := http.NewRequest(url)
			req.SetMethod("DELETE")
			resp, err := req.Do()
			logger.Logger.CheckError(err)
			resp, err = resolve(resp, false)
			logger.Logger.CheckWarning(err)
			if err != nil {
				logger.Logger.Debug("Removed: " + digest)
			}
			wg.Done()
		}

		first := true
		for layer, _ := range remove {
			wg.Add(1)
			// first one not so token can be cached
			if first {
				deleteBlob(layer)
				first = false
			} else {
				go deleteBlob(layer)
			}
		}
		wg.Wait()

		url := fmt.Sprintf("%s/v2/%s/manifests/%s", config.Config.RegistryHost, repository, manifest.Digest)
		logger.Logger.Debug("Requesting DELETE for url: " + url)
		req := http.NewRequest(url)
		req.SetMethod("DELETE")
		resp, err := req.Do()
		resp, err = resolve(resp, true)
		logger.Logger.CheckError(err)
	}
}