| @ -0,0 +1,13 @@ | |||||
| export IMG_VERSION = 7.5 | |||||
| # limpia todo | |||||
| all: imagen clean install | |||||
| imagen: | |||||
| cd ../servicios; make | |||||
| install: | |||||
| envsubst < repostajes-deployment.yaml |kubectl create -f - | |||||
| clean: | |||||
| envsubst < repostajes-deployment.yaml |kubectl delete -f - | |||||
| @ -0,0 +1,14 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolume | |||||
| metadata: | |||||
| name: repostajes-app-folder | |||||
| labels: | |||||
| app: repostajes | |||||
| spec: | |||||
| capacity: | |||||
| storage: 100Mi | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| hostPath: | |||||
| path: "/mnt/Externo/repostajes" | |||||
| @ -0,0 +1,56 @@ | |||||
| apiVersion: v1 | |||||
| kind: Service | |||||
| metadata: | |||||
| name: repostajes | |||||
| spec: | |||||
| type: NodePort | |||||
| ports: | |||||
| - name: http | |||||
| port: 5000 | |||||
| nodePort: 30340 | |||||
| targetPort: repostajes | |||||
| selector: | |||||
| app: repostajes | |||||
| --- | |||||
| apiVersion: apps/v1 | |||||
| kind: Deployment | |||||
| metadata: | |||||
| name: repostajes | |||||
| labels: | |||||
| app: repostajes | |||||
| spec: | |||||
| replicas: 1 | |||||
| selector: | |||||
| matchLabels: | |||||
| app: repostajes | |||||
| strategy: | |||||
| type: Recreate | |||||
| template: | |||||
| metadata: | |||||
| labels: | |||||
| app: repostajes | |||||
| spec: | |||||
| containers: | |||||
| - args: | |||||
| - gunicorn | |||||
| - --bind | |||||
| - 0.0.0.0:5000 | |||||
| - repostajes:create_app() | |||||
| image: creylopez/repostajes:$IMG_VERSION | |||||
| name: repostajes | |||||
| env: | |||||
| - name: SALUDO_DEMO | |||||
| value: "Hola, mundo" | |||||
| ports: | |||||
| - containerPort: 5000 | |||||
| name: repostajes | |||||
| resources: {} | |||||
| volumeMounts: | |||||
| - mountPath: /repostajes/instance | |||||
| name: repostajes-prod | |||||
| restartPolicy: Always | |||||
| volumes: | |||||
| - name: repostajes-prod | |||||
| persistentVolumeClaim: | |||||
| claimName: repostajes-prod | |||||
| status: {} | |||||
| @ -0,0 +1,14 @@ | |||||
| apiVersion: v1 | |||||
| kind: PersistentVolumeClaim | |||||
| metadata: | |||||
| creationTimestamp: null | |||||
| labels: | |||||
| io.kompose.service: repostajes-prod | |||||
| name: repostajes-prod | |||||
| spec: | |||||
| accessModes: | |||||
| - ReadWriteOnce | |||||
| resources: | |||||
| requests: | |||||
| storage: 100Mi | |||||
| status: {} | |||||
| @ -0,0 +1,44 @@ | |||||
| # Arreglar el fallo del nombre de constrain en migraciones | |||||
| https://stackoverflow.com/questions/62640576/flask-migrate-valueerror-constraint-must-have-a-name | |||||
| # Uso de migraciones | |||||
| https://www.digitalocean.com/community/tutorials/how-to-perform-flask-sqlalchemy-migrations-using-flask-migrate | |||||
| # Migración de la base de datos. | |||||
| Cada vez que se haga un cambio en la bd | |||||
| - flask db migrate -m "Mensaje" | |||||
| - flask db upgrade | |||||
| ## Migration Workflow | |||||
| From this point on you have a project that is fully enabled to use database migrations. The normal migration process goes as follows: | |||||
| - You will make some changes to your models in your Python source code. | |||||
| - You will then run flask db migrate to generate a new database migration for these changes. | |||||
| - You will finally apply the changes to the database by running flask db upgrade. | |||||
| This cycle repeats every time new changes to the database schema are needed. | |||||
| # Insertar los datos en la base de datos desde fichero sql | |||||
| 1. Borrar la base de datos. | |||||
| 2. flask db init | |||||
| 3. flask db migrate | |||||
| 4. flask db upgrade | |||||
| con lo anterior queda creada la base de datos. | |||||
| 5. Insertar los ficheros SQL con: | |||||
| sqlite3 repostajes.db < vehiculos.sql | |||||
| sqlite3 repostajes.db < repostajes.sql | |||||
| ¡ojo! estos ficheros son un volcado de mysql. Hay que 'tocarlos' para ajustarse al nuevo modelo. Los que hay aquí ya están adaptados | |||||
| @ -0,0 +1,8 @@ | |||||
| install: | |||||
| echo "Creando imagen con version ${IMG_VERSION}" | |||||
| docker build --no-cache -t creylopez/repostajes:${IMG_VERSION} . | |||||
| docker push creylopez/repostajes:${IMG_VERSION} | |||||
| @ -0,0 +1 @@ | |||||
| Single-database configuration for Flask. | |||||
| @ -0,0 +1,50 @@ | |||||
| # A generic, single database configuration. | |||||
| [alembic] | |||||
| # template used to generate migration files | |||||
| # file_template = %%(rev)s_%%(slug)s | |||||
| # set to 'true' to run the environment during | |||||
| # the 'revision' command, regardless of autogenerate | |||||
| # revision_environment = false | |||||
| # Logging configuration | |||||
| [loggers] | |||||
| keys = root,sqlalchemy,alembic,flask_migrate | |||||
| [handlers] | |||||
| keys = console | |||||
| [formatters] | |||||
| keys = generic | |||||
| [logger_root] | |||||
| level = WARN | |||||
| handlers = console | |||||
| qualname = | |||||
| [logger_sqlalchemy] | |||||
| level = WARN | |||||
| handlers = | |||||
| qualname = sqlalchemy.engine | |||||
| [logger_alembic] | |||||
| level = INFO | |||||
| handlers = | |||||
| qualname = alembic | |||||
| [logger_flask_migrate] | |||||
| level = INFO | |||||
| handlers = | |||||
| qualname = flask_migrate | |||||
| [handler_console] | |||||
| class = StreamHandler | |||||
| args = (sys.stderr,) | |||||
| level = NOTSET | |||||
| formatter = generic | |||||
| [formatter_generic] | |||||
| format = %(levelname)-5.5s [%(name)s] %(message)s | |||||
| datefmt = %H:%M:%S | |||||
| @ -0,0 +1,113 @@ | |||||
| import logging | |||||
| from logging.config import fileConfig | |||||
| from flask import current_app | |||||
| from alembic import context | |||||
| # this is the Alembic Config object, which provides | |||||
| # access to the values within the .ini file in use. | |||||
| config = context.config | |||||
| # Interpret the config file for Python logging. | |||||
| # This line sets up loggers basically. | |||||
| fileConfig(config.config_file_name) | |||||
| logger = logging.getLogger('alembic.env') | |||||
| def get_engine(): | |||||
| try: | |||||
| # this works with Flask-SQLAlchemy<3 and Alchemical | |||||
| return current_app.extensions['migrate'].db.get_engine() | |||||
| except (TypeError, AttributeError): | |||||
| # this works with Flask-SQLAlchemy>=3 | |||||
| return current_app.extensions['migrate'].db.engine | |||||
| def get_engine_url(): | |||||
| try: | |||||
| return get_engine().url.render_as_string(hide_password=False).replace( | |||||
| '%', '%%') | |||||
| except AttributeError: | |||||
| return str(get_engine().url).replace('%', '%%') | |||||
| # add your model's MetaData object here | |||||
| # for 'autogenerate' support | |||||
| # from myapp import mymodel | |||||
| # target_metadata = mymodel.Base.metadata | |||||
| config.set_main_option('sqlalchemy.url', get_engine_url()) | |||||
| target_db = current_app.extensions['migrate'].db | |||||
| # other values from the config, defined by the needs of env.py, | |||||
| # can be acquired: | |||||
| # my_important_option = config.get_main_option("my_important_option") | |||||
| # ... etc. | |||||
| def get_metadata(): | |||||
| if hasattr(target_db, 'metadatas'): | |||||
| return target_db.metadatas[None] | |||||
| return target_db.metadata | |||||
| def run_migrations_offline(): | |||||
| """Run migrations in 'offline' mode. | |||||
| This configures the context with just a URL | |||||
| and not an Engine, though an Engine is acceptable | |||||
| here as well. By skipping the Engine creation | |||||
| we don't even need a DBAPI to be available. | |||||
| Calls to context.execute() here emit the given string to the | |||||
| script output. | |||||
| """ | |||||
| url = config.get_main_option("sqlalchemy.url") | |||||
| context.configure( | |||||
| url=url, target_metadata=get_metadata(), literal_binds=True | |||||
| ) | |||||
| with context.begin_transaction(): | |||||
| context.run_migrations() | |||||
| def run_migrations_online(): | |||||
| """Run migrations in 'online' mode. | |||||
| In this scenario we need to create an Engine | |||||
| and associate a connection with the context. | |||||
| """ | |||||
| # this callback is used to prevent an auto-migration from being generated | |||||
| # when there are no changes to the schema | |||||
| # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html | |||||
| def process_revision_directives(context, revision, directives): | |||||
| if getattr(config.cmd_opts, 'autogenerate', False): | |||||
| script = directives[0] | |||||
| if script.upgrade_ops.is_empty(): | |||||
| directives[:] = [] | |||||
| logger.info('No changes in schema detected.') | |||||
| conf_args = current_app.extensions['migrate'].configure_args | |||||
| if conf_args.get("process_revision_directives") is None: | |||||
| conf_args["process_revision_directives"] = process_revision_directives | |||||
| connectable = get_engine() | |||||
| with connectable.connect() as connection: | |||||
| context.configure( | |||||
| connection=connection, | |||||
| target_metadata=get_metadata(), | |||||
| **conf_args | |||||
| ) | |||||
| with context.begin_transaction(): | |||||
| context.run_migrations() | |||||
| if context.is_offline_mode(): | |||||
| run_migrations_offline() | |||||
| else: | |||||
| run_migrations_online() | |||||
| @ -0,0 +1,24 @@ | |||||
| """${message} | |||||
| Revision ID: ${up_revision} | |||||
| Revises: ${down_revision | comma,n} | |||||
| Create Date: ${create_date} | |||||
| """ | |||||
| from alembic import op | |||||
| import sqlalchemy as sa | |||||
| ${imports if imports else ""} | |||||
| # revision identifiers, used by Alembic. | |||||
| revision = ${repr(up_revision)} | |||||
| down_revision = ${repr(down_revision)} | |||||
| branch_labels = ${repr(branch_labels)} | |||||
| depends_on = ${repr(depends_on)} | |||||
| def upgrade(): | |||||
| ${upgrades if upgrades else "pass"} | |||||
| def downgrade(): | |||||
| ${downgrades if downgrades else "pass"} | |||||