func TestStage1LoadingFromConfigNoDiscovery(t *testing.T) { // We shouldn't be using discovery in this setup, but enable // it, just in case. setup := newStubStage1Setup(t, taas.GetDefaultServerSetup()) defer setup.cleanup() cfg := &config.Stage1Data{ Name: setup.name, Version: setup.version, Location: setup.getLocation(stubStage1PathAbs), } setup.generateStage1Config(cfg) cmd := fmt.Sprintf("%s --insecure-options=image,tls --debug run %s", setup.ctx.Cmd(), getInspectImagePath()) child := spawnOrFail(setup.t, cmd) defer waitOrFail(setup.t, child, 0) discoveringStr := fmt.Sprintf("searching for app image %s", setup.name) for { matches, output, err := expectRegexWithOutput(child, `(?m)^image:.+$`) if err != nil { if strings.Index(output, stubStage1Output) < 0 { t.Fatalf("got no success notice from stub stage1, output:\n%s", output) } break } if strings.Index(matches[0], discoveringStr) >= 0 { t.Fatalf("rkt performs discovery for stage1 image, but it should not") } } }
func TestFetchNoStoreCacheControl(t *testing.T) { imageName := "rkt-inspect-fetch-nostore-cachecontrol" imageFileName := fmt.Sprintf("%s.aci", imageName) // no spaces between words, because of an actool limitation successMsg := "deferredSignatureDownloadWasSuccessful" args := []string{ fmt.Sprintf("--exec=/inspect --print-msg='%s'", successMsg), fmt.Sprintf("--name=%s", imageName), } image := patchTestACI(imageFileName, args...) defer os.Remove(image) asc := runSignImage(t, image, 1) defer os.Remove(asc) ascBase := filepath.Base(asc) setup := taas.GetDefaultServerSetup() setup.Server = taas.ServerQuay server := runServer(t, setup) defer server.Close() fileSet := make(map[string]string, 2) fileSet[imageFileName] = image fileSet[ascBase] = asc if err := server.UpdateFileSet(fileSet); err != nil { t.Fatalf("Failed to populate a file list in test aci server: %v", err) } ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() runRktTrust(t, ctx, "", 1) tests := []struct { imageArg string imageURL string }{ {"https://127.0.0.1/" + imageFileName, "https://127.0.0.1/" + imageFileName}, {"localhost/" + imageName, "https://127.0.0.1:443/localhost/" + imageFileName}, } for _, tt := range tests { cmd := fmt.Sprintf("%s --no-store --debug --insecure-options=tls,image fetch %s", ctx.Cmd(), tt.imageArg) expectedMessage := fmt.Sprintf("fetching image from %s", tt.imageURL) runRktAndCheckRegexOutput(t, cmd, expectedMessage) cmd = fmt.Sprintf("%s --no-store --debug --insecure-options=tls,image fetch %s", ctx.Cmd(), tt.imageArg) expectedMessage = fmt.Sprintf("image for %s isn't expired, not fetching.", tt.imageURL) runRktAndCheckRegexOutput(t, cmd, expectedMessage) ctx.Reset() } }
func runAuthServer(t *testing.T, auth taas.AuthType) (*taas.Server, string) { setup := taas.GetDefaultServerSetup() setup.Auth = auth setup.Port = taas.PortRandom server := runServer(t, setup) image := patchTestACI(authACIName, fmt.Sprintf("--exec=/inspect --print-msg='%s'", authSuccessfulDownload)) fileSet := make(map[string]string, 1) fileSet[authACIName] = image if err := server.UpdateFileSet(fileSet); err != nil { t.Fatalf("Failed to populate a file list in test aci server: %v", err) } return server, image }
func TestDifferentDiscoveryLabels(t *testing.T) { manifestTemplate := `{"acKind":"ImageManifest","acVersion":"0.8.6","name":"IMG_NAME","labels":[{"name":"version","value":"1.2.0"},{"name":"arch","value":"amd64"},{"name":"os","value":"linux"}]}` emptyImage := getEmptyImagePath() imageName := "localhost/rkt-test-different-discovery-labels-image" manifest := strings.Replace(manifestTemplate, "IMG_NAME", imageName, -1) tmpDir := createTempDirOrPanic("rkt-TestDifferentDiscoveryLabels-") defer os.RemoveAll(tmpDir) tmpManifest, err := ioutil.TempFile(tmpDir, "manifest") if err != nil { panic(fmt.Sprintf("Cannot create temp manifest: %v", err)) } if err := ioutil.WriteFile(tmpManifest.Name(), []byte(manifest), 0600); err != nil { panic(fmt.Sprintf("Cannot write to temp manifest: %v", err)) } defer os.Remove(tmpManifest.Name()) image := patchACI(emptyImage, "rkt-test-different-discovery-labels-image.aci", "--manifest", tmpManifest.Name()) imageFileName := fmt.Sprintf("%s.aci", filepath.Base(imageName)) defer os.Remove(image) asc := runSignImage(t, image, 1) defer os.Remove(asc) ascBase := filepath.Base(asc) setup := taas.GetDefaultServerSetup() server := runServer(t, setup) defer server.Close() fileSet := make(map[string]string, 2) fileSet[imageFileName] = image fileSet[ascBase] = asc if err := server.UpdateFileSet(fileSet); err != nil { t.Fatalf("Failed to populate a file list in test aci server: %v", err) } tests := []struct { imageName string expectedMessage string }{ {imageName + ":2.0", fmt.Sprintf("requested value for label %q: %q differs from fetched aci label value: %q", "version", "2.0", "1.2.0")}, {imageName + ":latest", fmt.Sprintf("requested value for label %q: %q differs from fetched aci label value: %q", "version", "latest", "1.2.0")}, {imageName + ",arch=armv7b", fmt.Sprintf("requested value for label %q: %q differs from fetched aci label value: %q", "arch", "armv7b", "amd64")}, {imageName + ",unexistinglabel=bla", fmt.Sprintf("requested label %q not provided by the image manifest", "unexistinglabel")}, } for _, tt := range tests { testDifferentDiscoveryNameLabels(t, tt.imageName, tt.expectedMessage) } }
func TestStage1LoadingFromFlagsHttp(t *testing.T) { // We need no discovery, so use random port. serverSetup := taas.GetDefaultServerSetup() serverSetup.Protocol = taas.ProtocolHttp serverSetup.Port = taas.PortRandom setup := newStubStage1Setup(t, serverSetup) defer setup.cleanup() flag := fmt.Sprintf("--stage1-url=%q", setup.getLocation(stubStage1UrlHttp)) expectedFirstRun := fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttp)) expectedSecondRun := fmt.Sprintf("image: using image from local store for url %s", setup.getLocation(stubStage1UrlHttp)) setup.check(flag, expectedFirstRun) setup.check(flag, expectedSecondRun) }
func TestRenderOnFetch(t *testing.T) { // If overlayfs is not supported, we don't render images on fetch if !common.SupportsOverlay() { t.Skip("Overlay fs not supported.") } ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() server := runServer(t, taas.GetDefaultServerSetup()) defer server.Close() fileSet, imageList := generateComplexDependencyTree(t, ctx) for _, img := range imageList { defer os.Remove(img.fileName) } if err := server.UpdateFileSet(fileSet); err != nil { t.Fatalf("Failed to populate a file list in test aci server: %v", err) } for i := len(imageList) - 1; i >= 0; i-- { img := imageList[i] if img.prefetch { t.Logf("Importing image %q: %q", img.imageName, img.fileName) testImageShortHash, err := importImageAndFetchHash(t, ctx, "", img.fileName) if err != nil { t.Fatalf("%v", err) } t.Logf("Imported image %q: %s", img.imageName, testImageShortHash) } } fetchCmd := fmt.Sprintf("%s --debug --insecure-options=image,tls fetch %s", ctx.Cmd(), topImage) child := spawnOrFail(t, fetchCmd) treeStoreDir := filepath.Join(ctx.DataDir(), "cas", "tree") trees, err := ioutil.ReadDir(treeStoreDir) if err != nil { panic(fmt.Sprintf("Cannot read tree store dir: %v", err)) } // We expect 2 trees: stage1 and the image if len(trees) != 2 { t.Fatalf("Expected 2 trees but found %d", len(trees)) } waitOrFail(t, child, 0) }
// TestImageDependencies generates ACIs with a complex dependency tree and // fetches them via the discovery mechanism. Some dependencies are already // cached in the CAS, and some dependencies are fetched via the discovery // mechanism. This is to reproduce the scenario in explained in: // https://github.com/coreos/rkt/issues/1752#issue-117121841 func TestImageDependencies(t *testing.T) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() server := runServer(t, taas.GetDefaultServerSetup()) defer server.Close() fileSet, imageList := generateComplexDependencyTree(t, ctx) for _, img := range imageList { defer os.Remove(img.fileName) } if err := server.UpdateFileSet(fileSet); err != nil { t.Fatalf("Failed to populate a file list in test aci server: %v", err) } for i := len(imageList) - 1; i >= 0; i-- { img := imageList[i] if img.prefetch { t.Logf("Importing image %q: %q", img.imageName, img.fileName) testImageShortHash, err := importImageAndFetchHash(t, ctx, "", img.fileName) if err != nil { t.Fatalf("%v", err) } t.Logf("Imported image %q: %s", img.imageName, testImageShortHash) } } runCmd := fmt.Sprintf("%s --debug --insecure-options=image,tls run %s", ctx.Cmd(), topImage) child := spawnOrFail(t, runCmd) expectedList := []string{ fmt.Sprintf("image: fetching image from %s/localhost/image-a.aci", server.URL), "image: using image from local store for image name localhost/image-b", fmt.Sprintf("image: fetching image from %s/localhost/image-c.aci", server.URL), fmt.Sprintf("image: fetching image from %s/localhost/image-d.aci", server.URL), "image: using image from local store for image name coreos.com/rkt-inspect", "HelloDependencies", } for _, expected := range expectedList { if err := expectWithOutput(child, expected); err != nil { t.Fatalf("Expected %q but not found: %v", expected, err) } } waitOrFail(t, child, 0) }
func TestDeferredSignatureDownload(t *testing.T) { imageName := "localhost/rkt-inspect-deferred-signature-download" imageFileName := fmt.Sprintf("%s.aci", filepath.Base(imageName)) // no spaces between words, because of an actool limitation successMsg := "deferredSignatureDownloadWasSuccessful" args := []string{ fmt.Sprintf("--exec=/inspect --print-msg='%s'", successMsg), fmt.Sprintf("--name=%s", imageName), } image := patchTestACI(imageFileName, args...) defer os.Remove(image) asc := runSignImage(t, image, 1) defer os.Remove(asc) ascBase := filepath.Base(asc) setup := taas.GetDefaultServerSetup() setup.Server = taas.ServerQuay server := runServer(t, setup) defer server.Close() fileSet := make(map[string]string, 2) fileSet[imageFileName] = image fileSet[ascBase] = asc if err := server.UpdateFileSet(fileSet); err != nil { t.Fatalf("Failed to populate a file list in test aci server: %v", err) } ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() runRktTrust(t, ctx, "", 1) runCmd := fmt.Sprintf("%s --debug --insecure-options=tls run %s", ctx.Cmd(), imageName) child := spawnOrFail(t, runCmd) defer waitOrFail(t, child, 0) expectedMessages := []string{ "server requested deferring the signature download", successMsg, } for _, msg := range expectedMessages { if err := expectWithOutput(child, msg); err != nil { t.Fatalf("Could not find expected msg %q, output follows:\n%v", msg, err) } } }
func TestStage1LoadingFromConfigHttp(t *testing.T) { // We don't need discovery in this test, so get random port. serverSetup := taas.GetDefaultServerSetup() serverSetup.Protocol = taas.ProtocolHttp serverSetup.Port = taas.PortRandom setup := newStubStage1Setup(t, serverSetup) defer setup.cleanup() expectedFirstRun := fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttp)) expectedSecondRun := fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version) cfg := &config.Stage1Data{ Name: setup.name, Version: setup.version, Location: setup.getLocation(stubStage1UrlHttp), } t.Logf("Generating stage1 configuration file with name %q, version %q and location %q", setup.name, setup.version, setup.getLocation(stubStage1UrlHttp)) setup.generateStage1Config(cfg) setup.check("", expectedFirstRun) setup.check("", expectedSecondRun) }
func TestStage1LoadingFromConfig(t *testing.T) { // We don't need discovery in this test, so get random port, // but keep https. serverSetup := taas.GetDefaultServerSetup() serverSetup.Port = taas.PortRandom setup := newStubStage1Setup(t, serverSetup) defer setup.cleanup() tests := []struct { name string version string location string expectedFirstRun string expectedSecondRun string skipReason string }{ // typical scenario - config file with correct name, // version and location, we expect the stage1 image to // be taken from file in the first run, and then from // store on subsequent runs { name: setup.name, version: setup.version, location: setup.getLocation(stubStage1PathAbs), expectedFirstRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version), }, // wrong name, resulting in always loading the stage1 // image from disk { name: "example.com/stage1", version: setup.version, location: setup.getLocation(stubStage1PathAbs), expectedFirstRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), }, // wrong version, resulting in always loading the stage1 // image from disk { name: setup.name, version: "3.2.1", location: setup.getLocation(stubStage1PathAbs), expectedFirstRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), }, // loading stage1 from http URL { name: setup.name, version: setup.version, location: setup.getLocation(stubStage1UrlHttp), skipReason: "tested in TestStage1LoadingFromConfigHttp", }, // loading stage1 from docker URL { name: setup.name, version: setup.version, location: setup.getLocation(stubStage1UrlDocker), skipReason: "tested in TestStage1LoadingFromConfigDocker", }, // loading stage1 from https URL { name: setup.name, version: setup.version, location: setup.getLocation(stubStage1UrlHttps), expectedFirstRun: fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttps)), expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version), }, // loading stage1 from file URL { name: setup.name, version: setup.version, location: setup.getLocation(stubStage1UrlFile), expectedFirstRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s:%s", setup.name, setup.version), }, } for _, tt := range tests { if tt.skipReason != "" { t.Logf("skipping the testcase with name %q, version %q and location %q, reason - %s", tt.name, tt.version, tt.location, tt.skipReason) continue } cfg := &config.Stage1Data{ Name: tt.name, Version: tt.version, Location: tt.location, } t.Logf("Generating stage1 configuration file with name %q, version %q and location %q", tt.name, tt.version, tt.location) setup.generateStage1Config(cfg) setup.check("", tt.expectedFirstRun) setup.check("", tt.expectedSecondRun) setup.ctx.Reset() } }
func TestStage1LoadingFromFlags(t *testing.T) { // We use discovery in this test. setup := newStubStage1Setup(t, taas.GetDefaultServerSetup()) defer setup.cleanup() tests := []struct { flag string expectedFirstRun string expectedSecondRun string skipReason string }{ // --stage1-path with a relative path { flag: fmt.Sprintf("--stage1-path=%q", setup.getLocation(stubStage1PathRel)), expectedFirstRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathRel)), expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathRel)), }, // --stage1-path with an absolute path { flag: fmt.Sprintf("--stage1-path=%q", setup.getLocation(stubStage1PathAbs)), expectedFirstRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), }, // --stage1-url with an http URL { flag: "--stage1-url=http://...", skipReason: "tested in TestStage1LoadingFromFlagsHttp", }, // --stage1-url with an docker URL { flag: "--stage1-url=docker://...", skipReason: "tested in TestStage1LoadingFromFlagsDocker", }, // --stage1-url with an https URL { flag: fmt.Sprintf("--stage1-url=%q", setup.getLocation(stubStage1UrlHttps)), expectedFirstRun: fmt.Sprintf("image: remote fetching from URL %q", setup.getLocation(stubStage1UrlHttps)), expectedSecondRun: fmt.Sprintf("image: using image from local store for url %s", setup.getLocation(stubStage1UrlHttps)), }, // --stage1-url with an file URL { flag: fmt.Sprintf("--stage1-url=%q", setup.getLocation(stubStage1UrlFile)), expectedFirstRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), expectedSecondRun: fmt.Sprintf("image: using image from file %s", setup.getLocation(stubStage1PathAbs)), }, // --stage1-name { flag: fmt.Sprintf("--stage1-name=%s", setup.getLocation(stubStage1Name)), expectedFirstRun: fmt.Sprintf("image: searching for app image %s", setup.name), expectedSecondRun: fmt.Sprintf("image: using image from local store for image name %s", setup.getLocation(stubStage1Name)), }, // --stage1-hash { flag: "--stage1-hash=...", skipReason: "tested in TestStage1LoadingFromFlagsHash", }, // --stage1-from-dir { flag: "--stage1-from-dir=...", skipReason: "tested in TestStage1LoadingFromFlagsFromDir", }, } for _, tt := range tests { if tt.skipReason != "" { t.Logf("skipping the testcase with the flag %s, reason - %s", tt.flag, tt.skipReason) continue } setup.check(tt.flag, tt.expectedFirstRun) setup.check(tt.flag, tt.expectedSecondRun) setup.ctx.Reset() } }
// TestImageDependencies generates ACIs with a complex dependency tree and // fetches them via the discovery mechanism. Some dependencies are already // cached in the CAS, and some dependencies are fetched via the discovery // mechanism. This is to reproduce the scenario in explained in: // https://github.com/coreos/rkt/issues/1752#issue-117121841 func TestImageDependencies(t *testing.T) { tmpDir := createTempDirOrPanic("rkt-TestImageDeps-") defer os.RemoveAll(tmpDir) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() server := runServer(t, taas.GetDefaultServerSetup()) defer server.Close() baseImage := getInspectImagePath() _ = importImageAndFetchHash(t, ctx, "", baseImage) emptyImage := getEmptyImagePath() fileSet := make(map[string]string) // Scenario from https://github.com/coreos/rkt/issues/1752#issue-117121841 // // A->B // A->C // A->D // // B: prefetched // // C->B // C->E // // D->B // D->E topImage := "localhost/image-a" imageList := []struct { shortName string imageName string deps string version string prefetch bool manifest string fileName string }{ { shortName: "a", imageName: topImage, deps: `{"imageName":"localhost/image-b"}, {"imageName":"localhost/image-c"}, {"imageName":"localhost/image-d"}`, version: "1", }, { shortName: "b", imageName: "localhost/image-b", deps: ``, version: "1", prefetch: true, }, { shortName: "c", imageName: "localhost/image-c", deps: `{"imageName":"localhost/image-b"}, {"imageName":"localhost/image-e", "labels": [{"name": "version", "value": "1"}]}`, version: "1", }, { shortName: "d", imageName: "localhost/image-d", deps: `{"imageName":"localhost/image-b"}, {"imageName":"localhost/image-e", "labels": [{"name": "version", "value": "1"}]}`, version: "1", }, { shortName: "e", imageName: "localhost/image-e", deps: `{"imageName":"coreos.com/rkt-inspect"}`, version: "1", }, } for i, _ := range imageList { // We need a reference rather than a new copy from "range" // because we modify the content img := &imageList[i] img.manifest = manifestDepsTemplate img.manifest = strings.Replace(img.manifest, "IMG_NAME", img.imageName, -1) img.manifest = strings.Replace(img.manifest, "DEPENDENCIES", img.deps, -1) img.manifest = strings.Replace(img.manifest, "VERSION", img.version, -1) tmpManifest, err := ioutil.TempFile(tmpDir, "manifest-"+img.shortName+"-") if err != nil { panic(fmt.Sprintf("Cannot create temp manifest: %v", err)) } defer os.Remove(tmpManifest.Name()) if err := ioutil.WriteFile(tmpManifest.Name(), []byte(img.manifest), 0600); err != nil { panic(fmt.Sprintf("Cannot write to temp manifest: %v", err)) } baseName := "image-" + img.shortName + ".aci" img.fileName = patchACI(emptyImage, baseName, "--manifest", tmpManifest.Name()) defer os.Remove(img.fileName) fileSet[baseName] = img.fileName } if err := server.UpdateFileSet(fileSet); err != nil { t.Fatalf("Failed to populate a file list in test aci server: %v", err) } for i := len(imageList) - 1; i >= 0; i-- { img := imageList[i] if img.prefetch { t.Logf("Importing image %q: %q", img.imageName, img.fileName) testImageShortHash := importImageAndFetchHash(t, ctx, "", img.fileName) t.Logf("Imported image %q: %s", img.imageName, testImageShortHash) } } runCmd := fmt.Sprintf("%s --debug --insecure-options=image,tls run %s", ctx.Cmd(), topImage) child := spawnOrFail(t, runCmd) expectedList := []string{ fmt.Sprintf("image: fetching image from %s/localhost/image-a.aci", server.URL), "image: using image from local store for image name localhost/image-b", fmt.Sprintf("image: fetching image from %s/localhost/image-c.aci", server.URL), fmt.Sprintf("image: fetching image from %s/localhost/image-d.aci", server.URL), "image: using image from local store for image name coreos.com/rkt-inspect", "HelloDependencies", } for _, expected := range expectedList { if err := expectWithOutput(child, expected); err != nil { t.Fatalf("Expected %q but not found: %v", expected, err) } } waitOrFail(t, child, 0) }