Skip to content

Commit a1251c1

Browse files
committed
fix(container): typed port error
1 parent 5a448df commit a1251c1

3 files changed

Lines changed: 36 additions & 93 deletions

File tree

rootfs/api/models/app.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from api.exceptions import AlreadyExists, DryccException, ServiceUnavailable
2424
from api.utils import generate_app_name, apply_tasks
2525
from scheduler import KubeHTTPException, KubeException
26-
from scheduler.resources.pod import DEFAULT_CONTAINER_PORT
2726
from .gateway import Gateway, Route
2827
from .limit import LimitPlan
2928
from .config import Config
@@ -682,9 +681,9 @@ def _deploy(self, deploys, procfile_types, prev_release,
682681
err = '(app::deploy): {}'.format(e)
683682
self.log(err, logging.ERROR)
684683
raise ServiceUnavailable(err) from e
685-
for procfile_type, value in deploys.items():
684+
for procfile_type in deploys.keys():
686685
if procfile_type == PROCFILE_TYPE_WEB: # http
687-
target_port = int(value.get('envs', {}).get('PORT', DEFAULT_CONTAINER_PORT))
686+
target_port = release.get_port(procfile_type)
688687
self._create_default_ingress(target_port)
689688
service = self.service_set.filter(procfile_type=procfile_type).first()
690689
if not service:
@@ -953,14 +952,13 @@ def _build_env_vars(self, release, procfile_type):
953952
}
954953

955954
default_env['SOURCE_VERSION'] = release.build.sha
956-
957-
# fetch application port and inject into ENV vars as needed
958-
port = release.get_port()
959-
if port:
960-
default_env['PORT'] = port
961955
# merge envs on top of default to make envs win
962956
default_env.update(release.config.values)
963957
default_env.update(release.config.typed_values.get(procfile_type, {}))
958+
# fetch application port and inject into ENV vars as needed
959+
port = release.get_port(procfile_type)
960+
if port:
961+
default_env['PORT'] = port
964962
return default_env
965963

966964
def _get_private_registry_config(self, image, registry=None):

rootfs/api/models/release.py

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -163,54 +163,15 @@ def new(self, user, config, build, summary=None, canary=False):
163163
build=build, version=new_version, summary=summary, canary=canary
164164
)
165165

166-
def get_port(self):
166+
def get_port(self, procfile_type):
167167
"""
168168
Get application port for a given release. If pulling from private registry
169169
then use default port or read from ENV var, otherwise attempt to pull from
170170
the container image
171171
"""
172-
try:
173-
envs = self.config.values
174-
creds = self.get_registry_auth()
175-
176-
if self.build.type == "buildpack":
177-
self.log(
178-
'buildpack type detected. Defaulting to $PORT %s' % DEFAULT_CONTAINER_PORT)
179-
return DEFAULT_CONTAINER_PORT
180-
181-
# application has registry auth - $PORT is required
182-
if (creds is not None) or (settings.REGISTRY_LOCATION != 'on-cluster'):
183-
if envs.get('PORT', None) is None:
184-
if not self.app.appsettings_set.latest().routable:
185-
return None
186-
raise DryccException(
187-
'PORT needs to be set in the application config '
188-
'when using a private registry'
189-
)
190-
191-
# User provided PORT
192-
return int(envs.get('PORT'))
193-
194-
# If the user provides PORT
195-
return int(envs.get('PORT', DEFAULT_CONTAINER_PORT))
196-
197-
except Exception as e:
198-
raise DryccException(str(e)) from e
199-
200-
def get_registry_auth(self):
201-
"""
202-
Gather login information for private registry if needed
203-
"""
204-
auth = None
205-
registry = self.config.registry
206-
if registry.get('username', None):
207-
auth = {
208-
'username': registry.get('username', None),
209-
'password': registry.get('password', None),
210-
'email': self.owner.email
211-
}
212-
213-
return auth
172+
return int(self.config.typed_values.get(
173+
procfile_type, {}).get(
174+
'PORT', self.config.values.get('PORT', DEFAULT_CONTAINER_PORT)))
214175

215176
def previous(self):
216177
"""

rootfs/api/tests/test_release.py

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from api.models.build import Build
1616
from api.models.release import Release
1717
from scheduler import KubeHTTPException
18-
from api.exceptions import DryccException
1918
from api.tests import adapter, DryccTransactionTestCase
2019
import requests_mock
2120

@@ -443,10 +442,7 @@ def test_release_get_port(self, mock_requests):
443442
release = app.release_set.latest()
444443

445444
# when app is not routable, then it still return 5000
446-
self.assertEqual(release.get_port(), 5000)
447-
448-
# when a buildpack type, default to 5000
449-
self.assertEqual(release.get_port(), 5000)
445+
self.assertEqual(release.get_port('web'), 5000)
450446

451447
# switch to a dockerfile app or else it'll automatically default to 5000
452448
url = f'/v2/apps/{app_id}/builds'
@@ -459,11 +455,29 @@ def test_release_get_port(self, mock_requests):
459455
response = self.client.post(url, body)
460456
self.assertEqual(response.status_code, 201, response.data)
461457
release = app.release_set.latest()
458+
self.assertEqual(release.get_port('web'), 8080)
462459

463-
# check that the port number returned is an int, not a string
464-
self.assertEqual(release.get_port(), 8080)
460+
url = f'/v2/apps/{app_id}/config'
461+
body = {'typed_values': json.dumps({"web": {'PORT': '9000'}})}
462+
response = self.client.post(url, body)
463+
self.assertEqual(response.status_code, 201, response.data)
464+
release = app.release_set.latest()
465+
self.assertEqual(release.get_port('web'), 9000)
465466

466-
# TODO(bacongobbler): test dockerfile ports
467+
# not web procfile
468+
self.assertEqual(release.get_port('task'), 8080)
469+
url = f'/v2/apps/{app_id}/config'
470+
body = {'values': json.dumps({'PORT': '9000'})}
471+
response = self.client.post(url, body)
472+
self.assertEqual(response.status_code, 201, response.data)
473+
release = app.release_set.latest()
474+
self.assertEqual(release.get_port('task'), 9000)
475+
# set typed_values port
476+
body = {'typed_values': json.dumps({"task": {'PORT': '9001'}})}
477+
response = self.client.post(url, body)
478+
self.assertEqual(response.status_code, 201, response.data)
479+
release = app.release_set.latest()
480+
self.assertEqual(release.get_port('task'), 9001)
467481

468482
@override_settings(DRYCC_DEPLOY_HOOK_URLS=['http://drycc.rocks'])
469483
@mock.patch('api.models.release.logger')
@@ -575,45 +589,15 @@ def test_release_external_registry(self, mock_requests):
575589
response = self.client.post(url, body)
576590
self.assertEqual(response.status_code, 201, response.data)
577591
release = app.release_set.latest()
578-
579-
self.assertEqual(release.get_port(), 3000)
580-
592+
self.assertEqual(release.get_port('web'), 3000)
581593
self.assertEqual(release.get_deploy_image(PROCFILE_TYPE_WEB), 'test/autotest/example')
582594

583-
@override_settings(REGISTRY_LOCATION="off-cluster")
584-
def test_release_external_registry_no_port(self, mock_requests):
585-
"""
586-
Test that an exception is raised when registry if off-cluster but
587-
no port is provided.
588-
"""
589-
app_id = self.create_app()
590-
591-
app = App.objects.get(id=app_id)
592-
url = f'/v2/apps/{app_id}/builds'
593-
body = {'image': 'test/autotest/example', 'stack': 'container'}
595+
url = f'/v2/apps/{app_id}/config'
596+
body = {'typed_values': json.dumps({"web": {'PORT': '9000'}})}
594597
response = self.client.post(url, body)
595598
self.assertEqual(response.status_code, 201, response.data)
596-
data = self.client.get(f"/v2/apps/{app_id}/releases/", body).json()
597-
self.assertEqual(data["results"][0]["state"], "crashed", data)
598-
599-
with self.assertRaises(
600-
DryccException,
601-
msg='PORT needs to be set in the config when using a private registry'
602-
):
603-
release = app.release_set.latest()
604-
release.get_port()
605-
606-
# Set routable to false and port should be None instead of error
607-
response = self.client.post(
608-
f'/v2/apps/{app.id}/settings',
609-
{'routable': False}
610-
)
611-
self.assertEqual(response.status_code, 201, response.data)
612-
self.assertFalse(app.appsettings_set.latest().routable)
613-
614599
release = app.release_set.latest()
615-
port = release.get_port()
616-
self.assertIsNone(port)
600+
self.assertEqual(release.get_port('web'), 9000)
617601

618602
def test_diff_procfile_types(self, mock_requests):
619603
app_id = self.create_app()

0 commit comments

Comments
 (0)