Skip to content
This repository was archived by the owner on Jun 2, 2021. It is now read-only.

Commit 90f5a4e

Browse files
sethboylesreneighbor
authored andcommitted
Allow start and restart if diego_docker is not enabled for kpack
apps WIP allow start and restart if diego_docker is not enabled for kpack apps [#172268950] Co-authored-by: Seth Boyles <sboyles@pivotal.io> Co-authored-by: Jaskanwal Pawar <jpawar@pivotal.io> Refactor condition for requiring diego_docker flag * if app lifecycle_type is docker (not droplet lifecycle_type) * Allows for kpack app lifecycle apps Authored-by: Renee Chu <rchu@pivotal.io>
1 parent 5679742 commit 90f5a4e

3 files changed

Lines changed: 198 additions & 66 deletions

File tree

app/controllers/v3/apps_controller.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ def start
157157
app_not_found! unless app && permission_queryer.can_read_from_space?(space.guid, org.guid)
158158
unprocessable_lacking_droplet! unless app.droplet
159159
unauthorized! unless permission_queryer.can_write_to_space?(space.guid)
160-
# TODO: only fail if also not `kpack` app lifecycle
161-
if app.droplet.lifecycle_type == DockerLifecycleDataModel::LIFECYCLE_TYPE
160+
161+
if app.lifecycle_type == DockerLifecycleDataModel::LIFECYCLE_TYPE
162162
FeatureFlag.raise_unless_enabled!(:diego_docker)
163163
end
164164

@@ -199,8 +199,8 @@ def restart
199199
app_not_found! unless app && permission_queryer.can_read_from_space?(space.guid, org.guid)
200200
unprocessable_lacking_droplet! unless app.droplet
201201
unauthorized! unless permission_queryer.can_write_to_space?(space.guid)
202-
# TODO: only fail if also not `kpack` app lifecycle
203-
if app.droplet.lifecycle_type == DockerLifecycleDataModel::LIFECYCLE_TYPE
202+
203+
if app.lifecycle_type == DockerLifecycleDataModel::LIFECYCLE_TYPE
204204
FeatureFlag.raise_unless_enabled!(:diego_docker)
205205
end
206206

spec/request/apps_spec.rb

Lines changed: 185 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,69 @@
18061806
}.to change { VCAP::CloudController::RevisionModel.count }.by(1)
18071807
end
18081808
end
1809+
1810+
context 'when app lifecycle is kpack' do
1811+
let(:app_model) { VCAP::CloudController::AppModel.make(:kpack, name: 'app-name', droplet: VCAP::CloudController::DropletModel.make(:kpack), space: space) }
1812+
1813+
before do
1814+
VCAP::CloudController::FeatureFlag.make(name: 'diego_docker', enabled: false, error_message: nil)
1815+
end
1816+
1817+
it 'starts the app' do
1818+
post "/v3/apps/#{app_model.guid}/actions/start", nil, user_header
1819+
expect(last_response.status).to eq(200)
1820+
1821+
parsed_response = MultiJson.load(last_response.body)
1822+
expect(parsed_response).to be_a_response_like({
1823+
'name' => 'app-name',
1824+
'guid' => app_model.guid,
1825+
'state' => 'STARTED',
1826+
'created_at' => iso8601,
1827+
'updated_at' => iso8601,
1828+
'metadata' => { 'labels' => {}, 'annotations' => {} },
1829+
'lifecycle' => {
1830+
'type' => 'kpack',
1831+
'data' => {}
1832+
},
1833+
'relationships' => {
1834+
'space' => {
1835+
'data' => {
1836+
'guid' => space.guid
1837+
}
1838+
}
1839+
},
1840+
'links' => {
1841+
'self' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}" },
1842+
'processes' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/processes" },
1843+
'packages' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/packages" },
1844+
'environment_variables' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/environment_variables" },
1845+
'space' => { 'href' => "#{link_prefix}/v3/spaces/#{space.guid}" },
1846+
'current_droplet' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets/current" },
1847+
'droplets' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets" },
1848+
'tasks' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/tasks" },
1849+
'start' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/start", 'method' => 'POST' },
1850+
'stop' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/stop", 'method' => 'POST' },
1851+
'revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions" },
1852+
'deployed_revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions/deployed" },
1853+
'features' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/features" },
1854+
}
1855+
})
1856+
1857+
event = VCAP::CloudController::Event.last
1858+
expect(event.values).to include({
1859+
type: 'audit.app.start',
1860+
actee: app_model.guid,
1861+
actee_type: 'app',
1862+
actee_name: 'app-name',
1863+
actor: user.guid,
1864+
actor_type: 'user',
1865+
actor_name: user_email,
1866+
actor_username: user_name,
1867+
space_guid: space.guid,
1868+
organization_guid: space.organization.guid,
1869+
})
1870+
end
1871+
end
18091872
end
18101873

18111874
describe 'POST /v3/apps/:guid/actions/stop' do
@@ -1921,84 +1984,145 @@
19211984
desired_state: 'STARTED',
19221985
)
19231986
}
1924-
let!(:droplet) do
1925-
VCAP::CloudController::DropletModel.make(
1926-
:buildpack,
1927-
app: app_model,
1928-
state: VCAP::CloudController::DropletModel::STAGED_STATE
1929-
)
1930-
end
1931-
before do
1932-
app_model.lifecycle_data.buildpacks = ['http://example.com/git']
1933-
app_model.lifecycle_data.stack = stack.name
1934-
app_model.lifecycle_data.save
1935-
app_model.droplet = droplet
1936-
app_model.save
1987+
1988+
context 'app lifecycle is buildpack' do
1989+
let!(:droplet) do
1990+
VCAP::CloudController::DropletModel.make(
1991+
:buildpack,
1992+
app: app_model,
1993+
state: VCAP::CloudController::DropletModel::STAGED_STATE
1994+
)
1995+
end
1996+
1997+
before do
1998+
app_model.lifecycle_data.buildpacks = ['http://example.com/git']
1999+
app_model.lifecycle_data.stack = stack.name
2000+
app_model.lifecycle_data.save
2001+
app_model.droplet = droplet
2002+
app_model.save
2003+
end
2004+
2005+
it 'restarts the app' do
2006+
post "/v3/apps/#{app_model.guid}/actions/restart", nil, user_header
2007+
expect(last_response.status).to eq(200)
2008+
2009+
parsed_response = MultiJson.load(last_response.body)
2010+
expect(parsed_response).to be_a_response_like(
2011+
{
2012+
'name' => 'app-name',
2013+
'guid' => app_model.guid,
2014+
'state' => 'STARTED',
2015+
'created_at' => iso8601,
2016+
'updated_at' => iso8601,
2017+
'metadata' => { 'labels' => {}, 'annotations' => {} },
2018+
'lifecycle' => {
2019+
'type' => 'buildpack',
2020+
'data' => {
2021+
'buildpacks' => ['http://example.com/git'],
2022+
'stack' => 'stack-name',
2023+
}
2024+
},
2025+
'relationships' => {
2026+
'space' => {
2027+
'data' => {
2028+
'guid' => space.guid
2029+
}
2030+
}
2031+
},
2032+
'links' => {
2033+
'self' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}" },
2034+
'processes' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/processes" },
2035+
'packages' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/packages" },
2036+
'environment_variables' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/environment_variables" },
2037+
'space' => { 'href' => "#{link_prefix}/v3/spaces/#{space.guid}" },
2038+
'current_droplet' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets/current" },
2039+
'droplets' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets" },
2040+
'tasks' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/tasks" },
2041+
'start' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/start", 'method' => 'POST' },
2042+
'stop' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/stop", 'method' => 'POST' },
2043+
'revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions" },
2044+
'deployed_revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions/deployed" },
2045+
'features' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/features" },
2046+
}
2047+
}
2048+
)
2049+
end
2050+
context 'telemetry' do
2051+
it 'should log the required fields when the app is restarted' do
2052+
Timecop.freeze do
2053+
expected_json = {
2054+
'telemetry-source' => 'cloud_controller_ng',
2055+
'telemetry-time' => Time.now.to_datetime.rfc3339,
2056+
'restart-app' => {
2057+
'api-version' => 'v3',
2058+
'app-id' => Digest::SHA256.hexdigest(app_model.guid),
2059+
'user-id' => Digest::SHA256.hexdigest(user.guid),
2060+
}
2061+
}
2062+
expect_any_instance_of(ActiveSupport::Logger).to receive(:info).with(JSON.generate(expected_json))
2063+
2064+
post "/v3/apps/#{app_model.guid}/actions/restart", nil, user_header
2065+
2066+
expect(last_response.status).to eq(200), last_response.body
2067+
end
2068+
end
2069+
end
19372070
end
19382071

1939-
it 'restarts the app' do
1940-
post "/v3/apps/#{app_model.guid}/actions/restart", nil, user_header
1941-
expect(last_response.status).to eq(200)
2072+
context 'app lifecycle is kpack' do
2073+
let(:app_model) {
2074+
VCAP::CloudController::AppModel.make(:kpack,
2075+
name: 'app-name',
2076+
droplet: VCAP::CloudController::DropletModel.make(:kpack),
2077+
space: space,
2078+
desired_state: 'STARTED')
2079+
}
19422080

1943-
parsed_response = MultiJson.load(last_response.body)
1944-
expect(parsed_response).to be_a_response_like(
1945-
{
2081+
before do
2082+
VCAP::CloudController::FeatureFlag.make(name: 'diego_docker', enabled: false, error_message: nil)
2083+
end
2084+
2085+
it 'restarts the app' do
2086+
post "/v3/apps/#{app_model.guid}/actions/restart", nil, user_header
2087+
expect(last_response.status).to eq(200)
2088+
2089+
parsed_response = MultiJson.load(last_response.body)
2090+
expect(parsed_response).to be_a_response_like(
2091+
{
19462092
'name' => 'app-name',
19472093
'guid' => app_model.guid,
19482094
'state' => 'STARTED',
19492095
'created_at' => iso8601,
19502096
'updated_at' => iso8601,
19512097
'metadata' => { 'labels' => {}, 'annotations' => {} },
19522098
'lifecycle' => {
1953-
'type' => 'buildpack',
1954-
'data' => {
1955-
'buildpacks' => ['http://example.com/git'],
1956-
'stack' => 'stack-name',
1957-
}
2099+
'type' => 'kpack',
2100+
'data' => {}
19582101
},
19592102
'relationships' => {
1960-
'space' => {
1961-
'data' => {
1962-
'guid' => space.guid
1963-
}
2103+
'space' => {
2104+
'data' => {
2105+
'guid' => space.guid
19642106
}
2107+
}
19652108
},
19662109
'links' => {
1967-
'self' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}" },
1968-
'processes' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/processes" },
1969-
'packages' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/packages" },
1970-
'environment_variables' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/environment_variables" },
1971-
'space' => { 'href' => "#{link_prefix}/v3/spaces/#{space.guid}" },
1972-
'current_droplet' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets/current" },
1973-
'droplets' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets" },
1974-
'tasks' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/tasks" },
1975-
'start' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/start", 'method' => 'POST' },
1976-
'stop' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/stop", 'method' => 'POST' },
1977-
'revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions" },
1978-
'deployed_revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions/deployed" },
1979-
'features' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/features" },
1980-
}
1981-
}
1982-
)
1983-
end
1984-
context 'telemetry' do
1985-
it 'should log the required fields when the app is restarted' do
1986-
Timecop.freeze do
1987-
expected_json = {
1988-
'telemetry-source' => 'cloud_controller_ng',
1989-
'telemetry-time' => Time.now.to_datetime.rfc3339,
1990-
'restart-app' => {
1991-
'api-version' => 'v3',
1992-
'app-id' => Digest::SHA256.hexdigest(app_model.guid),
1993-
'user-id' => Digest::SHA256.hexdigest(user.guid),
2110+
'self' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}" },
2111+
'processes' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/processes" },
2112+
'packages' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/packages" },
2113+
'environment_variables' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/environment_variables" },
2114+
'space' => { 'href' => "#{link_prefix}/v3/spaces/#{space.guid}" },
2115+
'current_droplet' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets/current" },
2116+
'droplets' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/droplets" },
2117+
'tasks' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/tasks" },
2118+
'start' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/start", 'method' => 'POST' },
2119+
'stop' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/actions/stop", 'method' => 'POST' },
2120+
'revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions" },
2121+
'deployed_revisions' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/revisions/deployed" },
2122+
'features' => { 'href' => "#{link_prefix}/v3/apps/#{app_model.guid}/features" },
19942123
}
19952124
}
1996-
expect_any_instance_of(ActiveSupport::Logger).to receive(:info).with(JSON.generate(expected_json))
1997-
1998-
post "/v3/apps/#{app_model.guid}/actions/restart", nil, user_header
1999-
2000-
expect(last_response.status).to eq(200), last_response.body
2001-
end
2125+
)
20022126
end
20032127
end
20042128
end

spec/unit/controllers/v3/apps_controller_spec.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1253,11 +1253,11 @@
12531253
let(:space) { app_model.space }
12541254
let(:org) { space.organization }
12551255
let(:user) { set_current_user(VCAP::CloudController::User.make) }
1256+
let(:buildpack_lifecycle) { VCAP::CloudController::BuildpackLifecycleDataModel.make(app: app_model, buildpacks: nil, stack: VCAP::CloudController::Stack.default.name) }
12561257

12571258
before do
12581259
allow_user_read_access_for(user, spaces: [space])
12591260
allow_user_write_access(user, space: space)
1260-
VCAP::CloudController::BuildpackLifecycleDataModel.make(app: app_model, buildpacks: nil, stack: VCAP::CloudController::Stack.default.name)
12611261
end
12621262

12631263
it 'returns a 200 and the app' do
@@ -1355,10 +1355,13 @@
13551355
end
13561356

13571357
context 'when requesting docker lifecycle and diego_docker feature flag is disabled' do
1358+
let(:app_model) { VCAP::CloudController::AppModel.make(droplet_guid: droplet.guid) }
13581359
let(:droplet) { VCAP::CloudController::DropletModel.make(:docker, state: VCAP::CloudController::DropletModel::STAGED_STATE) }
13591360

13601361
before do
13611362
VCAP::CloudController::FeatureFlag.make(name: 'diego_docker', enabled: false, error_message: nil)
1363+
# if app has no buildpack lifecyle data, default lifecycle type is "docker"
1364+
app_model.buildpack_lifecycle_data = nil
13621365
end
13631366

13641367
context 'admin' do
@@ -1570,11 +1573,14 @@
15701573
end
15711574

15721575
context 'when requesting docker lifecycle' do
1576+
let(:app_model) { VCAP::CloudController::AppModel.make(droplet_guid: droplet.guid) }
15731577
let(:droplet) { VCAP::CloudController::DropletModel.make(:docker, state: VCAP::CloudController::DropletModel::STAGED_STATE) }
15741578

15751579
context 'and diego_docker feature flag is enabled' do
15761580
before do
15771581
VCAP::CloudController::FeatureFlag.make(name: 'diego_docker', enabled: true, error_message: nil)
1582+
# if app has no buildpack lifecyle data, default lifecycle type is "docker"
1583+
app_model.buildpack_lifecycle_data = nil
15781584
end
15791585

15801586
it 'returns 200' do
@@ -1587,6 +1593,8 @@
15871593
context 'and diego_docker feature flag is disabled' do
15881594
before do
15891595
VCAP::CloudController::FeatureFlag.make(name: 'diego_docker', enabled: false, error_message: nil)
1596+
# if app has no buildpack lifecyle data, default lifecycle type is "docker"
1597+
app_model.buildpack_lifecycle_data = nil
15901598
end
15911599

15921600
context 'admin' do

0 commit comments

Comments
 (0)