Repository: kurtosis-tech/kurtosis
Pull request #314 (2023-03-23 13:57:50)

feat: result of add service contains a `name` property
## Description:
Result of add service contains a name; use it in other places

## Is this change user facing?
YES & docs have been added

## References (if applicable):
https://github.com/kurtosis-tech/kurtosis/issues/175


cloudflare-pages[bot]: ## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>fedbfa2</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>⚡️&nbsp; Build in progress...</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/kurtosis-docs/b1fbf336-a0f9-45f2-bb16-a3b6f21c12b6)


Patch:
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service.go b/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service.go
index 2f8ff90fa..c683b5ebc 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service.go
@@ -109,7 +109,7 @@ func (builtin *AddServiceCapabilities) Interpret(arguments *builtin_argument.Arg
 		return nil, startosis_errors.WrapWithInterpretationError(err, "Unable to create runtime value to hold '%v' command return values", AddServiceBuiltinName)
 	}
 
-	returnValue, interpretationErr := makeAddServiceInterpretationReturnValue(builtin.serviceConfig, builtin.resultUuid)
+	returnValue, interpretationErr := makeAddServiceInterpretationReturnValue(serviceName, builtin.serviceConfig, builtin.resultUuid)
 	if interpretationErr != nil {
 		return nil, interpretationErr
 	}
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service_shared.go b/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service_shared.go
index 7ceaf43fe..de108d7b4 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service_shared.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_service_shared.go
@@ -34,7 +34,7 @@ func fillAddServiceReturnValueWithRuntimeValues(service *service.Service, result
 	})
 }
 
-func makeAddServiceInterpretationReturnValue(serviceConfig *kurtosis_core_rpc_api_bindings.ServiceConfig, resultUuid string) (*kurtosis_types.Service, *startosis_errors.InterpretationError) {
+func makeAddServiceInterpretationReturnValue(serviceName starlark.String, serviceConfig *kurtosis_core_rpc_api_bindings.ServiceConfig, resultUuid string) (*kurtosis_types.Service, *startosis_errors.InterpretationError) {
 	ports := serviceConfig.GetPrivatePorts()
 	portSpecsDict := starlark.NewDict(len(ports))
 	for portId, port := range ports {
@@ -54,7 +54,7 @@ func makeAddServiceInterpretationReturnValue(serviceConfig *kurtosis_core_rpc_ap
 	}
 	ipAddress := starlark.String(fmt.Sprintf(magic_string_helper.RuntimeValueReplacementPlaceholderFormat, resultUuid, ipAddressRuntimeValue))
 	hostname := starlark.String(fmt.Sprintf(magic_string_helper.RuntimeValueReplacementPlaceholderFormat, resultUuid, hostnameRuntimeValue))
-	returnValue := kurtosis_types.NewService(hostname, ipAddress, portSpecsDict)
+	returnValue := kurtosis_types.NewService(serviceName, hostname, ipAddress, portSpecsDict)
 	return returnValue, nil
 }
 
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_services.go b/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_services.go
index b82850a97..3e30686fc 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_services.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service/add_services.go
@@ -306,7 +306,7 @@ func makeAddServicesInterpretationReturnValue(serviceConfigs map[service.Service
 		if err != nil {
 			return nil, nil, startosis_errors.WrapWithInterpretationError(err, "Unable to create runtime value to hold '%v' command return values", AddServicesBuiltinName)
 		}
-		serviceObject, interpretationErr := makeAddServiceInterpretationReturnValue(serviceConfig, resultUuids[serviceName])
+		serviceObject, interpretationErr := makeAddServiceInterpretationReturnValue(serviceNameStr, serviceConfig, resultUuids[serviceName])
 		if interpretationErr != nil {
 			return nil, nil, interpretationErr
 		}
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_types/service.go b/core/server/api_container/server/startosis_engine/kurtosis_types/service.go
index a447f9fa5..b4b5604e3 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_types/service.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_types/service.go
@@ -10,9 +10,10 @@ import (
 const (
 	serviceTypeName = "Service"
 
-	hostnameAttr  = "hostname"
-	ipAddressAttr = "ip_address"
-	portsAttr     = "ports"
+	hostnameAttr    = "hostname"
+	ipAddressAttr   = "ip_address"
+	portsAttr       = "ports"
+	serviceNameAttr = "name"
 )
 
 // Service is just a wrapper around a regular starlarkstruct.Struct
@@ -21,11 +22,12 @@ type Service struct {
 	*starlarkstruct.Struct
 }
 
-func NewService(hostname starlark.String, ipAddress starlark.String, ports *starlark.Dict) *Service {
+func NewService(serviceName starlark.String, hostname starlark.String, ipAddress starlark.String, ports *starlark.Dict) *Service {
 	structDict := starlark.StringDict{
-		hostnameAttr:  hostname,
-		ipAddressAttr: ipAddress,
-		portsAttr:     ports,
+		serviceNameAttr: serviceName,
+		hostnameAttr:    hostname,
+		ipAddressAttr:   ipAddress,
+		portsAttr:       ports,
 	}
 	return &Service{
 		Struct: starlarkstruct.FromStringDict(starlark.String(serviceTypeName), structDict),
diff --git a/docs/docs/reference/starlark-instructions.md b/docs/docs/reference/starlark-instructions.md
index cb6c3a0ff..08644601e 100644
--- a/docs/docs/reference/starlark-instructions.md
+++ b/docs/docs/reference/starlark-instructions.md
@@ -69,6 +69,7 @@ The `add_service` function returns a `service` object that contains service info
 - A `hostname` property representing [a future reference][future-references-reference] to the service's hostname.
 - An `ip_address` property representing [a future reference][future-references-reference] to the service's IP address.
 - A `ports` dictionary containing [future reference][future-references-reference] information about each port that the service is listening on.
+- A `name` property representing the name of the service.
 
 The value of the `ports` dictionary is an object with three properties, `number`, `transport_protocol` and `application_protocol` (optional), which themselves are [future references][future-references-reference].
 


Test patch:
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_service_framework_test.go b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_service_framework_test.go
index 29f49a5b5..10fae441b 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_service_framework_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/test_engine/add_service_framework_test.go
@@ -156,7 +156,7 @@ func (t *addServiceTestCase) Assert(interpretationResult starlark.Value, executi
 	serviceObj, ok := interpretationResult.(*kurtosis_types.Service)
 	require.True(t, ok, "interpretation result should be a dictionary")
 	require.NotNil(t, serviceObj)
-	expectedServiceObj := fmt.Sprintf(`Service\(hostname = "{{kurtosis:[0-9a-f]{32}:hostname.runtime_value}}", ip_address = "{{kurtosis:[0-9a-f]{32}:ip_address.runtime_value}}", ports = {%q: PortSpec\(number=%d, transport_protocol=%q, application_protocol=%q\)}\)`, TestPrivatePortId, TestPrivatePortNumber, TestPrivatePortProtocolStr, TestPrivateApplicationProtocol)
+	expectedServiceObj := fmt.Sprintf(`Service\(hostname = "{{kurtosis:[0-9a-f]{32}:hostname.runtime_value}}", ip_address = "{{kurtosis:[0-9a-f]{32}:ip_address.runtime_value}}", name = "%v", ports = {%q: PortSpec\(number=%d, transport_protocol=%q, application_protocol=%q\)}\)`, TestServiceName, TestPrivatePortId, TestPrivatePortNumber, TestPrivatePortProtocolStr, TestPrivateApplicationProtocol)
 	require.Regexp(t, expectedServiceObj, serviceObj.String())
 
 	expectedExecutionResult := fmt.Sprintf("Service '%s' added with service UUID '%s'", TestServiceName, TestServiceUuid)
diff --git a/core/server/api_container/server/startosis_engine/kurtosis_types/service_test.go b/core/server/api_container/server/startosis_engine/kurtosis_types/service_test.go
index 155d3c8a6..df4790ee1 100644
--- a/core/server/api_container/server/startosis_engine/kurtosis_types/service_test.go
+++ b/core/server/api_container/server/startosis_engine/kurtosis_types/service_test.go
@@ -14,19 +14,20 @@ const (
 	testInvalidAttr          = "invalid-test-attr"
 	httpApplicationProtocol  = "http"
 	emptyApplicationProtocol = ""
+	serviceNameTestValue     = starlark.String("test-service")
 )
 
 func TestService_StringRepresentation(t *testing.T) {
 	service, err := createTestServiceType()
 	require.Nil(t, err)
-	expectedStr := `Service(hostname = "datastore-1", ip_address = "{{kurtosis:service_name.ip_address}}", ports = {"grpc": PortSpec(number=123, transport_protocol="TCP")})`
+	expectedStr := `Service(hostname = "datastore-1", ip_address = "{{kurtosis:service_name.ip_address}}", name = "test-service", ports = {"grpc": PortSpec(number=123, transport_protocol="TCP")})`
 	require.Equal(t, expectedStr, service.String())
 }
 
 func TestService_StringRepresentationWithApplicationProtocol(t *testing.T) {
 	service, err := createTestServiceTypeWithApplicationProtocol()
 	require.Nil(t, err)
-	expectedStr := `Service(hostname = "datastore-1", ip_address = "{{kurtosis:service_name.ip_address}}", ports = {"grpc": PortSpec(number=123, transport_protocol="TCP", application_protocol="http")})`
+	expectedStr := `Service(hostname = "datastore-1", ip_address = "{{kurtosis:service_name.ip_address}}", name = "test-service", ports = {"grpc": PortSpec(number=123, transport_protocol="TCP", application_protocol="http")})`
 	require.Equal(t, expectedStr, service.String())
 }
 
@@ -78,7 +79,7 @@ func TestService_TestAttrNames(t *testing.T) {
 	service, err := createTestServiceType()
 	require.Nil(t, err)
 	attrNames := service.AttrNames()
-	require.Equal(t, []string{hostnameAttr, ipAddressAttr, portsAttr}, attrNames)
+	require.Equal(t, []string{hostnameAttr, ipAddressAttr, serviceNameAttr, portsAttr}, attrNames)
 }
 
 func createTestServiceType() (*Service, error) {
@@ -90,7 +91,7 @@ func createTestServiceType() (*Service, error) {
 	if err := ports.SetKey(starlark.String("grpc"), portSpec); err != nil {
 		return nil, err
 	}
-	service := NewService(hostnameTestValue, ipAddressTestValue, ports)
+	service := NewService(serviceNameTestValue, hostnameTestValue, ipAddressTestValue, ports)
 	return service, nil
 }
 
@@ -103,6 +104,6 @@ func createTestServiceTypeWithApplicationProtocol() (*Service, error) {
 	if err := ports.SetKey(starlark.String("grpc"), portSpec); err != nil {
 		return nil, err
 	}
-	service := NewService(hostnameTestValue, ipAddressTestValue, ports)
+	service := NewService(serviceNameTestValue, hostnameTestValue, ipAddressTestValue, ports)
 	return service, nil
 }
diff --git a/internal_testsuites/golang/testsuite/startosis_test/startosis_test.go b/internal_testsuites/golang/testsuite/startosis_test/startosis_test.go
index e16bcf4fa..72564059a 100644
--- a/internal_testsuites/golang/testsuite/startosis_test/startosis_test.go
+++ b/internal_testsuites/golang/testsuite/startosis_test/startosis_test.go
@@ -51,8 +51,8 @@ def run(plan, args):
 		}
 	)
 	
-	plan.add_service(service_name = DATASTORE_SERVICE_NAME, config = config)
-	plan.print("Service " + DATASTORE_SERVICE_NAME + " deployed successfully.")
+	result = plan.add_service(service_name = DATASTORE_SERVICE_NAME, config = config)
+	plan.print("Service " + result.name + " deployed successfully.")
 	plan.exec(
 		recipe = ExecRecipe(
 			command = ["touch", FILE_TO_BE_CREATED],