[402036] add DeploymentStrategy schema
In support of a larger effort to introduce a DeploymentStrategy document for Shipyard to use to drive baremetal node deployment, this change adds a schema and tests for that schema. Change-Id: I94c41f0ee8c8cf9c3762c5c1af575798fb1dccb4
This commit is contained in:
parent
47cd7a25f4
commit
6e32acbae1
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
schema: 'deckhand/DataSchema/v1'
|
schema: 'deckhand/DataSchema/v1'
|
||||||
metadata:
|
metadata:
|
||||||
@ -16,8 +15,6 @@ data:
|
|||||||
properties:
|
properties:
|
||||||
deployment_strategy:
|
deployment_strategy:
|
||||||
type: 'string'
|
type: 'string'
|
||||||
enum:
|
|
||||||
- 'all-at-once'
|
|
||||||
deploy_interval:
|
deploy_interval:
|
||||||
type: 'integer'
|
type: 'integer'
|
||||||
deploy_timeout:
|
deploy_timeout:
|
||||||
|
74
shipyard_airflow/schemas/deploymentStrategy.yaml
Normal file
74
shipyard_airflow/schemas/deploymentStrategy.yaml
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
schema: 'deckhand/DataSchema/v1'
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Control/v1
|
||||||
|
name: shipyard/DeploymentStrategy/v1
|
||||||
|
labels:
|
||||||
|
application: shipyard
|
||||||
|
data:
|
||||||
|
$schema: 'http://json-schema.org/schema#'
|
||||||
|
id: 'https://github.com/att-comdev/shipyard/deploymentStrategy.yaml'
|
||||||
|
type: 'object'
|
||||||
|
required:
|
||||||
|
- groups
|
||||||
|
properties:
|
||||||
|
groups:
|
||||||
|
type: 'array'
|
||||||
|
minItems: 0
|
||||||
|
items:
|
||||||
|
type: 'object'
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- critical
|
||||||
|
- depends_on
|
||||||
|
- selectors
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: 'string'
|
||||||
|
minLength: 1
|
||||||
|
critical:
|
||||||
|
type: 'boolean'
|
||||||
|
depends_on:
|
||||||
|
type: 'array'
|
||||||
|
minItems: 0
|
||||||
|
items:
|
||||||
|
type: 'string'
|
||||||
|
selectors:
|
||||||
|
type: 'array'
|
||||||
|
minItems: 0
|
||||||
|
items:
|
||||||
|
type: 'object'
|
||||||
|
minProperties: 1
|
||||||
|
properties:
|
||||||
|
node_names:
|
||||||
|
type: 'array'
|
||||||
|
items:
|
||||||
|
type: 'string'
|
||||||
|
node_labels:
|
||||||
|
type: 'array'
|
||||||
|
items:
|
||||||
|
type: 'string'
|
||||||
|
node_tags:
|
||||||
|
type: 'array'
|
||||||
|
items:
|
||||||
|
type: 'string'
|
||||||
|
rack_names:
|
||||||
|
type: 'array'
|
||||||
|
items:
|
||||||
|
type: 'string'
|
||||||
|
additionalProperties: false
|
||||||
|
success_criteria:
|
||||||
|
type: 'object'
|
||||||
|
minProperties: 1
|
||||||
|
properties:
|
||||||
|
percent_successful_nodes:
|
||||||
|
type: 'integer'
|
||||||
|
minimum: 0
|
||||||
|
maximum: 100
|
||||||
|
minimum_successful_nodes:
|
||||||
|
type: 'integer'
|
||||||
|
minimum: 0
|
||||||
|
maximum_failed_nodes:
|
||||||
|
type: 'integer'
|
||||||
|
minimum: 0
|
||||||
|
additionalProperties: false
|
51
tests/unit/schemas/base_schema_validation.py
Normal file
51
tests/unit/schemas/base_schema_validation.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
import jsonschema
|
||||||
|
import pkg_resources
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from jsonschema.exceptions import ValidationError
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSchemaValidationTest(object):
|
||||||
|
def _test_validate(self, schema, expect_failure, input_files, input):
|
||||||
|
"""validates input yaml against schema.
|
||||||
|
:param schema: schema yaml file
|
||||||
|
:param expect_failure: should the validation pass or fail.
|
||||||
|
:param input_files: pytest fixture used to access the test input files
|
||||||
|
:param input: test input yaml doc filename"""
|
||||||
|
schema_dir = pkg_resources.resource_filename('shipyard_airflow',
|
||||||
|
'schemas')
|
||||||
|
schema_filename = os.path.join(schema_dir, schema)
|
||||||
|
schema_file = open(schema_filename, 'r')
|
||||||
|
schema = yaml.safe_load(schema_file)
|
||||||
|
|
||||||
|
input_file = input_files.join(input)
|
||||||
|
instance_file = open(str(input_file), 'r')
|
||||||
|
instance = yaml.safe_load(instance_file)
|
||||||
|
|
||||||
|
LOG.info('Input: %s, Schema: %s', input_file, schema_filename)
|
||||||
|
|
||||||
|
if expect_failure:
|
||||||
|
# TypeError is raised when he input document is not well formed.
|
||||||
|
with pytest.raises((ValidationError, TypeError)):
|
||||||
|
jsonschema.validate(instance['data'], schema['data'])
|
||||||
|
else:
|
||||||
|
jsonschema.validate(instance['data'], schema['data'])
|
31
tests/unit/schemas/conftest.py
Normal file
31
tests/unit/schemas/conftest.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='module')
|
||||||
|
def input_files(tmpdir_factory, request):
|
||||||
|
tmpdir = tmpdir_factory.mktemp('data')
|
||||||
|
samples_dir = os.path.dirname(str(
|
||||||
|
request.fspath)) + "/" + "../yaml_samples"
|
||||||
|
samples = os.listdir(samples_dir)
|
||||||
|
|
||||||
|
for f in samples:
|
||||||
|
src_file = samples_dir + "/" + f
|
||||||
|
dst_file = str(tmpdir) + "/" + f
|
||||||
|
shutil.copyfile(src_file, dst_file)
|
||||||
|
return tmpdir
|
@ -11,44 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import logging
|
from .base_schema_validation import BaseSchemaValidationTest
|
||||||
import os
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
import jsonschema
|
|
||||||
import pkg_resources
|
|
||||||
import pytest
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
from jsonschema.exceptions import ValidationError
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseSchemaValidationTest(object):
|
|
||||||
def _test_validate(self, schema, expect_failure, input_files, input):
|
|
||||||
"""validates input yaml against schema.
|
|
||||||
:param schema: schema yaml file
|
|
||||||
:param expect_failure: should the validation pass or fail.
|
|
||||||
:param input_files: pytest fixture used to access the test input files
|
|
||||||
:param input: test input yaml doc filename"""
|
|
||||||
schema_dir = pkg_resources.resource_filename('shipyard_airflow',
|
|
||||||
'schemas')
|
|
||||||
schema_filename = os.path.join(schema_dir, schema)
|
|
||||||
schema_file = open(schema_filename, 'r')
|
|
||||||
schema = yaml.safe_load(schema_file)
|
|
||||||
|
|
||||||
input_file = input_files.join(input)
|
|
||||||
instance_file = open(str(input_file), 'r')
|
|
||||||
instance = yaml.safe_load(instance_file)
|
|
||||||
|
|
||||||
LOG.info('Input: %s, Schema: %s', input_file, schema_filename)
|
|
||||||
|
|
||||||
if expect_failure:
|
|
||||||
with pytest.raises(ValidationError):
|
|
||||||
jsonschema.validate(instance['data'], schema['data'])
|
|
||||||
else:
|
|
||||||
jsonschema.validate(instance['data'], schema['data'])
|
|
||||||
|
|
||||||
|
|
||||||
class TestValidation(BaseSchemaValidationTest):
|
class TestValidation(BaseSchemaValidationTest):
|
||||||
@ -63,16 +26,3 @@ class TestValidation(BaseSchemaValidationTest):
|
|||||||
def test_validate_deploy_config_minimal_valid(self, input_files):
|
def test_validate_deploy_config_minimal_valid(self, input_files):
|
||||||
self._test_validate('deploymentConfiguration.yaml', False, input_files,
|
self._test_validate('deploymentConfiguration.yaml', False, input_files,
|
||||||
'deploymentConfiguration_minimal_valid.yaml')
|
'deploymentConfiguration_minimal_valid.yaml')
|
||||||
|
|
||||||
@pytest.fixture(scope='module')
|
|
||||||
def input_files(self, tmpdir_factory, request):
|
|
||||||
tmpdir = tmpdir_factory.mktemp('data')
|
|
||||||
samples_dir = os.path.dirname(str(
|
|
||||||
request.fspath)) + "/" + "../yaml_samples"
|
|
||||||
samples = os.listdir(samples_dir)
|
|
||||||
|
|
||||||
for f in samples:
|
|
||||||
src_file = samples_dir + "/" + f
|
|
||||||
dst_file = str(tmpdir) + "/" + f
|
|
||||||
shutil.copyfile(src_file, dst_file)
|
|
||||||
return tmpdir
|
|
||||||
|
38
tests/unit/schemas/test_deployment_strategy.py
Normal file
38
tests/unit/schemas/test_deployment_strategy.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright 2017 AT&T Intellectual Property. All other rights reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
from .base_schema_validation import BaseSchemaValidationTest
|
||||||
|
|
||||||
|
|
||||||
|
class TestValidation(BaseSchemaValidationTest):
|
||||||
|
def test_validate_deploy_config_full_valid(self, input_files):
|
||||||
|
self._test_validate('deploymentStrategy.yaml', False, input_files,
|
||||||
|
'deploymentStrategy_full_valid.yaml')
|
||||||
|
|
||||||
|
self._test_validate('deploymentStrategy.yaml', False, input_files,
|
||||||
|
'deploymentStrategy_minimal.yaml')
|
||||||
|
|
||||||
|
self._test_validate('deploymentStrategy.yaml', False, input_files,
|
||||||
|
'deploymentStrategy_min_with_content.yaml')
|
||||||
|
|
||||||
|
for testnum in range(1, 5):
|
||||||
|
self._test_validate(
|
||||||
|
'deploymentStrategy.yaml', True, input_files,
|
||||||
|
'deploymentStrategy_bad_values_{}.yaml'.format(testnum)
|
||||||
|
)
|
||||||
|
|
||||||
|
self._test_validate('deploymentStrategy.yaml', True, input_files,
|
||||||
|
'total_garbage.yaml')
|
||||||
|
|
||||||
|
self._test_validate('deploymentStrategy.yaml', True, input_files,
|
||||||
|
'empty.yaml')
|
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_1.yaml
Normal file
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_1.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups:
|
||||||
|
# name is a min length of 1
|
||||||
|
- name: ""
|
||||||
|
critical: false
|
||||||
|
depends_on: []
|
||||||
|
selectors: []
|
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_2.yaml
Normal file
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_2.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups:
|
||||||
|
- name: a_group
|
||||||
|
# critical is boolean
|
||||||
|
critical: cheese sandwich
|
||||||
|
depends_on: []
|
||||||
|
selectors: []
|
15
tests/unit/yaml_samples/deploymentStrategy_bad_values_3.yaml
Normal file
15
tests/unit/yaml_samples/deploymentStrategy_bad_values_3.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups:
|
||||||
|
- name: some_group
|
||||||
|
critical: true
|
||||||
|
# depends_on missing
|
||||||
|
selectors: []
|
18
tests/unit/yaml_samples/deploymentStrategy_bad_values_4.yaml
Normal file
18
tests/unit/yaml_samples/deploymentStrategy_bad_values_4.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups:
|
||||||
|
- name: my_name_is
|
||||||
|
critical: false
|
||||||
|
depends_on: []
|
||||||
|
selectors:
|
||||||
|
# node_names are strings
|
||||||
|
- node_names: [false, true, false]
|
||||||
|
node_labels: []
|
20
tests/unit/yaml_samples/deploymentStrategy_bad_values_5.yaml
Normal file
20
tests/unit/yaml_samples/deploymentStrategy_bad_values_5.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups:
|
||||||
|
- name: my_group
|
||||||
|
critical: false
|
||||||
|
depends_on: []
|
||||||
|
selectors:
|
||||||
|
- node_names: []
|
||||||
|
node_labels: []
|
||||||
|
success_criteria:
|
||||||
|
# should be 100 or less
|
||||||
|
percent_successful_nodes: 190
|
75
tests/unit/yaml_samples/deploymentStrategy_full_valid.yaml
Normal file
75
tests/unit/yaml_samples/deploymentStrategy_full_valid.yaml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups:
|
||||||
|
- name: control-nodes
|
||||||
|
critical: true
|
||||||
|
depends_on:
|
||||||
|
- ntp-node
|
||||||
|
selectors:
|
||||||
|
- node_names: []
|
||||||
|
node_labels: []
|
||||||
|
node_tags:
|
||||||
|
- control
|
||||||
|
rack_names:
|
||||||
|
- rack03
|
||||||
|
success_criteria:
|
||||||
|
percent_successful_nodes: 90
|
||||||
|
minimum_successful_nodes: 3
|
||||||
|
maximum_failed_nodes: 1
|
||||||
|
- name: compute-nodes-1
|
||||||
|
critical: false
|
||||||
|
depends_on:
|
||||||
|
- control-nodes
|
||||||
|
selectors:
|
||||||
|
- node_names: []
|
||||||
|
node_labels: []
|
||||||
|
rack_names:
|
||||||
|
- rack01
|
||||||
|
node_tags:
|
||||||
|
- compute
|
||||||
|
success_criteria:
|
||||||
|
percent_successful_nodes: 50
|
||||||
|
- name: compute-nodes-2
|
||||||
|
critical: false
|
||||||
|
depends_on:
|
||||||
|
- control-nodes
|
||||||
|
selectors:
|
||||||
|
- node_names: []
|
||||||
|
node_labels: []
|
||||||
|
rack_names:
|
||||||
|
- rack02
|
||||||
|
node_tags:
|
||||||
|
- compute
|
||||||
|
success_criteria:
|
||||||
|
percent_successful_nodes: 50
|
||||||
|
- name: monitoring-nodes
|
||||||
|
critical: false
|
||||||
|
depends_on: []
|
||||||
|
selectors:
|
||||||
|
- node_names: []
|
||||||
|
node_labels: []
|
||||||
|
node_tags:
|
||||||
|
- monitoring
|
||||||
|
rack_names:
|
||||||
|
- rack03
|
||||||
|
- rack02
|
||||||
|
- rack01
|
||||||
|
- name: ntp-node
|
||||||
|
critical: true
|
||||||
|
depends_on: []
|
||||||
|
selectors:
|
||||||
|
- node_names:
|
||||||
|
- ntp01
|
||||||
|
node_labels: []
|
||||||
|
node_tags: []
|
||||||
|
rack_names: []
|
||||||
|
success_criteria:
|
||||||
|
minimum_successful_nodes: 1
|
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups:
|
||||||
|
- name: some-nodes
|
||||||
|
critical: false
|
||||||
|
depends_on: []
|
||||||
|
selectors: []
|
11
tests/unit/yaml_samples/deploymentStrategy_minimal.yaml
Normal file
11
tests/unit/yaml_samples/deploymentStrategy_minimal.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
schema: shipyard/DeploymentStrategy/v1
|
||||||
|
metadata:
|
||||||
|
schema: metadata/Document/v1
|
||||||
|
name: deployment-strategy
|
||||||
|
layeringDefinition:
|
||||||
|
abstract: false
|
||||||
|
layer: global
|
||||||
|
storagePolicy: cleartext
|
||||||
|
data:
|
||||||
|
groups: []
|
0
tests/unit/yaml_samples/empty.yaml
Normal file
0
tests/unit/yaml_samples/empty.yaml
Normal file
44
tests/unit/yaml_samples/total_garbage.yaml
Normal file
44
tests/unit/yaml_samples/total_garbage.yaml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras euismod
|
||||||
|
sed urna nec posuere. Phasellus vel arcu vestibulum, mattis ligula eu,
|
||||||
|
pulvinar magna. Cras mollis velit quis maximus gravida. Morbi nec ligula
|
||||||
|
neque. Cras vitae cursus tellus, ut ornare enim. Nulla vel suscipit
|
||||||
|
arcu, in auctor ipsum. Ut a maximus magna. Integer massa risus,
|
||||||
|
tristique sit amet urna sit amet, facilisis bibendum lectus. Vivamus
|
||||||
|
vehicula urna in purus lacinia, sit amet tincidunt diam consequat.
|
||||||
|
Quisque ut metus vitae mauris condimentum sollicitudin. Pellentesque
|
||||||
|
urna nibh, mollis eu dui ac, molestie malesuada quam. Aliquam fringilla
|
||||||
|
faucibus orci, a tincidunt dui sollicitudin ac. Nullam enim velit,
|
||||||
|
imperdiet ut nulla quis, efficitur tincidunt eros. Curabitur nisi justo,
|
||||||
|
tristique non ornare vitae, mollis eu tortor. In non congue libero.
|
||||||
|
Mauris et tincidunt sem. Quisque sed congue diam, non ultrices turpis.
|
||||||
|
Pellentesque lobortis quam justo, facilisis sollicitudin mi imperdiet
|
||||||
|
sed. Ut nec leo placerat, gravida odio id, hendrerit erat. Praesent
|
||||||
|
placerat diam mi, et blandit mi sollicitudin et. Proin ligula sapien,
|
||||||
|
faucibus eget arcu vel, rhoncus vestibulum ipsum. Morbi tristique
|
||||||
|
pharetra diam non faucibus. Nam scelerisque, leo ut tempus fermentum,
|
||||||
|
dolor odio tempus nisl, et volutpat ante est id enim. Integer venenatis
|
||||||
|
scelerisque augue, quis porta lorem dapibus non. Sed arcu purus, iaculis
|
||||||
|
vitae sem sit amet, ultrices pretium leo. Nulla ultricies eleifend
|
||||||
|
tempus. Aenean elementum ipsum id auctor faucibus. Cras quis ipsum
|
||||||
|
vehicula, auctor velit et, dignissim sem. Duis sed nunc sagittis,
|
||||||
|
interdum dui consequat, iaculis purus. Curabitur quam ex, pellentesque
|
||||||
|
nec sapien ut, sodales lacinia enim. Etiam hendrerit sem eu turpis
|
||||||
|
euismod, quis luctus tortor iaculis. Vivamus a rutrum orci. Class aptent
|
||||||
|
taciti sociosqu ad litora torquent per conubia nostra, per inceptos
|
||||||
|
himenaeos. Pellentesque habitant morbi tristique senectus et netus et
|
||||||
|
malesuada fames ac turpis egestas. Aenean non neque ultrices, consequat
|
||||||
|
erat vitae, porta lorem. Phasellus fringilla fringilla imperdiet.
|
||||||
|
Quisque in nulla at elit sodales vestibulum ac eget mauris. Ut vel purus
|
||||||
|
nec metus ultrices aliquet in sed leo. Mauris vel congue velit. Donec
|
||||||
|
quam turpis, venenatis tristique sem nec, condimentum fringilla orci.
|
||||||
|
Sed eu feugiat dui. Proin vulputate lacus id blandit tempor. Vivamus
|
||||||
|
sollicitudin tincidunt ultrices. Aenean sit amet orci efficitur,
|
||||||
|
condimentum mi vel, condimentum nisi. Cras pellentesque, felis vel
|
||||||
|
maximus volutpat, turpis arcu dapibus metus, vitae fringilla massa lorem
|
||||||
|
et elit. Interdum et malesuada fames ac ante ipsum primis in faucibus.
|
||||||
|
Duis lorem velit, laoreet tincidunt fringilla at, vestibulum eget risus.
|
||||||
|
Pellentesque ullamcorper venenatis lectus, a mattis lectus feugiat vel.
|
||||||
|
Suspendisse potenti. Duis suscipit malesuada risus nec egestas. Vivamus
|
||||||
|
maximus, neque quis egestas rhoncus, mauris purus fringilla nisl, ut
|
||||||
|
fringilla odio nunc sit amet justo. Phasellus at dui quis magna
|
||||||
|
elementum sagittis. Nullam sed luctus felis, ac tincidunt erat.
|
Loading…
x
Reference in New Issue
Block a user