-
Notifications
You must be signed in to change notification settings - Fork 369
Expand file tree
/
Copy pathapp_model.rb
More file actions
205 lines (160 loc) · 7.52 KB
/
app_model.rb
File metadata and controls
205 lines (160 loc) · 7.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
require 'cloud_controller/database_uri_generator'
require 'cloud_controller/serializer'
require 'models/helpers/process_types'
require 'hashdiff'
module VCAP::CloudController
class AppModel < Sequel::Model(:apps)
include Serializer
APP_NAME_REGEX = /\A[[:alnum:][:punct:][:print:]]+\Z/
DEFAULT_CONTAINER_USER = 'vcap'.freeze
DEFAULT_DOCKER_CONTAINER_USER = 'root'.freeze
many_to_many :routes, join_table: :route_mappings, left_key: :app_guid, left_primary_key: :guid, right_primary_key: :guid, right_key: :route_guid
one_to_many :route_mappings, class: 'VCAP::CloudController::RouteMappingModel', key: :app_guid, primary_key: :guid
one_to_many :service_bindings, key: :app_guid, primary_key: :guid
one_to_many :tasks, class: 'VCAP::CloudController::TaskModel', key: :app_guid, primary_key: :guid
many_to_one :space, class: 'VCAP::CloudController::Space', key: :space_guid, primary_key: :guid, without_guid_generation: true
one_through_one :organization, join_table: Space.table_name, left_key: :guid, left_primary_key: :space_guid, right_primary_key: :id, right_key: :organization_id
one_to_many :processes, class: 'VCAP::CloudController::ProcessModel', key: :app_guid, primary_key: :guid do |dataset|
dataset.order(Sequel.asc(:created_at), Sequel.asc(:id))
end
one_to_many :packages, class: 'VCAP::CloudController::PackageModel', key: :app_guid, primary_key: :guid
one_to_many :droplets, class: 'VCAP::CloudController::DropletModel', key: :app_guid, primary_key: :guid
one_to_many :builds, class: 'VCAP::CloudController::BuildModel', key: :app_guid, primary_key: :guid
one_to_many :deployments, class: 'VCAP::CloudController::DeploymentModel', key: :app_guid, primary_key: :guid
one_to_many :labels, class: 'VCAP::CloudController::AppLabelModel', key: :resource_guid, primary_key: :guid
one_to_many :annotations, class: 'VCAP::CloudController::AppAnnotationModel', key: :resource_guid, primary_key: :guid
one_to_many :revisions,
class: 'VCAP::CloudController::RevisionModel',
key: :app_guid,
primary_key: :guid,
order: [Sequel.asc(:created_at), Sequel.asc(:id)]
one_to_many :sidecars, class: 'VCAP::CloudController::SidecarModel', key: :app_guid, primary_key: :guid
many_to_one :droplet, class: 'VCAP::CloudController::DropletModel', key: :droplet_guid, primary_key: :guid, without_guid_generation: true
one_to_many :web_processes,
class: 'VCAP::CloudController::ProcessModel',
key: :app_guid,
primary_key: :guid,
conditions: { type: ProcessTypes::WEB } do |dataset|
dataset.order(Sequel.asc(:created_at), Sequel.asc(:id))
end
one_to_one :buildpack_lifecycle_data,
class: 'VCAP::CloudController::BuildpackLifecycleDataModel',
key: :app_guid,
primary_key: :guid
one_to_one :kpack_lifecycle_data,
class: 'VCAP::CloudController::KpackLifecycleDataModel',
key: :app_guid,
primary_key: :guid
one_to_one :cnb_lifecycle_data,
class: 'VCAP::CloudController::CNBLifecycleDataModel',
key: :app_guid,
primary_key: :guid
set_field_as_encrypted :environment_variables, column: :encrypted_environment_variables
serializes_via_json :environment_variables
add_association_dependencies buildpack_lifecycle_data: :destroy
add_association_dependencies kpack_lifecycle_data: :destroy
add_association_dependencies cnb_lifecycle_data: :destroy
add_association_dependencies labels: :destroy
add_association_dependencies annotations: :destroy
strip_attributes :name
plugin :after_initialize
def after_initialize
self.enable_ssh = Config.config.get(:default_app_ssh_access) if enable_ssh.nil?
end
def around_save
yield
rescue Sequel::UniqueConstraintViolation => e
raise e unless e.message.include?('apps_v3_space_guid_name_index')
errors.add(%i[space_guid name], :unique)
raise validation_failed_error
rescue Sequel::ForeignKeyConstraintViolation => e
raise e unless e.message.include?('fk_apps_droplet_guid')
errors.add(:droplet, :presence)
raise validation_failed_error
end
def validate
super
validates_presence :name
validates_format APP_NAME_REGEX, :name
validate_environment_variables
validate_droplet_is_staged
validates_unique %i[space_guid name], message: Sequel.lit("App with the name '#{name}' already exists.")
end
def lifecycle_type
return BuildpackLifecycleDataModel::LIFECYCLE_TYPE if buildpack_lifecycle_data
return CNBLifecycleDataModel::LIFECYCLE_TYPE if cnb_lifecycle_data
DockerLifecycleDataModel::LIFECYCLE_TYPE
end
def lifecycle_data
return buildpack_lifecycle_data if buildpack_lifecycle_data
return cnb_lifecycle_data if cnb_lifecycle_data
DockerLifecycleDataModel.new
end
def current_package
droplet&.package
end
def database_uri
service_binding_uris = service_bindings.map do |binding|
binding.credentials['uri'] if binding.credentials.present?
end.compact
DatabaseUriGenerator.new(service_binding_uris).database_uri
end
def windows_gmsa_credential_refs
service_bindings.sort_by(&:id).map do |binding|
binding.credentials['credhub-windows-gmsa-credential-ref'] if binding.credentials.present?
end.compact
end
def staging_in_progress?
builds_dataset.where(state: BuildModel::STAGING_STATE).any?
end
def docker?
lifecycle_type == DockerLifecycleDataModel::LIFECYCLE_TYPE
end
def buildpack?
lifecycle_type == BuildpackLifecycleDataModel::LIFECYCLE_TYPE
end
def cnb?
lifecycle_type == CNBLifecycleDataModel::LIFECYCLE_TYPE
end
def stopped?
desired_state == ProcessModel::STOPPED
end
def deploying?
deployments_dataset.where(state: DeploymentModel::PROGRESSING_STATES).any?
end
def self.user_visibility_filter(user)
space_guids = Space.join(:spaces_developers, space_id: :id, user_id: user.id).select(:spaces__guid).
union(Space.join(:spaces_managers, space_id: :id, user_id: user.id).select(:spaces__guid)).
union(Space.join(:spaces_auditors, space_id: :id, user_id: user.id).select(:spaces__guid)).
union(Space.join(:spaces_supporters, space_id: :id, user_id: user.id).select(:spaces__guid)).
union(Space.join(:organizations_managers, organization_id: :organization_id, user_id: user.id).select(:spaces__guid))
{
apps__guid: AppModel.where(space: space_guids.all).select(:guid)
}
end
def oldest_web_process
web_processes.first
end
def newest_web_process
web_processes.last
end
def latest_revision
reload.revisions.last if revisions_enabled
end
def commands_by_process_type
processes.
select { |p| p.type != ProcessTypes::WEB || p == newest_web_process }.
map { |p| [p.type, p.command] }.to_h
end
private
def validate_environment_variables
return unless environment_variables
VCAP::CloudController::Validators::EnvironmentVariablesValidator.
validate_each(self, :environment_variables, environment_variables)
end
def validate_droplet_is_staged
return unless droplet && droplet.state != DropletModel::STAGED_STATE
errors.add(:droplet, 'must be in staged state')
end
end
end