* run script changes

* testing

* changes

* test for run changes

* Test for the run.sh task

* changes

* run.sh changes

* addressed PR commends

* run command integration test

* merged with main branch

* run command changes

* address pr changes

* customized run command for Node, PhP

* python run command change

* run command changes

* addressed PR changes

* bug fix
This commit is contained in:
waliMSFT 2022-08-16 15:59:37 -04:00 коммит произвёл GitHub
Родитель b4dcd1107c
Коммит e45c810dc9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 185 добавлений и 16 удалений

Просмотреть файл

@ -13,3 +13,4 @@ const Logger string = "/opt/oryx/logger"
const Bash string = "/bin/bash"
const Benv string = "/opt/oryx/benv"
const PreRunCommandEnvVarName string = "PRE_RUN_COMMAND"
const AppSvcFileName string = "appsvc.yaml"

Просмотреть файл

@ -60,6 +60,28 @@ func WriteScript(filePath string, command string) {
ioutil.WriteFile(filePath, []byte(command), 0755)
}
// Appends command to a file
func AppendScript(filePath string, command string) {
if command == "" {
return
}
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
fmt.Println("Unable to read provided file to append command to. Error: " + err.Error())
return
}
defer file.Close()
fmt.Println("Appending provided command to '" + filePath + "'")
// Appends the command at the end of the file
if _, err := file.WriteString("\n" + command); err != nil {
fmt.Println("Unable to write in the file. Error: " + err.Error())
return
}
}
// Try to add a permission to a file
func TryAddPermission(filePath string, permission os.FileMode) bool {
err := os.Chmod(filePath, permission)

Просмотреть файл

@ -0,0 +1,58 @@
// --------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
// --------------------------------------------------------------------------------------------
package common
import (
"bufio"
"fmt"
"os"
"strings"
)
func ParseUserRunCommand(sourcePath string) string {
appsvcFile, err := os.Open(sourcePath)
if err != nil {
return ""
}
defer appsvcFile.Close()
const runHeading string = "run:" // format of run command- "run: gunicorn myapp.app --workers 5"
runCommand := ""
var isRunCommandFound bool
scanner := bufio.NewScanner(appsvcFile)
for scanner.Scan() {
indexOfRunHeading := strings.Index(scanner.Text(), runHeading)
isCurrentLineContainsAnyHeading := strings.Contains(scanner.Text(), ":")
if isCurrentLineContainsAnyHeading && isRunCommandFound {
// runCommand already found
// not considering any other customized commands
break
}
isValidRunCommand := indexOfRunHeading == 0 && len(scanner.Text()) > len(runHeading)
if isRunCommandFound || isValidRunCommand {
if isRunCommandFound {
runCommand += "\n"
runCommand += strings.TrimSpace(scanner.Text())
} else {
isRunCommandFound = true
runCommand += strings.TrimSpace(scanner.Text()[indexOfRunHeading+len(runHeading):]) //gets the run command and trim to get rid of the forward and trailing spaces
}
}
}
fmt.Println("User provided run command: " + runCommand)
if err := scanner.Err(); err != nil {
fmt.Println(err)
return ""
}
return runCommand
}

Просмотреть файл

@ -130,6 +130,9 @@ func main() {
}
common.WriteScript(fullOutputPath, command)
userRunCommand := common.ParseUserRunCommand(filepath.Join(fullAppPath, consts.AppSvcFileName))
common.AppendScript(fullOutputPath, userRunCommand)
}
if setupEnvCommand.Parsed() {

Просмотреть файл

@ -11,6 +11,7 @@ import (
"flag"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
)
@ -101,6 +102,9 @@ func main() {
}
script := gen.GenerateEntrypointScript()
common.WriteScript(*outputPathPtr, script)
userRunCommand := common.ParseUserRunCommand(filepath.Join(fullAppPath, consts.AppSvcFileName))
common.AppendScript(*outputPathPtr, userRunCommand)
}
if setupEnvCommand.Parsed() {

Просмотреть файл

@ -9,6 +9,7 @@ import (
"common"
"common/consts"
"flag"
"path/filepath"
)
func main() {
@ -58,5 +59,8 @@ func main() {
command := entrypointGenerator.GenerateEntrypointScript()
common.WriteScript(*outputPathPtr, command)
userRunCommand := common.ParseUserRunCommand(filepath.Join(fullAppPath, consts.AppSvcFileName))
common.AppendScript(*outputPathPtr, userRunCommand)
}
}

Просмотреть файл

@ -10,6 +10,7 @@ import (
"common/consts"
"flag"
"fmt"
"path/filepath"
"strings"
)
@ -87,6 +88,9 @@ func main() {
command := entrypointGenerator.GenerateEntrypointScript()
common.WriteScript(*outputPathPtr, command)
userRunCommand := common.ParseUserRunCommand(filepath.Join(fullAppPath, consts.AppSvcFileName))
common.AppendScript(*outputPathPtr, userRunCommand)
}
if setupEnvCommand.Parsed() {

Просмотреть файл

@ -10,6 +10,7 @@ import (
"common/consts"
"flag"
"fmt"
"path/filepath"
"strings"
)
@ -73,16 +74,19 @@ func main() {
configuration.PreRunCommand = viperConfig.GetString(consts.PreRunCommandEnvVarName)
gen := RubyStartupScriptGenerator{
SourcePath: fullAppPath,
UserStartupCommand: *userStartupCommandPtr,
DefaultAppFilePath: fullDefaultAppFilePath,
RailEnv: *railEnvironment,
BindPort: *bindPortPtr,
Manifest: buildManifest,
Configuration: configuration,
SourcePath: fullAppPath,
UserStartupCommand: *userStartupCommandPtr,
DefaultAppFilePath: fullDefaultAppFilePath,
RailEnv: *railEnvironment,
BindPort: *bindPortPtr,
Manifest: buildManifest,
Configuration: configuration,
}
script := gen.GenerateEntrypointScript()
common.WriteScript(*outputPathPtr, script)
userRunCommand := common.ParseUserRunCommand(filepath.Join(fullAppPath, consts.AppSvcFileName))
common.AppendScript(*outputPathPtr, userRunCommand)
}
if setupEnvCommand.Parsed() {
@ -107,4 +111,4 @@ func main() {
buildManifest.RubyVersion))
common.SetupEnv(finalScript)
}
}
}

Просмотреть файл

@ -6,6 +6,7 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Oryx.BuildScriptGenerator;
using Microsoft.Oryx.BuildScriptGenerator.Common;
using Microsoft.Oryx.BuildScriptGenerator.DotNetCore;
using Microsoft.Oryx.BuildScriptGeneratorCli;
@ -71,6 +72,71 @@ namespace Microsoft.Oryx.Integration.Tests
});
}
[Fact]
public async Task CanBuildAndRun_NetCore60MvcApp_WithCustomizedRunCommand()
{
// Arrange
var dotnetcoreVersion = DotNetCoreRunTimeVersions.NetCoreApp60;
var hostDir = Path.Combine(_hostSamplesDir, "DotNetCore", NetCoreApp60MvcApp);
var tmpDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tmpDir);
try
{
var tmpVolume = DockerVolume.CreateMirror(tmpDir, true);
var tmpContainerDir = tmpVolume.ContainerDir;
var volume = DockerVolume.CreateMirror(hostDir);
var appDir = volume.ContainerDir;
var appOutputDirVolume = CreateAppOutputDirVolume();
var appOutputDir = appOutputDirVolume.ContainerDir;
var appsvcFile = appOutputDirVolume.ContainerDir + "/appsvc.yaml";
var runCommand = "echo 'Hello Azure! New Feature!!'";
var buildImageScript = new ShellScriptBuilder()
.AddDefaultTestEnvironmentVariables()
.AddCommand(
$"oryx build {appDir} -i /tmp/int --platform {DotNetCoreConstants.PlatformName} " +
$"--platform-version {dotnetcoreVersion} -o {appOutputDir}")
.ToString();
var runtimeImageScript = new ShellScriptBuilder()
.CreateFile(appsvcFile, $"\"run: {runCommand}\"")
.AddCommand(
$"oryx create-script -appPath {appOutputDir} -bindPort {ContainerPort} -output {tmpContainerDir}/run.sh")
.AddCommand($".{tmpContainerDir}/run.sh")
.ToString();
await EndToEndTestHelper.BuildRunAndAssertAppAsync(
NetCoreApp60MvcApp,
_output,
new DockerVolume[] { volume, appOutputDirVolume, tmpVolume },
_imageHelper.GetGitHubActionsBuildImage(),
"/bin/sh",
new[]
{
"-c",
buildImageScript
},
_imageHelper.GetRuntimeImage("dotnetcore", "6.0"),
ContainerPort,
"/bin/sh",
new[]
{
"-c",
runtimeImageScript
},
async (hostPort) =>
{
var data = await _httpClient.GetStringAsync($"http://localhost:{hostPort}/");
Assert.Contains("Welcome to ASP.NET Core MVC!", data);
var runScript = File.ReadAllText(Path.Combine(tmpDir, "run.sh"));
Assert.Contains(runCommand, runScript);
});
}
finally
{
Directory.Delete(tmpDir, true);
}
}
[Fact]
public async Task CanBuildAndRun_Adds_Oryx_AppInsights_Codeless_ConfigurationAsync()
{

Просмотреть файл

@ -53,13 +53,13 @@ namespace Microsoft.Oryx.Tests.Common
/// </summary>
/// <param name="hostDir">local directory to be used in a container</param>
/// <returns>DockerVolume instance that can be used to mount the new copy of `originalDir`.</returns>
public static DockerVolume CreateMirror(string hostDir)
/// <param name="writeToHostDir">a boolean which indicates if we want the actual directory or the copy of the actual directory</param>
public static DockerVolume CreateMirror(string hostDir, bool writeToHostDir = false)
{
if (string.IsNullOrEmpty(hostDir))
{
throw new ArgumentException($"'{nameof(hostDir)}' cannot be null or empty.");
}
if (!Directory.Exists(hostDir))
{
throw new ArgumentException($"'{nameof(hostDir)}' must point to an existing directory.");
@ -90,12 +90,15 @@ namespace Microsoft.Oryx.Tests.Common
tempDirRoot = Path.Combine(Path.GetTempPath(), MountedHostDirRootName);
}
var writableHostDir = Path.Combine(
tempDirRoot,
Guid.NewGuid().ToString("N"),
dirInfo.Name);
CopyDirectories(hostDir, writableHostDir, copySubDirs: true);
var writableHostDir = hostDir;
if (!writeToHostDir)
{
writableHostDir = Path.Combine(
tempDirRoot,
Guid.NewGuid().ToString("N"),
dirInfo.Name);
CopyDirectories(hostDir, writableHostDir, copySubDirs: true);
}
// Grant permissions to the folder we just copied on the host machine. The permisions here allow the
// user(a non-root user) in the container to read/write/execute files.
var linuxOS = OSPlatform.Create("LINUX");